Skip to content

Add context-aware shell completion and inline suggestions#576

Merged
tnaum-ms merged 32 commits intorel/release_0.8.0from
dev/tnaum/shell-auto-completions
Apr 15, 2026
Merged

Add context-aware shell completion and inline suggestions#576
tnaum-ms merged 32 commits intorel/release_0.8.0from
dev/tnaum/shell-auto-completions

Conversation

@tnaum-ms
Copy link
Copy Markdown
Collaborator

This pull request introduces advanced shell completion and inline suggestion ("ghost text") features to the DocumentDBShellPty class, greatly enhancing the interactive shell experience. It adds a tab-completion system, inline ghost text suggestions, and manages their rendering and acceptance, as well as related state and cleanup logic.

Shell Completion and Ghost Text Features:

  • Added a ShellCompletionProvider and ShellGhostText to the shell PTY, supporting tab completion and inline ghost text suggestions. These are initialized in the constructor and managed as part of the shell session state. [1] [2]
  • Implemented tab completion logic: pressing Tab invokes completion, inserts the common prefix or displays a completion list, and allows accepting ghost text with Tab or Right Arrow.
  • Added ghost text evaluation: after buffer changes, the shell evaluates if an inline suggestion is appropriate, debounced for performance, and displays it if there's a single clear completion or matches smart patterns (e.g., suggesting find() after db.<collection>.).
  • Provided logic to accept ghost text, inserting the suggestion into the buffer and clearing the inline display.
  • Introduced a set of known database methods to avoid inappropriate ghost text suggestions.

Terminal State and Cleanup Improvements:

  • Tracked terminal width for improved completion list rendering, and handled cleanup of timers and ghost text state on shell close and prompt reset. [1] [2] [3]
  • Managed visibility state for completion lists and ghost text to ensure correct UI updates on user input and buffer changes.

These enhancements make the shell more user-friendly and efficient by providing context-aware completions and suggestions as users type.

Context-aware completion engine for the interactive shell with 7 context
types: top-level commands, show subcommands, use database, db-dot
(collections + database methods), collection methods, method arguments
(field names + operators), and cursor chains.

Data sources: ClustersClient (cached), SchemaStore, documentdb-constants,
documentdb-shell-api-types. All reads are synchronous from caches.

ShellCompletionRenderer renders bash/zsh-style multi-column ANSI picker
with common prefix detection and truncation for long lists.
Ghost text renders a single obvious completion in dim gray (ANSI 2m+90m)
after the cursor. Users accept with Right Arrow or Tab. Lifecycle:
show → clear → accept/reset. 15 unit tests.
ShellInputHandler: add Tab key handling, getCursor() getter, insertText()
method, onTab/onBufferChange/onAcceptGhostText callbacks. Right Arrow at
end of buffer accepts ghost text.

DocumentDBShellPty: wire ShellCompletionProvider for Tab, ShellGhostText
for inline suggestions with 50ms debounce, setDimensions() for terminal
width tracking, smart ghost text patterns (db.coll. → find()).
Completion list now uses per-candidate ANSI colors to visually
differentiate item types:
- Cyan: collection names
- Yellow: methods/commands (with () suffix)
- Green: field names
- Magenta: operators and BSON constructors
- Gray: databases

Methods display with trailing () suffix (e.g., 'find()' vs 'users')
so collections and methods are distinguishable at a glance.

Added cursor chain completion support with tests: db.coll.find().,
db.coll.find().limit(10)., db.coll.aggregate([]).
Smart/pattern-based ghost text (e.g., find() after db.collection.) is
now dismissed by Tab, which then shows the full method picker. Only
prefix-match ghost text (single unique match) is accepted by Tab.
Right Arrow still accepts both types of ghost text.

This fixes the issue where pressing Tab after db.collection. would
accept find() instead of showing the full list of available methods.
Remove pattern-based ghost text (e.g., find() after db.coll.) because it
created a confusing inconsistency: users expected Tab to accept the ghost
suggestion, but it was dismissed to show the full picker instead.

Ghost text now only appears for single prefix matches (e.g., db.rest →
dim 'aurants') where Tab acceptance is unambiguous. The Tab picker
provides full method discoverability at db.<coll>. without ghost text
competing.
- Create docs/ai-and-plans/interactive-shell/9-shell-autocompletion.md
  with architecture, design decisions, and reasoning
