diff --git a/packages/cli-repl/src/cli-repl.spec.ts b/packages/cli-repl/src/cli-repl.spec.ts index 499d2b85bd..c8240d0406 100644 --- a/packages/cli-repl/src/cli-repl.spec.ts +++ b/packages/cli-repl/src/cli-repl.spec.ts @@ -1177,6 +1177,13 @@ describe('CliRepl', () => { await waitCompletion(cliRepl.bus); expect(output).to.include('use admin'); }); + + it('completes query operators', async() => { + input.write('db.movies.find({year: {$g'); + await tabtab(); + await waitCompletion(cliRepl.bus); + expect(output).to.include('db.movies.find({year: {$gte'); + }); }); } }); diff --git a/packages/cli-repl/src/mongosh-repl.ts b/packages/cli-repl/src/mongosh-repl.ts index 4e0e101b7a..ba3bec0b35 100644 --- a/packages/cli-repl/src/mongosh-repl.ts +++ b/packages/cli-repl/src/mongosh-repl.ts @@ -204,13 +204,22 @@ class MongoshNodeRepl implements EvaluationListener { if (mongoshResultsExclusive) { return [mongoshResults, text]; } + + // The REPL completer may not complete the entire string; for example, + // when completing ".ed" to ".editor", it reports as having completed + // only the last piece ("ed"), or when completing "{ $g", it completes + // only "$g" and not the entire result. + // The mongosh completer always completes on the entire string. + // In order to align them, we always extend the REPL results to include + // the full string prefix. + const replResultPrefix = replOrig ? text.substr(0, text.lastIndexOf(replOrig)) : ''; + const longReplResults = replResults.map((result: string) => replResultPrefix + result); + // Remove duplicates, because shell API methods might otherwise show // up in both completions. - const deduped = [...new Set([...replResults, ...mongoshResults])]; + const deduped = [...new Set([...longReplResults, ...mongoshResults])]; - // Use the REPL completer's original text when available, because that - // makes a difference for completion of REPL commands like `.editor`. - return [deduped, replOrig ?? text]; + return [deduped, text]; } finally { this.insideAutoCompleteOrGetPrompt = false; }