Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit f5b8292

Browse files
committedFeb 28, 2024··
Adds caret to autocompletions
1 parent 2ed0598 commit f5b8292

File tree

7 files changed

+51
-41
lines changed

7 files changed

+51
-41
lines changed
 

‎packages/language-server/src/autocompletion.ts

+3-9
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@ import {
44
TextDocuments,
55
} from 'vscode-languageserver/node';
66

7-
import { Range } from 'vscode-languageserver-types';
8-
97
import { autocomplete } from '@neo4j-cypher/language-support';
108
import { Neo4jSchemaPoller } from '@neo4j-cypher/schema-poller';
119
import { TextDocument } from 'vscode-languageserver-textdocument';
@@ -19,16 +17,12 @@ export function doAutoCompletion(
1917
if (textDocument === undefined) return [];
2018

2119
const position: Position = textDocumentPosition.position;
22-
const range: Range = {
23-
// TODO Nacho: We are parsing from the begining of the file.
24-
// Do we need to parse from the begining of the current query?
25-
start: Position.create(0, 0),
26-
end: position,
27-
};
20+
const offset = textDocument.offsetAt(position);
2821

2922
return autocomplete(
30-
textDocument.getText(range),
23+
textDocument.getText(),
3124
neo4j.metadata?.dbSchema ?? {},
25+
offset,
3226
);
3327
};
3428
}

‎packages/language-support/src/autocompletion/autocompletion.ts

+8-6
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
import { CompletionItem } from 'vscode-languageserver-types';
22

33
import { DbSchema } from '../dbSchema';
4+
import { findCaret } from '../helpers';
45
import { parserWrapper } from '../parserWrapper';
56
import { completionCoreCompletion } from './completionCoreCompletions';
67

