From d2d5a279ad5f84245d89f7fbb8c0bcaa72761d8a Mon Sep 17 00:00:00 2001 From: Andre Henriques Date: Thu, 29 Feb 2024 15:39:13 +0000 Subject: [PATCH] chore: more work on the lsp --- index.ts | 2 +- languagetool.ts | 2 +- lsp.ts | 16 +- lsp_run.ts | 24 +- parser.ts | 901 +++++++++++++++++++++++++----------------------- 5 files changed, 511 insertions(+), 434 deletions(-) diff --git a/index.ts b/index.ts index 6d93201..ed9f119 100644 --- a/index.ts +++ b/index.ts @@ -15,6 +15,6 @@ const res = parseLsp(file); fs.writeFileSync('./res', res.text); //const diag = await diagnosticsRequests(res); -const diag = await getDiagnostics(file); +//const diag = await getDiagnostics(file); //add_personal(['AutoML']); diff --git a/languagetool.ts b/languagetool.ts index 0542ad5..e765cc6 100644 --- a/languagetool.ts +++ b/languagetool.ts @@ -6,7 +6,7 @@ export async function add_personal(words: string[]): Promise { method: 'POST', headers: { 'Accept': 'application/json', - 'authorization': process.env.AUTHORIZATION ?? '', + 'authorization': process.env.AUTHORIZATION_MY_LTEX ?? '', 'content-type': 'application/json', }, body: JSON.stringify({ diff --git a/lsp.ts b/lsp.ts index 4827694..a486d61 100644 --- a/lsp.ts +++ b/lsp.ts @@ -187,11 +187,19 @@ async function handleJSON(req: RPCRequest) { const character = req.params.range.start.character; const line = req.params.range.start.line; + if (!req.params.context?.diagnostics[0]) { + sendRPCMessage(req, [{ + title: "No diagnostics found in this file" + }]); + return; + } + let item: GetDiagnosticsReturn | undefined = undefined; - console.log(JSON.stringify(req.params)); + console.log(JSON.stringify(req.params) + "\n\n\n"); + console.log(JSON.stringify(req.params.context.diagnostics[0]) + "\n\n\n"); - if (!req.params.context?.diagnostics || !req.params.context?.diagnostics[0] || typeof req.params.context?.diagnostics[0].data != 'number') { + if (typeof req.params.context?.diagnostics[0].data != 'number') { for (const _item of saved) { if (_item.range.end.line >= line && _item.range.start.line <= line) { if (_item.range.end.character >= character && _item.range.start.character <= line) { @@ -218,7 +226,7 @@ async function handleJSON(req: RPCRequest) { }]); return; } - + const items: { title: string, edit?: { @@ -236,7 +244,7 @@ async function handleJSON(req: RPCRequest) { changes: { [reqO.params.textDocument.uri]: [ { - range: item!.range, + range: reqO.params.context.diagnostics[0].range, newText: value } ] diff --git a/lsp_run.ts b/lsp_run.ts index b686078..68a2cf2 100644 --- a/lsp_run.ts +++ b/lsp_run.ts @@ -2,12 +2,24 @@ import { error, handleData, log } from "./lsp"; console.log = log; -process.stdin.resume(); +log('Started the server logging'); + + +try { + log('Listening for Input') + process.stdin.resume(); +} catch (e: any) { + log('failed to listen to the stdin'); + log(e.toString()); + throw e; +} process.stdin.on('data', function(data) { - try { - handleData(data); - } catch (e) { - error("TRY GOT ERROR:" + e) - } + log('Got the data function'); + try { + handleData(data); + } catch (e) { + log("got here") + error("TRY GOT ERROR:" + e) + } }) diff --git a/parser.ts b/parser.ts index 21c9589..d24eca9 100644 --- a/parser.ts +++ b/parser.ts @@ -2,555 +2,612 @@ import * as fs from 'fs'; import process from 'process'; import { Severity, type Dialog } from './lsp'; -import { createSourceFile } from 'typescript'; +import { OperationCanceledException } from 'typescript'; type ParseResultConversion = { - length: number, - original_length?: number, - original_position: number, - position: number, - type: 'text' | 'h1' | 'h2' + length: number, + original_length?: number, + original_position: number, + position: number, + type: 'text' | 'h1' | 'h2' }; type ParseResult = { - text: string, - originalString: string, - conversions: ParseResultConversion[], + text: string, + originalString: string, + conversions: ParseResultConversion[], } // Returns the number of character skiped // This puts the i at the \n so it's skiped function parseComment(text: string, curPos: number): number { - for (let i = curPos + 1; i < text.length; i++) { - const char = text[i]; - if (char === '\n') { - return i - curPos; + for (let i = curPos + 1; i < text.length; i++) { + const char = text[i]; + if (char === '\n') { + return i - curPos; + } } - } - return text.length - curPos; + return text.length - curPos; } function createPartition(text: string, startPos: number, curPos: number, result: string, ignoreLast: number = 0): [ParseResultConversion[], string] | null { - curPos = curPos - ignoreLast; - if (startPos >= curPos || text.substring(startPos, curPos).match(/^\s*$/)) { - return null; - } + curPos = curPos - ignoreLast; + if (startPos >= curPos || text.substring(startPos, curPos + 1).match(/^\s*$/)) { + return null; + } - var t = text.substring(startPos, curPos); + var t = text.substring(startPos, curPos + 1); - if (t.indexOf('\n') == -1) { - return [[{ - length: curPos - startPos, - position: result.length, - original_position: startPos, - type: 'text', - }], t]; - } + if (!t.includes('\n')) { + return [[{ + length: curPos - startPos, + position: result.length, + original_position: startPos, + type: 'text', + }], t]; + } - const split = t.split('\n'); + const split = t.split('\n'); - let nt = ""; - const convs: ParseResultConversion[] = []; + let nt = ""; + const convs: ParseResultConversion[] = []; - let n = startPos; + let n = startPos; - let pos = result.length; + let pos = result.length; - for (const line of split) { - let nLine = line.replace(/^\s*/, ''); - n += line.length - nLine.length; - nt += nLine + '\n'; - convs.push({ - length: nLine.length, - original_position: n, - position: pos, - type: 'text' - }); - pos += nLine.length + 1; - n += nLine.length + 1; - } + for (const line of split) { + let nLine = line.replace(/^\s*/, ''); + n += line.length - nLine.length; + nt += nLine + '\n'; + convs.push({ + length: nLine.length, + original_position: n, + position: pos, + type: 'text' + }); + pos += nLine.length + 1; + n += nLine.length + 1; + } - return [convs, nt]; + return [convs, nt]; } function isChar(charCode: number): boolean { - return (charCode >= 92 && charCode <= 122) || (charCode >= 65 && charCode <= 90) || charCode == 42; + return (charCode >= 92 && charCode <= 122) || (charCode >= 65 && charCode <= 90) || charCode == 42; } function readBalanced(endChar: string, startChar: string, text: string, curPos: number): number { - let bal = 1; - for (let i = curPos; i < text.length; i++) { - const char = text[i]; - if (char == endChar) { - if (bal == 1) { - return i - curPos + 1; - } else { - bal -= 1; - } - } else if (char == startChar) { - bal += 1; + let bal = 1; + for (let i = curPos; i < text.length; i++) { + const char = text[i]; + if (char == endChar) { + if (bal == 1) { + return i - curPos + 1; + } else { + bal -= 1; + } + } else if (char == startChar) { + bal += 1; + } } - } - throw new Error("Can not find end of balance read") + throw new Error("Can not find end of balance read") } function isWhiteSpace(char: string): boolean { - return [' ', '\t', '\n'].includes(char); + return [' ', '\t', '\n'].includes(char); } function parseCommand(text: string, curPos: number, result: string): [number, ParseResultConversion, string] | [number] { - if (text.length - 1 == curPos) { - throw new Error("The latex file has the wrong format the file can not end with a empty command"); - } - - if (text[curPos + 1] === '\\') { - return [2, { - length: 1, - position: result.length, - original_position: curPos + 1, - type: 'text' - }, '\\']; - } else if (text[curPos + 1] === '%') { - return [2, { - length: 1, - position: result.length, - original_position: curPos + 1, - type: 'text' - }, '%']; - } else if (text[curPos + 1] === '_') { - return [2, { - length: 1, - position: result.length, - original_position: curPos + 1, - type: 'text' - }, '_']; - } - - let commandName = ""; - let commandNameFinished = false; - - // TODO store the location of the opts and args - let options = []; - let args = []; - - let findEnd = false; - - - let len = 0; - - for (let i = curPos + 1; i < text.length; i++) { - const char = text[i]; - if (isChar(char.charCodeAt(0))) { - if (!commandNameFinished) { - commandName += char; - } else { - len = i; - findEnd = true; - break; - } - } else if (char === '[') { - commandNameFinished = true; - const len = readBalanced(']', '[', text, i + 1); - options.push(text.substring(i + 1, i + len)) - i += len; - } else if (char === '{') { - commandNameFinished = true; - const len = readBalanced('}', '{', text, i + 1); - args.push(text.substring(i + 1, i + len)) - i += len; - } else if (isWhiteSpace(char)) { - len = i; - findEnd = true; - break; - } else { - - if (char == '.' || char == ',') { - if (commandNameFinished) { - len = i; - findEnd = true; - break; - } - } - - console.log(text.substring(i - 20, i + 20)); - console.log('Char:' + char.charCodeAt(0)); - throw new Error("TODO handle not char chars in the parse command function"); + if (text.length - 1 == curPos) { + throw new Error("The latex file has the wrong format the file can not end with a empty command"); } - } - if (!findEnd) { - throw new Error("Could not end of the command"); - } + if (text[curPos + 1] === '\\') { + return [2, { + length: 1, + position: result.length, + original_position: curPos + 1, + type: 'text' + }, '\\']; + } else if (text[curPos + 1] === '%') { + return [2, { + length: 1, + position: result.length, + original_position: curPos + 1, + type: 'text' + }, '%']; + } else if (text[curPos + 1] === '_') { + return [2, { + length: 1, + position: result.length, + original_position: curPos + 1, + type: 'text' + }, '_']; + } - //console.log("Parsed '" + text.substring(curPos, len) + "'") - //console.log("Ranged '" + text.substring(curPos - 5 , len + 5) + "'") + let commandName = ""; + let commandNameFinished = false; - len = len - curPos; + // TODO store the location of the opts and args + let options = []; + let args = []; - switch (commandName) { - case 'documentclass': - case 'usepackage': - case 'graphicspath': - case 'hypersetup': - case 'pagestyle': - case 'fancyhead': - case 'fancyfoot': - case 'renewcommand': - case 'setlength': - case 'addbibresource': - case 'date': - case 'maketitle': - case 'newpage': - case 'tableofcontents': - case 'includegraphics': - case 'appendix': - case 'printbibliography': - case 'subsection*': - case 'section*': - return [len]; - case 'title': - case 'author': - case 'end': - console.log("TODO: add way to check the " + commandName) - return [len]; + let findEnd = false; - case 'cite': - console.log("TODO check if it exists on the bibliography"); - return [len]; - case 'begin': + let len = 0; - switch (args[0]) { + for (let i = curPos + 1; i < text.length; i++) { + const char = text[i]; + if (isChar(char.charCodeAt(0))) { + if (!commandNameFinished) { + commandName += char; + } else { + len = i; + findEnd = true; + break; + } + } else if (char === '[') { + commandNameFinished = true; + const len = readBalanced(']', '[', text, i + 1); + options.push(text.substring(i + 1, i + len)) + i += len; + } else if (char === '{') { + commandNameFinished = true; + const len = readBalanced('}', '{', text, i + 1); + args.push(text.substring(i + 1, i + len)) + i += len; + } else if (isWhiteSpace(char)) { + len = i; + findEnd = true; + break; + } else { - case 'verbatim': + if (char == '.' || char == ',') { + if (commandNameFinished) { + len = i; + findEnd = true; + break; + } + } - const find = '\end{verbatim}'; + console.log(text.substring(i - 20, i + 20)); + console.log('Char:' + char.charCodeAt(0)); + throw new Error("TODO handle not char chars in the parse command function"); + } + } - let endPos = text.indexOf(find, curPos) + find.length; + if (!findEnd) { + throw new Error("Could not end of the command"); + } + + //console.log("Parsed '" + text.substring(curPos, len) + "'") + //console.log("Ranged '" + text.substring(curPos - 5 , len + 5) + "'") + + len = len - curPos; + + switch (commandName) { + case 'documentclass': + case 'usepackage': + case 'graphicspath': + case 'hypersetup': + case 'pagestyle': + case 'fancyhead': + case 'fancyfoot': + case 'renewcommand': + case 'setlength': + case 'addbibresource': + case 'date': + case 'maketitle': + case 'newpage': + case 'tableofcontents': + case 'includegraphics': + case 'appendix': + case 'printbibliography': + case 'vspace*': + case 'pagebreak': + case 'today': + case 'label': + return [len]; + + case 'title': + case 'author': + case 'end': + case 'ref': + case 'caption': + case 'footnote': + console.log("TODO: add way to check the " + commandName) + return [len]; + + case 'cite': + console.log("TODO check if it exists on the bibliography"); + console.log(`Find cite for '${args[0]}'`); + + let toAdd = "[0]" + + return [len, { + length: toAdd.length, + original_length: len, + original_position: curPos, + position: result.length, + type: 'text' + }, toAdd]; + + // return [len]; + + case 'begin': + + switch (args[0]) { + + case 'verbatim': + + const find = '\end{verbatim}'; + + let endPos = text.indexOf(find, curPos) + find.length; + + len = endPos - curPos; + break + default: + console.log("Do not know how to handle " + args[0]) + } + + + return [len]; + + case 'item': + + if (args[0]) { + return [len, { + length: 2 + args[0].length + 1, + original_length: len, + original_position: curPos + commandName.length, + position: result.length, + type: 'text' + }, "— " + args[0] + '\n']; + } + + return [len, { + length: 2, + original_length: len, + original_position: curPos, + position: result.length, + type: 'text' + }, "— "]; + + case 'section*': + case 'section': + return [len, { + length: args[0].length + 1, + original_length: len, + original_position: curPos + 2 + commandName.length, + position: result.length, + type: 'h1', + }, args[0] + '\n'] + + case 'subsection*': + case 'subsection': + return [len, { + length: args[0].length + 1, + original_length: len, + original_position: curPos + 2 + commandName.length, + position: result.length, + type: 'h2', + }, args[0] + '\n'] - len = endPos - curPos; - break default: - console.log("Do not know how to handle " + args[0]) - } - - - return [len]; - - case 'item': - - if (args[0]) { - return [len, { - length: 2 + args[0].length + 1, - original_length: len, - original_position: curPos + commandName.length, - position: result.length, - type: 'text' - }, "— " + args[0] + '\n']; - } - - return [len, { - length: 2, - original_length: len, - original_position: curPos, - position: result.length, - type: 'text' - }, "— "]; - - case 'section': - return [len, { - length: args[0].length + 1, - original_length: len, - original_position: curPos + 2 + commandName.length, - position: result.length, - type: 'h1', - }, args[0] + '\n'] - - case 'subsection': - return [len, { - length: args[0].length + 1, - original_length: len, - original_position: curPos + 2 + commandName.length, - position: result.length, - type: 'h2', - }, args[0] + '\n'] - - default: - console.log("Command name: " + commandName + " options: " + options + " args: " + args); - throw new Error("TODO handle this case"); - } + console.log("Command name: " + commandName + " options: " + options + " args: " + args); + throw new Error("TODO handle this case " + commandName); + } } function readUntil(text: string, char: string, curPos: number): number { - for (let i = curPos; i < text.length; i++) { - if (text[i] === char) { - return i - curPos; + for (let i = curPos; i < text.length; i++) { + if (text[i] === char) { + return i - curPos; + } } - } - throw new Error("Could not find matching pair"); + throw new Error("Could not find matching pair"); } export function parseLsp(text: string): ParseResult { - const result: ParseResult = { - text: '', - originalString: text, - conversions: [], - }; + const result: ParseResult = { + text: '', + originalString: text, + conversions: [], + }; - let conversionStartPosition = 0; + let conversionStartPosition = 0; - for (let i = 0; i < text.length; i++) { - let char = text[i]; + for (let i = 0; i < text.length; i++) { + let char = text[i]; - if (char === '%') { - //console.log("Found comment"); + if (char === '%') { + //console.log("Found comment"); - const possiblePartition = createPartition(text, conversionStartPosition, i - 1, result.text); + const possiblePartition = createPartition(text, conversionStartPosition, i - 1, result.text); - if (possiblePartition) { - const [conv, toAdd] = possiblePartition; - result.conversions = result.conversions.concat(conv) - result.text += toAdd; - } + if (possiblePartition) { + const [conv, toAdd] = possiblePartition; + result.conversions = result.conversions.concat(conv) + result.text += toAdd; + } - const len = parseComment(text, i); + const len = parseComment(text, i); - i += len; + i += len; - // Skip the begining \n - conversionStartPosition = i + 1; + // Skip the begining \n + conversionStartPosition = i + 1; - } else if (char === '\\') { - //console.log("Found command") + } else if (char === '\\') { + //console.log("Found command") - const possiblePartition = createPartition(text, conversionStartPosition, i - 1, result.text); + const possiblePartition = createPartition(text, conversionStartPosition, i - 1, result.text); - if (possiblePartition) { - const [conv, toAdd] = possiblePartition; - result.conversions = result.conversions.concat(conv); - result.text += toAdd; - } + console.log(possiblePartition) - const res = parseCommand(text, i, result.text); + if (possiblePartition) { + const [conv, toAdd] = possiblePartition; + result.conversions = result.conversions.concat(conv); + result.text += toAdd; + } - if (res.length === 1) { - const [len] = res; - i += len; - } else { - const [len, conv, toAdd] = res; + const res = parseCommand(text, i, result.text); - result.conversions.push(conv); - result.text += toAdd; - i += len; - } + if (res.length === 1) { + const [len] = res; + i += len; + } else { + const [len, conv, toAdd] = res; - conversionStartPosition = i + 1; - } else if (char === '$') { - console.log('Found math expr') - if (text[i + 1] === '$') { - throw new Error("Handle double math expression"); - } + result.conversions.push(conv); + result.text += toAdd; + i += len; + } - const possiblePartition = createPartition(text, conversionStartPosition, i, result.text); + conversionStartPosition = i + 1; + } else if (char === '$') { + console.log('Found math expr') + if (text[i + 1] === '$') { + throw new Error("Handle double math expression"); + } - if (possiblePartition) { - const [conv, toAdd] = possiblePartition; - result.conversions = result.conversions.concat(conv); - result.text += toAdd; - } + const possiblePartition = createPartition(text, conversionStartPosition, i - 1, result.text); - const len = readUntil(text, '$', i + 1); + if (possiblePartition) { + const [conv, toAdd] = possiblePartition; + result.conversions = result.conversions.concat(conv); + result.text += toAdd; + } - let to_add = 'mathexpr' + (text[i + len + 1 + 1] === ' ' ? ' ' : ''); - - result.conversions = result.conversions.concat( - [{ - length: to_add.length, - position: result.text.length, - original_position: i, - type: 'text', - }] - ); - result.text += to_add; + const len = readUntil(text, '$', i + 1); - i += len + 1; + let to_add = 'mathexpr' + (text[i + len + 1] === ' ' ? ' ' : ''); + + result.conversions = result.conversions.concat( + [{ + length: to_add.length, + position: result.text.length, + original_position: i, + type: 'text', + }] + ); + result.text += to_add; + + i += len + 1; + + conversionStartPosition = i + 1; + } else if (char == '`' || char == "'") { + console.log('Found coutes') + if (text[i + 1] !== char) { + continue; + } + + const possiblePartition = createPartition(text, conversionStartPosition, i - 1, result.text); + + if (possiblePartition) { + const [conv, toAdd] = possiblePartition; + result.conversions = result.conversions.concat(conv); + result.text += toAdd; + } + + let to_add = '"'; + + if (char == '`') { + to_add = "“" + } else if (char == "'") { + to_add = "”" + } + + result.conversions = result.conversions.concat( + [{ + length: to_add.length, + position: result.text.length, + original_position: i, + type: 'text', + }] + ); + result.text += to_add; + + i += 1; + + conversionStartPosition = i + 1; + } else { + //console.log(char); + } - conversionStartPosition = i + 1; - } else { - //console.log(char); } - } + result.text = result.text.replace(/``/g, "''"); - result.text = result.text.replace(/``/g, "''"); - - return result; + return result; } function getLineAndChar(lineIndex: number[], offset: number): [number, number] { - let l = 0; - let r = lineIndex.length; + let l = 0; + let r = lineIndex.length; - while (r >= l) { - const i = Math.floor((r + l) / 2); - //console.log(i, l ,r, offset, lineIndex[i]); + while (r >= l) { + const i = Math.floor((r + l) / 2); + //console.log(i, l ,r, offset, lineIndex[i]); - if (lineIndex[i + 1] < offset) { - l = i + 1; - continue; + if (lineIndex[i + 1] < offset) { + l = i + 1; + continue; + } + if (lineIndex[i] > offset) { + r = i - 1; + continue; + } + return [i, offset - lineIndex[i]]; } - if (lineIndex[i] > offset) { - r = i - 1; - continue; - } - return [i, offset - lineIndex[i]]; - } - return [-1, -1]; + return [-1, -1]; } function getOriginalPostion(res: ParseResult, offset: number): number { - let l = 0; - let r = res.conversions.length; + let l = 0; + let r = res.conversions.length; - while (r >= l) { - const i = Math.floor((r + l) / 2); - const conv = res.conversions[i]; + while (r >= l) { + const i = Math.floor((r + l) / 2); + const conv = res.conversions[i]; - if (conv.position > offset) { - r = i - 1; - continue; + if (conv.position > offset) { + r = i - 1; + continue; + } + + if (conv.position + conv.length < offset) { + l = i + 1; + continue; + } + + return conv.original_position + (offset - conv.position); } - if (conv.position + conv.length < offset) { - l = i + 1; - continue; - } - - return conv.original_position + (offset - conv.position); - } - - return -1; + return -1; } function buildLineIndex(file: string) { - const lines = file.split('\n'); - let i = 0; - const lineIndex = [0]; - for (const line of lines) { - i += line.length + 1; - lineIndex.push(i); - } - return lineIndex; + const lines = file.split('\n'); + let i = 0; + const lineIndex = [0]; + for (const line of lines) { + i += line.length + 1; + lineIndex.push(i); + } + return lineIndex; } type Match = { - message: string, - shortMessage: string, - offset: number, - length: number, - replacements: { - value: string - }[], - context: { - text: string, + message: string, + shortMessage: string, offset: number, - length: number - }, - sentence: string, - rule: { - id: string, - subId: string, - description: string, - urls: { - value: string + length: number, + replacements: { + value: string }[], - issueType: string, - category: { - id: string, - name: string + context: { + text: string, + offset: number, + length: number + }, + sentence: string, + rule: { + id: string, + subId: string, + description: string, + urls: { + value: string + }[], + issueType: string, + category: { + id: string, + name: string + } } - } } export async function diagnosticsRequests(res: ParseResult): Promise { - const formData = new URLSearchParams(); + const formData = new URLSearchParams(); - formData.set('text', res.text); - formData.set('language', 'en-GB'); - formData.set('username', process.env.USERNAME ?? ''); - formData.set('apiKey', process.env.APIKEY ?? ''); - formData.set('level', 'picky'); + formData.set('text', res.text); + formData.set('language', 'en-GB'); + formData.set('username', process.env.USERNAME_MY_LTEX ?? ''); + formData.set('apiKey', process.env.APIKEY_MY_LTEX ?? ''); + formData.set('level', 'picky'); - const rawRes = await fetch('https://api.languagetoolplus.com/v2/check', { - method: 'POST', - headers: { - 'Accept': 'application/json', - }, - body: formData, - }); + const rawRes = await fetch('https://api.languagetoolplus.com/v2/check', { + method: 'POST', + headers: { + 'Accept': 'application/json', + }, + body: formData, + }); - if (rawRes.status !== 200) { - console.log("Error:" + (await (await rawRes.blob()).text())) - process.exit(2); - } - const body = await rawRes.json(); + if (rawRes.status !== 200) { + console.log("Error:" + (await (await rawRes.blob()).text())) + process.exit(2); + } + const body = await rawRes.json(); - return body.matches; + return body.matches; } export type GetDiagnosticsReturn = (Dialog & { replacements: string[], rule_id: string, word?: string }); export async function getDiagnostics(file: string): Promise { - const res = parseLsp(file); + const res = parseLsp(file); - fs.writeFileSync('/tmp/latex-lsp-res', res.text) + fs.writeFileSync('/tmp/latex-lsp-res', res.text) - const matches = await diagnosticsRequests(res); + const matches = await diagnosticsRequests(res); - const lineIndex = buildLineIndex(file); + const lineIndex = buildLineIndex(file); - const diags = []; + const diags = []; - for (const i of matches) { - const match: Match = i; - const original_position = getOriginalPostion(res, match.offset); - if (original_position == -1) { - console.log("Could not find the original position") - continue; + for (const i of matches) { + const match: Match = i; + const original_position = getOriginalPostion(res, match.offset); + if (original_position == -1) { + console.log("Could not find the original position") + continue; + } + + let word: string | undefined = undefined; + + if (match.rule.id.startsWith("MORFOLOGIK_RULE")) { + word = file.substring(original_position, original_position + match.length); + } + + const [startLine, startChar] = getLineAndChar(lineIndex, original_position); + const [endLine, endChar] = getLineAndChar(lineIndex, original_position + match.length); + + const range = { + start: { line: startLine, character: startChar }, + end: { line: endLine, character: endChar }, + } + + diags.push({ + range, + severity: Severity.Error, + message: match.message, + replacements: match.replacements.map(a => a.value), + rule_id: match.rule.id, + word, + }) } - let word: string | undefined = undefined; - - if (match.rule.id.startsWith("MORFOLOGIK_RULE")) { - word = file.substring(original_position, original_position + match.length); - } - - const [startLine, startChar] = getLineAndChar(lineIndex, original_position); - const [endLine, endChar] = getLineAndChar(lineIndex, original_position + match.length); - - const range = { - start: { line: startLine, character: startChar }, - end: { line: endLine, character: endChar }, - } - - diags.push({ - range, - severity: Severity.Error, - message: match.message, - replacements: match.replacements.map(a => a.value), - rule_id: match.rule.id, - word, - }) - } - - return diags; + return diags; }