diff --git a/packages/react-codemirror/src/e2e_tests/signature-help.spec.tsx b/packages/react-codemirror/src/e2e_tests/signature-help.spec.tsx index 95e86b18f..6bb028e94 100644 --- a/packages/react-codemirror/src/e2e_tests/signature-help.spec.tsx +++ b/packages/react-codemirror/src/e2e_tests/signature-help.spec.tsx @@ -89,14 +89,14 @@ test('Signature help shows the description for the first argument', async ({ }); }); -test('Signature help works when the parenthesis has been auto closed and the cursor is placed before )', async ({ +test('Signature help shows the description for the first argument when the cursor is at that position', async ({ page, mount, }) => { const query = 'CALL apoc.import.csv()'; await mount( - , + , ); const tooltip = page.locator('.cm-tooltip-signature-help').last(); @@ -133,6 +133,46 @@ test('Signature help shows the description for the second argument', async ({ }); }); +test('Signature help shows the description for the second argument when the cursor is at that position', async ({ + page, + mount, +}) => { + const query = 'CALL apoc.import.csv(nodes,)'; + + await mount( + , + ); + + const tooltip = page.locator('.cm-tooltip-signature-help').last(); + + await testTooltip(tooltip, { + includes: [ + 'rels :: LIST', + 'Imports `NODE` and `RELATIONSHIP` values with the given labels and types from the provided CSV file', + ], + }); +}); + +test('Signature help shows the description for the second argument when the cursor is at that position, even after whitespaces', async ({ + page, + mount, +}) => { + const query = 'CALL apoc.import.csv(nodes, )'; + + await mount( + , + ); + + const tooltip = page.locator('.cm-tooltip-signature-help').last(); + + await testTooltip(tooltip, { + includes: [ + 'rels :: LIST', + 'Imports `NODE` and `RELATIONSHIP` values with the given labels and types from the provided CSV file', + ], + }); +}); + test('Signature help shows description for arguments with a space following a separator', async ({ page, mount, diff --git a/packages/react-codemirror/src/lang-cypher/signature-help.ts b/packages/react-codemirror/src/lang-cypher/signature-help.ts index fe67aea7d..32d77f392 100644 --- a/packages/react-codemirror/src/lang-cypher/signature-help.ts +++ b/packages/react-codemirror/src/lang-cypher/signature-help.ts @@ -1,29 +1,18 @@ import { EditorState, StateField } from '@codemirror/state'; import { showTooltip, Tooltip } from '@codemirror/view'; -import { - CallClauseContext, - findParent, - FunctionInvocationContext, - ParserRuleContext, - parserWrapper, - signatureHelp, - StatementsContext, -} from '@neo4j-cypher/language-support'; +import { signatureHelp } from '@neo4j-cypher/language-support'; import { CypherConfig } from './lang-cypher'; -function isMethodNameOrExpressionName(parent: ParserRuleContext) { - return ( - parent instanceof FunctionInvocationContext || - parent instanceof CallClauseContext || - parent instanceof StatementsContext - ); -} +function getTriggerCharacter(query: string, offset: number) { + let i = offset - 1; + let triggerCharacter = query.at(i); + + while (/\s/.test(triggerCharacter) && i > 0) { + i -= 1; + triggerCharacter = query.at(i); + } -function isMethodName(parent: ParserRuleContext) { - return ( - parent instanceof FunctionInvocationContext || - parent instanceof CallClauseContext - ); + return triggerCharacter; } function getSignatureHelpTooltip( @@ -32,34 +21,19 @@ function getSignatureHelpTooltip( ): Tooltip[] { let result: Tooltip[] = []; const schema = config.schema; + const ranges = state.selection.ranges; + const range = ranges.at(0); + + if (schema && ranges.length === 1 && range.from === range.to) { + const position = range.from; + const query = state.doc.toString(); + + const triggerCharacter = getTriggerCharacter(query, position); + + if (triggerCharacter === '(' || triggerCharacter === ',') { + const queryUntilPosition = query.slice(0, position); - const tokens = parserWrapper.parsingResult.tokens.filter( - (token) => token.channel == 0, - ); - const lastToken = tokens.at(-2); - const prevToken = tokens.at(-3); - - if (schema && lastToken) { - const pos = state.selection.main.head; - const tree = parserWrapper.parsingResult; - const isOpenBracket = lastToken.text === '('; - const isPairOfBrackets = - prevToken !== undefined && - prevToken.text === '(' && - lastToken.text === ')'; - const isSeparator = lastToken.text === ','; - - if ( - (isOpenBracket || isPairOfBrackets || isSeparator) && - tree && - findParent(tree.stopNode, (parent) => - isOpenBracket - ? isMethodNameOrExpressionName(parent) - : isMethodName(parent), - ) - ) { - const query = state.doc.toString(); - const signatureHelpInfo = signatureHelp(query, schema); + const signatureHelpInfo = signatureHelp(queryUntilPosition, schema); const activeSignature = signatureHelpInfo.activeSignature; const signatures = signatureHelpInfo.signatures; const activeParameter = signatureHelpInfo.activeParameter; @@ -85,7 +59,7 @@ function getSignatureHelpTooltip( result = [ { - pos: pos, + pos: position, above: true, strictSide: true, arrow: true,