Skip to content

Commit

Permalink
fix: corrections larger than the misspelling
Browse files Browse the repository at this point in the history
would overwrite adjacent text. Now they will be correctly inserted.
  • Loading branch information
tekumara committed Apr 25, 2023
1 parent 1f993a6 commit 27f53ef
Show file tree
Hide file tree
Showing 8 changed files with 134 additions and 27 deletions.
7 changes: 2 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,6 @@ jobs:
- run: cargo build
- run: npm ci
- run: npm run lint
# vscode requires an X Server
- name: npm test
run: |
mkdir -p bundled
cp target/debug/typos-lsp bundled/
# vscode requires an X Server
xvfb-run npm test
run: xvfb-run npm test
73 changes: 63 additions & 10 deletions crates/typos-lsp/src/lsp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,13 +127,7 @@ impl LanguageServer for Backend<'static> {
changes: Some(HashMap::from([(
params.text_document.uri.clone(),
vec![TextEdit {
range: Range::new(
diag.range.start,
Position::new(
diag.range.start.line,
diag.range.start.character + c.len() as u32,
),
),
range: diag.range,
new_text: c.to_string(),
}],
)])),
Expand Down Expand Up @@ -321,7 +315,7 @@ mod tests {
"uri": "file:///diagnostics.txt",
"languageId": "plaintext",
"version": 1,
"text": "this is a\ntest fo typos\n"
"text": "this is an apropriate test\nfo typos\n"
}
}
}
Expand Down Expand Up @@ -374,6 +368,53 @@ mod tests {
}
"#;

let code_action_insertion = r#"
{
"jsonrpc": "2.0",
"method": "textDocument/codeAction",
"params": {
"textDocument": {
"uri": "file:///diagnostics.txt"
},
"range": {
"start": {
"line": 0,
"character": 11
},
"end": {
"line": 0,
"character": 21
}
},
"context": {
"diagnostics": [
{
"range": {
"start": {
"line": 0,
"character": 11
},
"end": {
"line": 0,
"character": 21
}
},
"message": "`apropriate` should be `appropriate`",
"data": {
"corrections": ["appropriate"]
},
"severity": 2,
"source": "typos"
}
],
"only": ["quickfix"],
"triggerKind": 1
}
},
"id": 3
}
"#;

let (mut req_client, mut resp_client) = start_server();
let mut buf = vec![0; 1024];

