From cbe8a5fbc44b1acfd75a721ce4256044030badd1 Mon Sep 17 00:00:00 2001 From: Brett Saviano Date: Tue, 26 Mar 2024 07:59:20 -0400 Subject: [PATCH] Fixes #311 --- CHANGELOG.md | 1 + server/src/providers/signatureHelp.ts | 173 +++++++++++--------------- 2 files changed, 75 insertions(+), 99 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 102b84d..d6332e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ - Fix issue [#308](https://github.com/intersystems/language-server/issues/308): Enhance intellisense for %New when %OnNew is defined - Fix issue [#309](https://github.com/intersystems/language-server/issues/309): Fix coloring of CSS urls that contain a right parenthesis - Fix issue [#310](https://github.com/intersystems/language-server/issues/310): Update documentation links for preprocessor directives +- Fix issue [#311](https://github.com/intersystems/language-server/issues/311): Fix SignatureHelp parameter highlighting for parameters with default values that contain a comma - Parser changes: - DP-429226: Coloring for User Defined Aggregate Functions (UDAF) - DP-429298: Coloring support for new SQL Scalar function DATE_TRUNC() diff --git a/server/src/providers/signatureHelp.ts b/server/src/providers/signatureHelp.ts index db357e7..fd14ffa 100644 --- a/server/src/providers/signatureHelp.ts +++ b/server/src/providers/signatureHelp.ts @@ -1,4 +1,4 @@ -import { Position, SignatureHelp, SignatureHelpParams, SignatureHelpTriggerKind, SignatureInformation, Range, MarkupKind } from 'vscode-languageserver/node'; +import { Position, SignatureHelp, SignatureHelpParams, SignatureHelpTriggerKind, SignatureInformation, Range, MarkupKind, ParameterInformation } from 'vscode-languageserver/node'; import { getServerSpec, getLanguageServerSettings, makeRESTRequest, getMacroContext, findFullRange, getClassMemberContext, beautifyFormalSpec, documaticHtmlToMarkdown, findOpenParen, getParsedDocument, quoteUDLIdentifier } from '../utils/functions'; import { ServerSpec, SignatureHelpDocCache, SignatureHelpMacroContext } from '../utils/types'; import { documents } from '../utils/variables'; @@ -21,33 +21,35 @@ var signatureHelpStartPosition: Position | undefined = undefined; /** Determine the active parameter number */ function determineActiveParam(text: string): number { - let activeparam = 0; - let openparencount = 0; - let instring = false; - let incomment = false; - for (let i = 0; i < text.length; i++) { - const char = text.charAt(i); - if (char === "(") { - openparencount++; - } - else if (char === ")") { - openparencount--; - } - else if (char === '"') { - instring = !instring; - } - else if (char === "/" && (i < text.length - 1) && text.charAt(i + 1) == "*" && !incomment) { - incomment = true; - } - else if (char === "*" && (i < text.length - 1) && text.charAt(i + 1) == "/" && incomment) { - incomment = false; - } - else if (char === "," && openparencount === 0 && !instring && !incomment) { - // Only increment parameter number if comma isn't inside nested parentheses, a string literal or a multiline-style comment - activeparam++; + let activeParam = 0, openParenCount = 0, openBraceCount = 0, inQuote = false, inComment = false; + Array.from(text).forEach((char: string, idx: number) => { + switch (char) { + case "{": + if (!inQuote && !inComment) openBraceCount++; + break; + case "}": + if (!inQuote && !inComment) openBraceCount--; + break; + case "(": + if (!inQuote && !inComment) openParenCount++; + break; + case ")": + if (!inQuote && !inComment) openParenCount--; + break; + case "\"": + if (!inComment) inQuote = !inQuote; + break; + case "/": + if (!inQuote && !inComment && (idx < text.length - 1) && text[idx+1] == "*") inComment = true; + break; + case "*": + if (inComment && (idx < text.length - 1) && text[idx+1] == "/") inComment = false; + break; + case ",": + if (!inQuote && !inComment && !openBraceCount && !openParenCount) activeParam++; } - } - return activeparam; + }); + return activeParam; } /** Placeholder for the Markdown emphasis characters before an argument. */ @@ -123,6 +125,39 @@ function markdownifyExpansion(exp: string[]): string { .replace(new RegExp(emphasizeSuffix,"g"),"**_"); } +/** Returns the [start,end] tuples for all parameters in `formalSpec` */ +function formalSpecToParamsArr(formalSpec: string): ParameterInformation[] { + const result: ParameterInformation[] = []; + if (formalSpec.replace(/\s+/g,"") == "()") return result; // No parameters + let currentParamStart = 1, openParenCount = 0, openBraceCount = 0, inQuote = false; + Array.from(formalSpec).forEach((char: string, idx: number) => { + switch (char) { + case "{": + if (!inQuote) openBraceCount++; + break; + case "}": + if (!inQuote) openBraceCount--; + break; + case "(": + if (!inQuote) openParenCount++; + break; + case ")": + if (!inQuote) openParenCount--; + break; + case "\"": + inQuote = !inQuote; + break; + case ",": + if (!inQuote && !openBraceCount && openParenCount == 1) { + result.push(ParameterInformation.create([currentParamStart,idx])); + currentParamStart = idx + 1; + } + } + }); + result.push(ParameterInformation.create([currentParamStart,formalSpec.length - 1])); + return result; +} + export async function onSignatureHelp(params: SignatureHelpParams): Promise { if (params.context === undefined) {return null;} const doc = documents.get(params.textDocument.uri); @@ -222,23 +257,11 @@ export async function onSignatureHelp(params: SignatureHelpParams): Promise