diff --git a/server/src/lfortran-language-server.ts b/server/src/lfortran-language-server.ts index a77dd12..126d3fd 100644 --- a/server/src/lfortran-language-server.ts +++ b/server/src/lfortran-language-server.ts @@ -106,6 +106,7 @@ const symbolKindToCompletionItemKind: Map = new const RE_IDENTIFIABLE: RegExp = /^[a-z0-9_]$/i; const RE_ALPHABETIC: RegExp = /^[a-z]$/i; const RE_ALPHA_UNDER: RegExp = /^[a-z_]$/i; +const RE_QUOTE: RegExp = /['"]/; interface FileCacheEntry { mtime: Date; @@ -638,13 +639,14 @@ export class LFortranLanguageServer { let currLine: number = 0; let currCol: number = 0; + const reIdentifiable: RegExp = RE_IDENTIFIABLE; + const reAlphabetic: RegExp = RE_ALPHABETIC; + const reQuote: RegExp = RE_QUOTE; for (let i = 0, k = text.length; i < k; i++) { let c: string = text[i]; if ((line === currLine) && (column === currCol)) { - const reIdentifiable: RegExp = RE_IDENTIFIABLE; - const reAlphabetic: RegExp = RE_ALPHABETIC; - if (!reIdentifiable.test(c) && (i > 0) && reIdentifiable.test(text[i - 1])) { + if (!reIdentifiable.test(c) && !reQuote.test(c) && (i > 0) && reIdentifiable.test(text[i - 1])) { // Cursor is just right of the query string's word boundary. i--; c = text[i]; @@ -664,6 +666,9 @@ export class LFortranLanguageServer { while ((u < k) && reIdentifiable.test(text[u])) { u++; } + if (RE_QUOTE.test(text[u]) && (u > 0) && (text[u - 1] === '_')) { + u--; + } query = text.substring(l, u); break; } @@ -846,7 +851,10 @@ export class LFortranLanguageServer { currCol += j; i += (j - 1); - if ((j === l) && (((i + 1) === k) || !reIdentifiable.test(text[i + 1]))) { + if ((j === l) && + (((i + 1) === k) || + !reIdentifiable.test(text[i + 1]) || + ((text[i + 1] === '_') && ((i + 2) < k) && RE_QUOTE.test(text[i + 2])))) { const endLine: number = currLine; const endCol: number = currCol; @@ -923,11 +931,11 @@ export class LFortranLanguageServer { return workspaceEdit; } - async onDocumentHighlight(params: DocumentHighlightParams): Promise { + async onDocumentHighlight(params: DocumentHighlightParams): Promise { const fnid: string = "onDocumentHighlight"; const start: number = performance.now(); - let highlights: DocumentHighlight[] | null = null; + let highlights: DocumentHighlight[]; const uri: string = params.textDocument.uri; const document = this.documents.get(uri); @@ -936,15 +944,14 @@ export class LFortranLanguageServer { const pos: Position = params.position; const query: string | null = this.extractQuery(text, pos.line, pos.character); if (query !== null) { - const dictionary = this.dictionaries.get(uri); - if ((dictionary !== undefined) && dictionary.contains(query)) { - highlights = this.highlightSymbol(text, query).map(range => ({ - range: range, - })); - } else { - this.logWarn('Cannot find symbol to highlight: "%s"', query); - } + highlights = this.highlightSymbol(text, query).map(range => ({ + range: range, + })); + } else { + highlights = []; } + } else { + highlights = []; } if (this.logger.isBenchmarkOrTraceEnabled()) { @@ -956,6 +963,7 @@ export class LFortranLanguageServer { highlights ); } + return highlights; } } diff --git a/server/test/spec/lfortran-language-server.spec.ts b/server/test/spec/lfortran-language-server.spec.ts index 3c204fe..c5fec88 100644 --- a/server/test/spec/lfortran-language-server.spec.ts +++ b/server/test/spec/lfortran-language-server.spec.ts @@ -611,6 +611,62 @@ describe("LFortranLanguageServer", () => { query = server.extractQuery(text, 0, 27); // actual text " " assert.isNull(query); }); + + it("extracts prefix types", () => { + const text: string = "print *, foo_'string'"; + + let query: string | null = server.extractQuery(text, 0, 8); + assert.isNull(query); + + query = server.extractQuery(text, 0, 9); + assert.equal(query, "foo"); + + query = server.extractQuery(text, 0, 10); + assert.equal(query, "foo"); + + query = server.extractQuery(text, 0, 11); + assert.equal(query, "foo"); + + query = server.extractQuery(text, 0, 12); + assert.equal(query, "foo"); + + query = server.extractQuery(text, 0, 13); + assert.isNull(query); + }); + + it("extracts suffix types", () => { + const text: string = "f(123.456_my_dbl) + x"; + + let query: string | null = server.extractQuery(text, 0, 8); + assert.isNull(query); + + query = server.extractQuery(text, 0, 9); + assert.isNull(query); + + query = server.extractQuery(text, 0, 10); + assert.equal(query, "my_dbl"); + + query = server.extractQuery(text, 0, 11); + assert.equal(query, "my_dbl"); + + query = server.extractQuery(text, 0, 12); + assert.equal(query, "my_dbl"); + + query = server.extractQuery(text, 0, 13); + assert.equal(query, "my_dbl"); + + query = server.extractQuery(text, 0, 14); + assert.equal(query, "my_dbl"); + + query = server.extractQuery(text, 0, 15); + assert.equal(query, "my_dbl"); + + query = server.extractQuery(text, 0, 16); + assert.equal(query, "my_dbl"); + + query = server.extractQuery(text, 0, 17); + assert.isNull(query); + }); }); describe("onCompletion", () => { @@ -888,7 +944,7 @@ describe("LFortranLanguageServer", () => { }); describe("onDocumentHighlight", () => { - it("does not highlight symbols when they are not recognized", async () => { + it("highlights symbols when they are not recognized", async () => { const text: string = "foo bar foo baz.foo"; document.getText.returns(text); @@ -923,11 +979,24 @@ describe("LFortranLanguageServer", () => { }; const actual: DocumentHighlight[] | undefined | null = await server.onDocumentHighlight(params); - assert.isNull(actual); + assert.deepEqual(actual, [ + { + range: { + start: { + line: 0, + character: 4, + }, + end: { + line: 0, + character: 7, + }, + }, + }, + ]); }); it("highlights symbols when they are recognized", async () => { - const text: string = "foo bar foo baz.foo"; + const text: string = "foo bar foo baz%foo foo_'str' 123.456_foo"; document.getText.returns(text); const symbols: SymbolInformation[] = [ @@ -989,6 +1058,30 @@ describe("LFortranLanguageServer", () => { }, }, }, + { + range: { + start: { + line: 0, + character: 20, + }, + end: { + line: 0, + character: 23, + }, + }, + }, + { + range: { + start: { + line: 0, + character: 38, + }, + end: { + line: 0, + character: 41, + }, + }, + }, ]; const params: DocumentHighlightParams = {