78
export function autocomplete(
8-
textUntilPosition: string,
9+
query: string,
910
dbSchema: DbSchema,
10-
// TODO Add caret index here
11+
caretPosition: number = query.length,
1112
): CompletionItem[] {
12-
const parsingResult = parserWrapper.parse(textUntilPosition);
13+
const parsingResult = parserWrapper.parse(query);
1314
/* We try to locate the latest statement by finding the latest available `;`
1415
in the query and take from that point to the end of the query
1516
@@ -22,9 +23,10 @@ export function autocomplete(
2223
If there was no ;, we don't want to reparse, so we return undefined
2324
inside findLatestStatement
2425
*/
25-
const lastStatement = parsingResult.statementsParsing.at(-1);
26-
if (lastStatement !== undefined) {
27-
return completionCoreCompletion(lastStatement, dbSchema);
26+
const caret = findCaret(parsingResult, caretPosition);
27+
if (caret) {
28+
const statement = caret.statement;
29+
return completionCoreCompletion(statement, dbSchema);
2830
}
2931

3032
return [];

‎packages/language-support/src/helpers.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ export function findCaret(
126126

127127
while (j < tokens.length && keepLooking) {
128128
const currentToken = tokens[j];
129-
keepLooking = currentToken.start < caretPosition;
129+
keepLooking = currentToken.start <= caretPosition;
130130

131131
if (currentToken.channel === 0 && keepLooking) {
132132
result = { statement: statement, token: currentToken };

‎packages/language-support/src/parserWrapper.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ export function createParsingScaffolding(query: string): ParsingScaffolding {
101101
stmTokenStreams.map((t) => {
102102
const tokens = [...t.tokens];
103103
const parser = new CypherParser(t);
104+
parser.removeErrorListeners();
104105

105106
return {
106107
parser: parser,
@@ -134,7 +135,6 @@ export function createParsingResult(query: string): ParsingResult {
134135
const variableFinder = new VariableCollector();
135136
const errorListener = new SyntaxErrorsListener();
136137
parser._parseListeners = [labelsCollector, variableFinder];
137-
parser.removeErrorListeners();
138138
parser.addErrorListener(errorListener);
139139
const ctx = parser.statementsOrCommands();
140140
// The statement is empty if we cannot find anything that is not EOF or a space

‎packages/language-support/src/signatureHelp.ts

+32-20
Original file line numberDiff line numberDiff line change
@@ -134,31 +134,43 @@ class SignatureHelper extends CypherCmdParserListener {
134134
}
135135

136136
export function signatureHelp(
137-
fullQuery: string,
137+
query: string,
138138
dbSchema: DbSchema,
139-
caretPosition: number,
139+
caretPosition: number = query.length,
140140
): SignatureHelp {
141141
let result: SignatureHelp = emptyResult;
142-
143-
const parserResult = parserWrapper.parse(fullQuery);
144-
const caret = findCaret(parserResult, caretPosition);
145-
146-
if (caret) {
147-
const statement = caret.statement;
148-
149-
const signatureHelper = new SignatureHelper(statement.tokens, caret.token);
150-
151-
ParseTreeWalker.DEFAULT.walk(signatureHelper, statement.ctx);
152-
const method = signatureHelper.result;
153-
154-
if (method !== undefined) {
155-
if (method.methodType === MethodType.function) {
156-
result = toSignatureHelp(dbSchema.functionSignatures, method);
157-
} else {
158-
result = toSignatureHelp(dbSchema.procedureSignatures, method);
142+
/* We need the token inmediately before the caret
143+
144+
CALL something(
145+
^
146+
because in this case what gives us information on where we are
147+
in the procedure is not the space at the caret, but the opening (
148+
*/
149+
const prevCaretPosition = caretPosition - 1;
150+
151+
if (prevCaretPosition > 0) {
152+
const parserResult = parserWrapper.parse(query);
153+
const caret = findCaret(parserResult, prevCaretPosition);
154+
155+
if (caret) {
156+
const statement = caret.statement;
157+
158+
const signatureHelper = new SignatureHelper(
159+
statement.tokens,
160+
caret.token,
161+
);
162+
163+
ParseTreeWalker.DEFAULT.walk(signatureHelper, statement.ctx);
164+
const method = signatureHelper.result;
165+
166+
if (method !== undefined) {
167+
if (method.methodType === MethodType.function) {
168+
result = toSignatureHelp(dbSchema.functionSignatures, method);
169+
} else {
170+
result = toSignatureHelp(dbSchema.procedureSignatures, method);
171+
}
159172
}
160173
}
161174
}
162-
163175
return result;
164176
}

‎packages/language-support/src/tests/autocompletion/completionAssertionHelpers.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,20 @@ import { DbSchema } from '../../dbSchema';
44

55
export function testCompletions({
66
query,
7+
offset = query.length,
78
dbSchema = {},
89
excluded = [],
910
expected = [],
1011
assertEmpty = false,
1112
}: {
1213
query: string;
14+
offset?: number;
1315
dbSchema?: DbSchema;
1416
excluded?: Partial<CompletionItem>[];
1517
expected?: CompletionItem[];
1618
assertEmpty?: boolean;
1719
}) {
18-
const actualCompletionList = autocomplete(query, dbSchema);
20+
const actualCompletionList = autocomplete(query, dbSchema, offset);
1921

2022
if (assertEmpty) {
2123
expect(actualCompletionList).toEqual([]);

‎packages/language-support/src/tests/benchmarks/benchmark.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -107,16 +107,16 @@ suite
107107
const query = largePokemonquery + periodicIterate + periodicIterateFirstArg;
108108
parserWrapper.clearCache();
109109
// This mimics getting the cursor back in the query and retriggering signature help
110-
signatureHelp(query, testData.mockSchema, query.length - 1);
111-
signatureHelp(query, testData.mockSchema, subQuery.length - 1);
110+
signatureHelp(query, testData.mockSchema, query.length);
111+
signatureHelp(query, testData.mockSchema, subQuery.length);
112112
})
113113
.add('multistatement - autocompletion', function () {
114114
const query = tictactoe + ';\n' + tictactoe;
115115
const subQuery = tictactoe;
116116
parserWrapper.clearCache();
117117
// This mimics getting the cursor back in the query and retriggering auto-completion
118118
autocomplete(query, testData.mockSchema);
119-
autocomplete(subQuery, testData.mockSchema);
119+
autocomplete(query, testData.mockSchema, subQuery.length);
120120
});
121121

122122
Object.entries(autocompletionQueries).forEach(([name, query]) => {

0 commit comments

Comments
 (0)
Please sign in to comment.