Add context-aware shell completion and inline suggestions#576
Add context-aware shell completion and inline suggestions#576tnaum-ms merged 32 commits intorel/release_0.8.0from
Conversation
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)
There was a problem hiding this comment.
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
ShellInputHandlercallbacks. - 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. |
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)
|
Review issue #6 — Issue: Action: Documented the contract in the JSDoc: 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)
|
Review issue #8 — No rate limiting on background cache fetch triggers (S4 — Low) Issue: Action: Added a Commit: e8cce7b |
|
Review issue #9 — Issue: Action: Replaced the hardcoded set with 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)
bd19c36 to
795f52f
Compare
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.
45fe84b to
84d699f
Compare
# Conflicts: # src/documentdb/shell/DocumentDBShellPty.ts
… playground execution
…o-quoting, and error code extraction for cleaner messages
…ns in shell autocompletion
This pull request introduces advanced shell completion and inline suggestion ("ghost text") features to the
DocumentDBShellPtyclass, 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:
ShellCompletionProviderandShellGhostTextto 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]find()afterdb.<collection>.).Terminal State and Cleanup Improvements:
These enhancements make the shell more user-friendly and efficient by providing context-aware completions and suggestions as users type.