@@ -49,6 +49,8 @@ import { Script, createContext, runInContext } from 'vm';
4949import { installPasteSupport } from './repl-paste-support' ;
5050import util from 'util' ;
5151
52+ import { MongoDBAutocompleter } from '@mongodb-js/mongodb-ts-autocomplete' ;
53+
5254declare const __non_webpack_require__ : any ;
5355
5456/**
@@ -131,6 +133,53 @@ type Mutable<T> = {
131133 - readonly [ P in keyof T ] : T [ P ] ;
132134} ;
133135
136+ function filterStartingWith ( {
137+ kind,
138+ name,
139+ trigger,
140+ } : {
141+ kind : string ;
142+ name : string ;
143+ trigger : string ;
144+ } ) : boolean {
145+ name = name . toLocaleLowerCase ( ) ;
146+ trigger = trigger . toLocaleLowerCase ( ) ;
147+
148+ /*
149+ 1. If the trigger was blank and the kind is not property/method filter out the
150+ result. This way if you autocomplete db.test.find({ you don't get all the
151+ global variables, just the known collection field names and mql but you can
152+ still autocomplete global variables and functions if you type part of the
153+ name.
154+ 2. Don't filter out exact matches (where filter === name) so that we match the
155+ behaviour of the node completer.
156+ 3. Make sure the name starts with the trigger, otherwise it will return every
157+ possible property/name that's available at that level. ie. all the "peer"
158+ properties of the things that match.
159+ */
160+ //console.log(name, kind);
161+ // TODO: This can be improved further if we first see if there are any
162+ // property/method kind completions and then just use those, then if there
163+ // aren't return all completions. The reason is that db.test.find({m makes it
164+ // through this filter and then you get all globals starting with m anyway.
165+ // But to properly solve it we need more context. ie. if you're after { (ie.
166+ // inside an object literal) and you're to the left of a : (or there isn't
167+ // one) then you probably don't want globals regardless. If you're to the
168+ // right of a : it is probably fine because you could be using a variable.
169+ return (
170+ ( trigger !== '' || kind === 'property' || kind === 'method' ) &&
171+ name . startsWith ( trigger )
172+ ) ;
173+ }
174+
175+ function transformAutocompleteResults (
176+ line : string ,
177+ results : { result : string } [ ]
178+ ) : [ string [ ] , string ] | [ string [ ] , string , 'exclusive' ] {
179+ // TODO: actually use 'exclusive' when we should
180+ return [ results . map ( ( result ) => result . result ) , line ] ;
181+ }
182+
134183/**
135184 * An instance of a `mongosh` REPL, without any of the actual I/O.
136185 * Specifically, code called by this class should not do any
@@ -430,10 +479,22 @@ class MongoshNodeRepl implements EvaluationListener {
430479 this . outputFinishString += installPasteSupport ( repl ) ;
431480
432481 const origReplCompleter = promisify ( repl . completer . bind ( repl ) ) ; // repl.completer is callback-style
433- const mongoshCompleter = completer . bind (
434- null ,
435- instanceState . getAutocompleteParameters ( )
436- ) ;
482+ let newMongoshCompleter : MongoDBAutocompleter ;
483+ let oldMongoshCompleter : (
484+ line : string
485+ ) => Promise < [ string [ ] , string , 'exclusive' ] | [ string [ ] , string ] > ;
486+ if ( process . env . USE_NEW_AUTOCOMPLETE ) {
487+ const autocompletionContext = instanceState . getAutocompletionContext ( ) ;
488+ newMongoshCompleter = new MongoDBAutocompleter ( {
489+ context : autocompletionContext ,
490+ autocompleterOptions : { filter : filterStartingWith } ,
491+ } ) ;
492+ } else {
493+ oldMongoshCompleter = completer . bind (
494+ null ,
495+ instanceState . getAutocompleteParameters ( )
496+ ) ;
497+ }
437498 const innerCompleter = async (
438499 text : string
439500 ) : Promise < [ string [ ] , string ] > => {
@@ -442,8 +503,19 @@ class MongoshNodeRepl implements EvaluationListener {
442503 [ replResults , replOrig ] ,
443504 [ mongoshResults , , mongoshResultsExclusive ] ,
444505 ] = await Promise . all ( [
445- ( async ( ) => ( await origReplCompleter ( text ) ) || [ [ ] ] ) ( ) ,
446- ( async ( ) => await mongoshCompleter ( text ) ) ( ) ,
506+ ( async ( ) => {
507+ const nodeResults = ( await origReplCompleter ( text ) ) || [ [ ] ] ;
508+ return nodeResults ;
509+ } ) ( ) ,
510+ ( async ( ) => {
511+ if ( process . env . USE_NEW_AUTOCOMPLETE ) {
512+ const results = await newMongoshCompleter . autocomplete ( text ) ;
513+ const transformed = transformAutocompleteResults ( text , results ) ;
514+ return transformed ;
515+ } else {
516+ return oldMongoshCompleter ( text ) ;
517+ }
518+ } ) ( ) ,
447519 ] ) ;
448520 this . bus . emit ( 'mongosh:autocompletion-complete' ) ; // For testing.
449521
0 commit comments