srecord noeq LeftArrowScriptAutoCompleter(GazelleV_LeftArrowScriptParser parser) { LS tok; CharInToken cursor; S typedCharacters; ScoredStringSearcher searcher; settable new G22Utils g22utils; void seek(S text, int iChar) { parser.setText(text); parser.init(); tok = parser.tok; cursor = charIndexToCharInToken(tok, iChar); // move one token left if necessary if (cursor.iTok > 1 && cursor.iChar == 0 && empty(space())) { cursor.iTok -= 2; cursor.iChar = l(token()); } typedCharacters = takeFirst(cursor.token(), cursor.iChar); } S typedCharacters() { printVars ifdef LeftArrowScriptAutoCompleter_debug(+cursor); ret typedCharacters; } S space() { ret get(tok, cursor.iTok-1); } S token() { ret get(tok, cursor.iTok); } S prevToken() { ret get(tok, cursor.iTok-2); } bool beginningOfCmd() { ret eqOneOf(prevToken(), ";", "{", "}") || containsNewLine(space()); } Cl getCompletions() { ret searcher()!; } ScoredStringSearcher searcher() { searcher = new ScoredStringSearcher(typedCharacters); if (empty(typedCharacters)) searcher.returnAll = true; S prev = prevToken(); printVars ifdef LeftArrowScriptAutoCompleter_debug(+beginningOfCmd(), +prev, +cursor, +typedCharacters); if (beginningOfCmd() || !isIdentifier(prev)) { addToSearcher(globalMethodNames()); addToSearcher(globalClassNames()); } addToSearcher("true", "false", "null"); ret searcher; } swappable Cl globalMethodNames() { ret concatMap methodNames(parser.functionContainers); } simplyCached Cl globalClassNames() { var packages = mapToTreeSet(standardImports_fullyImportedPackages(), pkg -> pkg + "."); LS filtered = filter(g22utils.classNameResolver().allFullyQualifiedClassNames(), className -> startsWithOneOf_treeSet(className, packages)); ret mapToSet(afterLastDot(filtered)); } void addToSearcher(Iterable or S... l) { fOr (s : l) if (!eq(s, typedCharacters)) searcher.add(s); } }