- Update terminal-enhancements.md: mark Tab Completion Fallback as done
  (PR #576), link ghost text to PR, add issue #577 tracking
- Created GitHub issue #577 for TerminalCompletionProvider migration
  (blocked by microsoft/vscode#224505)
@tnaum-ms tnaum-ms marked this pull request as ready for review April 14, 2026 10:22
@tnaum-ms tnaum-ms requested a review from a team as a code owner April 14, 2026 10:22
@tnaum-ms tnaum-ms requested a review from Copilot April 14, 2026 10:22
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

This PR adds a self-contained tab-completion system and inline “ghost text” suggestions to the DocumentDB interactive shell PTY, providing a richer terminal editing experience without relying on VS Code’s proposed TerminalCompletionProvider API.

Changes:

  • Added a completion provider + renderer to produce context-aware candidates and display multi-column completion lists in the terminal.
  • Added ghost text lifecycle management and wired it into the PTY via new ShellInputHandler callbacks.
  • Expanded unit tests and documentation to cover the new completion and ghost text behaviors.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
src/documentdb/shell/ShellInputHandler.ts Adds Tab handling, buffer-change callbacks, cursor getter, and text insertion API for completions/ghost text.
src/documentdb/shell/ShellInputHandler.test.ts Adds tests for Tab callback, cursor tracking, insertText, buffer-change callbacks, and ghost acceptance hook.
src/documentdb/shell/ShellGhostText.ts New module to render/clear/reset inline ANSI ghost text suggestions.
src/documentdb/shell/ShellGhostText.test.ts Unit tests for ghost text rendering lifecycle and ANSI output.
src/documentdb/shell/ShellCompletionRenderer.ts New module to render completion lists and compute common prefixes.
src/documentdb/shell/ShellCompletionRenderer.test.ts Unit tests for completion list layout/colors/truncation and common prefix behavior.
src/documentdb/shell/ShellCompletionProvider.ts New context detector and candidate generator using caches/schema/operators/method metadata.
src/documentdb/shell/ShellCompletionProvider.test.ts Unit tests covering context detection and candidate generation/filtering.
src/documentdb/shell/DocumentDBShellPty.ts Wires Tab completion + ghost text into the PTY, adds dimension tracking, debounce timer, and cleanup.
docs/ai-and-plans/shell-autocompletion/9-shell-autocompletion.md Adds architecture/design documentation for completion + ghost text.
docs/ai-and-plans/future-work/terminal-enhancements.md Updates future-work doc to mark fallback completion as implemented and link to docs/issue.

Comment thread src/documentdb/shell/ShellInputHandler.ts
Comment thread src/documentdb/shell/DocumentDBShellPty.ts
Comment thread src/documentdb/shell/ShellCompletionProvider.ts Outdated
Comment thread src/documentdb/shell/ShellCompletionProvider.ts
Comment thread docs/ai-and-plans/future-work/terminal-enhancements.md Outdated
clearBeforeCursor(), clearAfterCursor(), and deleteWordBeforeCursor()
mutate the buffer but did not call onBufferChange, causing ghost text
to remain visible with stale content after these editing operations.

Fixes review issue #1 (S2 — High)
detectContext routed db['collection'] into detectDbContext, but the
parser assumed db. dot-access syntax (slice(3)). Bracket notation
produced garbled prefix matching and no useful completions.

Removed the db[ branch since the downstream parsing doesn't support
bracket-based collection access. Added a comment explaining why.

Fixes review issue #2 (S3 — Medium)
showPrompt() reset ghost text state but did not clear _ghostTextTimer.
The pending timer closure captured old buffer/cursor values and could
render ghost text on a fresh empty prompt after command completion or
Ctrl+C interrupt.

Fixes review issue #3 (S3 — Medium)
The fieldLookup closure re-fetched getKnownFields() and did a linear
scan (Array.find) on every invocation. Pre-compute a Map<path, type>
once and use O(1) Map.get() in the closure.

Fixes review issue #4 (S4 — Low)
shell-autocomletion → shell-autocompletion (missing 'p')

Fixes review issue #5 (S5 — Nit)
insertText() is a PTY-controlled mutation — the PTY handles follow-up
evaluations after calling it. Document this intentional asymmetry to
prevent future code from relying on onBufferChange for PTY-driven
insertions.

Addresses review issue #6 (S4 — Low)
@tnaum-ms
Copy link
Copy Markdown
Collaborator Author

Review issue #6 — insertText() doesn't fire onBufferChange (S4 — Low)

Issue: insertText() modifies _buffer and _cursor but doesn't call onBufferChange, creating an asymmetry with other buffer-mutating methods.

Action: Documented the contract in the JSDoc: insertText is intentionally a PTY-controlled mutation — the PTY handles follow-up evaluations (ghost text, etc.) after calling it. This prevents future code from incorrectly relying on onBufferChange for PTY-driven insertions.

Commit: 1dd1e0e

ClustersClient does not deduplicate concurrent requests internally.
Rapid Tab pressing with empty caches fired multiple identical network
requests. Added a _backgroundFetchTriggered set that tracks in-flight
fetches and prevents duplicate requests for the same resource.

Fixes review issue #8 (S4 — Low)
@tnaum-ms
Copy link
Copy Markdown
Collaborator Author

Review issue #8 — No rate limiting on background cache fetch triggers (S4 — Low)

Issue: getDatabaseCandidates and getDbDotCandidates fire background listDatabases()/listCollections() on every Tab press when the cache is empty. ClustersClient does not deduplicate concurrent requests, so rapid Tab pressing causes multiple identical network requests.

Action: Added a _backgroundFetchTriggered set that tracks in-flight fetches by resource key. Duplicate fetch requests for the same resource are suppressed while one is already in progress. The key is cleaned up in .finally() so the guard resets after the fetch completes (success or failure).

Commit: e8cce7b

@tnaum-ms
Copy link
Copy Markdown
Collaborator Author

Review issue #9 — DATABASE_METHODS hardcoded, not derived from types (S4 — Low)

Issue: DATABASE_METHODS was a hardcoded 14-entry Set. If a new database method is added to documentdb-shell-api-types, the completion provider would treat db.newMethod as a collection name.

Action: Replaced the hardcoded set with new Set(getMethodsByTarget('database').map((m) => m.name)), which is already imported and used elsewhere in the same file. The set now stays in sync automatically.

Commit: bd19c36

Replace the hardcoded 14-entry Set with a dynamically derived Set from
getMethodsByTarget('database'). This ensures the set stays in sync
when new database methods are added to the shell API types package.

Fixes review issue #9 (S4 — Low)
@tnaum-ms tnaum-ms force-pushed the dev/tnaum/shell-auto-completions branch from bd19c36 to 795f52f Compare April 14, 2026 12:31
Two improvements to method-argument completions:

1. At key position, show only field names by default. Operators appear
   only when $ is typed. This eliminates the 'random operator dump'
   when the user presses Tab inside find({}).

2. Include '.' in extractArgumentPrefix and findReplacementStart so
   dotted nested field paths like 'toplevel.isEnabled' are matched
   correctly. Previously 'toplevel.is' was split at the dot, extracting
   just 'is' which incorrectly matched ISODate and other BSON types.

Added 20 tests covering both behaviors.
Moved feedResultToSchemaStore(), deserializeResultForSchema(), and
randomSample() from executePlaygroundCode.ts into a shared module at
src/documentdb/feedResultToSchemaStore.ts.

The playground now imports from the shared utility. The shell PTY will
use the same functions in the next commit.

No behavioral changes — pure extraction refactor.
After displaying query results, the shell PTY now deserializes the
EJSON printable string back to raw objects and feeds them to SchemaStore
via the shared feedResultToSchemaStore utility.

This enables field name completions in the shell after running queries
like db.users.find(). Previously, schema data was only populated from
Collection View and Query Playground — the shell discarded all query
result documents without analyzing them.

Schema feeding is asynchronous and non-blocking. Failures are silently
ignored (best-effort).
Covers result type filtering, namespace validation, CursorIterationResult
unwrapping, document filtering (primitives, arrays, missing _id),
document cap at 100, EJSON deserialization with fallbacks.
Dotted nested field paths like 'address.city' are not valid as
unquoted JavaScript object keys. Tab-completing them inside find({})
produced a syntax error:

  db.users.find({address.city: 'x'})  // SyntaxError

Now, dotted field candidates have their insertText wrapped in quotes:

  db.users.find({"address.city": 'x'})  // Valid

Implementation:
- Added replaceText(deleteCount, text) to ShellInputHandler for
  replace-mode completions (delete prefix, insert full quoted text)
- addFieldCandidates now quotes dotted paths in insertText
- applySingleCompletion detects quoted insertText and uses replaceText
- Ghost text is skipped for quoting candidates (visual would be wrong)
- Added schema hint ghost text: shows 'ⓘ Run db.<coll>.find() first
  for field suggestions' when no schema data is available
- Hint ghost text is non-insertable (Tab/Right Arrow won't accept it)

Added 12 tests: 6 for replaceText, 6 for dotted field quoting.
The schema hint ghost text was shown whenever zero completions matched,
including when the user typed a typo (e.g., 'addiitid') on a collection
with known schema. Now checks SchemaStore.getKnownFields() and only
shows the hint when the collection truly has no schema data.
@tnaum-ms tnaum-ms force-pushed the dev/tnaum/shell-auto-completions branch from 45fe84b to 84d699f Compare April 14, 2026 18:39
@tnaum-ms tnaum-ms merged commit f520aa9 into rel/release_0.8.0 Apr 15, 2026
1 of 2 checks passed
@tnaum-ms tnaum-ms deleted the dev/tnaum/shell-auto-completions branch April 15, 2026 11:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Development

Successfully merging this pull request may close these issues.

2 participants