Expand All @@ -392,7 +433,7 @@ mod tests {

similar_asserts::assert_eq!(
body(&buf[..n]).unwrap(),
r#"{"jsonrpc":"2.0","method":"textDocument/publishDiagnostics","params":{"diagnostics":[{"data":{"corrections":["of","for"]},"message":"`fo` should be `of`, `for`","range":{"end":{"character":7,"line":1},"start":{"character":5,"line":1}},"severity":2,"source":"typos"}],"uri":"file:///diagnostics.txt","version":1}}"#,
r#"{"jsonrpc":"2.0","method":"textDocument/publishDiagnostics","params":{"diagnostics":[{"data":{"corrections":["appropriate"]},"message":"`apropriate` should be `appropriate`","range":{"end":{"character":21,"line":0},"start":{"character":11,"line":0}},"severity":2,"source":"typos"},{"data":{"corrections":["of","for"]},"message":"`fo` should be `of`, `for`","range":{"end":{"character":2,"line":1},"start":{"character":0,"line":1}},"severity":2,"source":"typos"}],"uri":"file:///diagnostics.txt","version":1}}"#,
);

tracing::debug!("{}", code_action);
Expand All @@ -404,7 +445,19 @@ mod tests {

similar_asserts::assert_eq!(
body(&buf[..n]).unwrap(),
r#"{"jsonrpc":"2.0","result":[{"diagnostics":[{"data":{"corrections":["of","for"]},"message":"`fo` should be `of`, `for`","range":{"end":{"character":7,"line":1},"start":{"character":5,"line":1}},"severity":2,"source":"typos"}],"edit":{"changes":{"file:///diagnostics.txt":[{"newText":"of","range":{"end":{"character":7,"line":1},"start":{"character":5,"line":1}}}]}},"kind":"quickfix","title":"of"},{"diagnostics":[{"data":{"corrections":["of","for"]},"message":"`fo` should be `of`, `for`","range":{"end":{"character":7,"line":1},"start":{"character":5,"line":1}},"severity":2,"source":"typos"}],"edit":{"changes":{"file:///diagnostics.txt":[{"newText":"for","range":{"end":{"character":8,"line":1},"start":{"character":5,"line":1}}}]}},"kind":"quickfix","title":"for"}],"id":2}"#,
r#"{"jsonrpc":"2.0","result":[{"diagnostics":[{"data":{"corrections":["of","for"]},"message":"`fo` should be `of`, `for`","range":{"end":{"character":7,"line":1},"start":{"character":5,"line":1}},"severity":2,"source":"typos"}],"edit":{"changes":{"file:///diagnostics.txt":[{"newText":"of","range":{"end":{"character":7,"line":1},"start":{"character":5,"line":1}}}]}},"kind":"quickfix","title":"of"},{"diagnostics":[{"data":{"corrections":["of","for"]},"message":"`fo` should be `of`, `for`","range":{"end":{"character":7,"line":1},"start":{"character":5,"line":1}},"severity":2,"source":"typos"}],"edit":{"changes":{"file:///diagnostics.txt":[{"newText":"for","range":{"end":{"character":7,"line":1},"start":{"character":5,"line":1}}}]}},"kind":"quickfix","title":"for"}],"id":2}"#,
);

tracing::debug!("{}", code_action_insertion);
req_client
.write_all(req(code_action_insertion).as_bytes())
.await
.unwrap();
let n = resp_client.read(&mut buf).await.unwrap();

similar_asserts::assert_eq!(
body(&buf[..n]).unwrap(),
r#"{"jsonrpc":"2.0","result":[{"diagnostics":[{"data":{"corrections":["appropriate"]},"message":"`apropriate` should be `appropriate`","range":{"end":{"character":21,"line":0},"start":{"character":11,"line":0}},"severity":2,"source":"typos"}],"edit":{"changes":{"file:///diagnostics.txt":[{"newText":"appropriate","range":{"end":{"character":21,"line":0},"start":{"character":11,"line":0}}}]}},"isPreferred":true,"kind":"quickfix","title":"appropriate"}],"id":3}"#,
);
}

Expand Down
28 changes: 28 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@
"lint": "prettier --check . && eslint src --ext ts",
"fix": "prettier --write . && eslint src --ext ts --fix",
"pretest": "tsc && npm run build",
"test": "node ./out/test/runTest.js"
"test": "cross-env TYPOS_LSP_PATH=$PWD/target/debug/typos-lsp node ./out/test/runTest.js"
},
"devDependencies": {
"@types/glob": "^8.1.0",
Expand All @@ -96,6 +96,7 @@
"@typescript-eslint/parser": "^5.53.0",
"@vscode/test-electron": "^2.2.3",
"@vscode/vsce": "^2.19.0",
"cross-env": "^7.0.3",
"esbuild": "^0.17.18",
"eslint": "^8.34.0",
"glob": "^8.1.0",
Expand Down
4 changes: 2 additions & 2 deletions src/test/fixture/diagnostics.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
this is an apropriate
test fo typos
this is an apropriate test
fo typos
8 changes: 7 additions & 1 deletion src/test/runTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,14 @@ async function main() {
// Passed to --extensionTestsPath
const extensionTestsPath = path.resolve(__dirname, "./suite/index");

const launchArgs = ["--disable-extensions"];

// Download VS Code, unzip it and run the integration test
await runTests({ extensionDevelopmentPath, extensionTestsPath });
await runTests({
extensionDevelopmentPath,
extensionTestsPath,
launchArgs,
});
} catch (err) {
console.error("Failed to run tests", err);
process.exit(1);
Expand Down
6 changes: 3 additions & 3 deletions src/test/suite/helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,18 @@ export let editor: vscode.TextEditor;
*/
export async function activate(docUri: vscode.Uri) {
const ext = vscode.extensions.getExtension("tekumara.typos-vscode")!;
// TODO: configure path

await ext.activate();
try {
doc = await vscode.workspace.openTextDocument(docUri);
editor = await vscode.window.showTextDocument(doc);
await sleep(2000); // Wait for server activation
await sleep(100); // Wait for server activation
} catch (e) {
console.error(e);
}
}

async function sleep(ms: number) {
export async function sleep(ms: number) {
return new Promise((resolve) => setTimeout(resolve, ms));
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import * as vscode from "vscode";
import * as assert from "assert";
import { getDocUri, activate } from "./helper";
import { activate, getDocUri, sleep } from "./helper";

suite("Should get diagnostics", () => {
suite("VS Code Integration Tests", async () => {
const docUri = getDocUri("diagnostics.txt");

suiteSetup(async () => {
await activate(docUri);
});

test("Diagnoses typo", async () => {
await testDiagnostics(docUri, [
{
Expand All @@ -15,12 +19,32 @@ suite("Should get diagnostics", () => {
},
{
message: "`fo` should be `of`, `for`",
range: toRange(1, 5, 1, 7),
range: toRange(1, 0, 1, 2),
severity: vscode.DiagnosticSeverity.Warning,
source: "ex",
},
]);
});

test("Auto fix applies corrections", async () => {
let editor = vscode.window.activeTextEditor;

if (!editor) {
throw new Error("no active editor");
}

// place cursor on the spelling mistake
let position = new vscode.Position(0, 13);
let selection = new vscode.Selection(position, position);
editor.selection = selection;

// trigger correction
await vscode.commands.executeCommand("editor.action.autoFix");
await sleep(100);

let contents = vscode.window.activeTextEditor?.document.getText();
assert.equal(contents, "this is an appropriate test\nfo typos\n");
});
});

function toRange(sLine: number, sChar: number, eLine: number, eChar: number) {
Expand All @@ -33,8 +57,6 @@ async function testDiagnostics(
docUri: vscode.Uri,
expectedDiagnostics: vscode.Diagnostic[]
) {
await activate(docUri);

const actualDiagnostics = vscode.languages.getDiagnostics(docUri);
assert.equal(actualDiagnostics.length, expectedDiagnostics.length);

Expand Down

0 comments on commit 27f53ef

Please sign in to comment.