Skip to content

Commit 450dc34

Browse files
committed
Add support for autocompletion command.
1 parent a27a625 commit 450dc34

File tree

2 files changed

+80
-11
lines changed

2 files changed

+80
-11
lines changed

server/src/dumpCommand.ts

Lines changed: 60 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,29 +3,44 @@ import { RequestMessage } from "vscode-languageserver";
33
import * as utils from "./utils";
44
import * as path from "path";
55
import { exec } from "child_process";
6+
import * as tmp from "tmp";
7+
import fs from "fs";
8+
9+
let findExecutable = (uri: string) => {
10+
let filePath = fileURLToPath(uri);
11+
let projectRootPath = utils.findProjectRootOfFile(filePath);
12+
if (projectRootPath == null) {
13+
return null;
14+
} else {
15+
// Currently assumes the dump command is "bin.exe" at the project root.
16+
let binaryPath = path.join(projectRootPath, "bin.exe");
17+
if (fs.existsSync(binaryPath)) {
18+
return { binaryPath, filePath, cwd: projectRootPath };
19+
} else {
20+
return null;
21+
}
22+
}
23+
};
624

725
export function runDumpCommand(
8-
msg: RequestMessage,
26+
msg: RequestMessage,
927
onResult: (
1028
result: { hover?: string; definition?: { uri?: string; range: any } } | null
1129
) => void
1230
) {
13-
let filePath = fileURLToPath(msg.params.textDocument.uri);
14-
let projectRootPath = utils.findProjectRootOfFile(filePath);
15-
if (projectRootPath == null) {
31+
let executable = findExecutable(msg.params.textDocument.uri);
32+
if (executable == null) {
1633
onResult(null);
1734
} else {
18-
// Currently assumes the dump command is "bin.exe" at the project root.
19-
let commandPath = path.join(projectRootPath, "bin.exe");
2035
let command =
21-
commandPath +
36+
executable.binaryPath +
2237
" dump " +
23-
filePath +
38+
executable.filePath +
2439
":" +
2540
msg.params.position.line +
2641
":" +
2742
msg.params.position.character;
28-
exec(command, { cwd: projectRootPath }, function (_error, _stdout, stderr) {
43+
exec(command, { cwd: executable.cwd }, function (_error, _stdout, stderr) {
2944
let result = JSON.parse(stderr);
3045
if (result && result[0]) {
3146
onResult(result[0]);
@@ -35,3 +50,39 @@ export function runDumpCommand(
3550
});
3651
}
3752
}
53+
54+
export function runCompletionCommand(
55+
msg: RequestMessage,
56+
code: string,
57+
onResult: (result: [{ label: string }] | null) => void
58+
) {
59+
let executable = findExecutable(msg.params.textDocument.uri);
60+
if (executable == null) {
61+
onResult(null);
62+
} else {
63+
let tmpobj = tmp.fileSync();
64+
let tmpname = tmpobj.name;
65+
fs.writeFileSync(tmpname, code, { encoding: "utf-8" });
66+
67+
let command =
68+
executable.binaryPath +
69+
" complete " +
70+
executable.filePath +
71+
":" +
72+
msg.params.position.line +
73+
":" +
74+
msg.params.position.character +
75+
" " +
76+
tmpname;
77+
78+
exec(command, { cwd: executable.cwd }, function (_error, _stdout, stderr) {
79+
tmpobj.removeCallback();
80+
let result = JSON.parse(stderr);
81+
if (result && result[0]) {
82+
onResult(result);
83+
} else {
84+
onResult(null);
85+
}
86+
});
87+
}
88+
}

server/src/server.ts

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,7 @@ import * as chokidar from "chokidar";
2020
import { assert } from "console";
2121
import { fileURLToPath } from "url";
2222
import { ChildProcess } from "child_process";
23-
import { runDumpCommand } from "./dumpCommand";
24-
23+
import { runDumpCommand, runCompletionCommand } from "./dumpCommand";
2524

2625
// https://microsoft.github.io/language-server-protocol/specification#initialize
2726
// According to the spec, there could be requests before the 'initialize' request. Link in comment tells how to handle them.
@@ -272,6 +271,7 @@ process.on("message", (msg: m.Message) => {
272271
documentFormattingProvider: true,
273272
hoverProvider: true,
274273
definitionProvider: true,
274+
completionProvider: { triggerCharacters: ["."] },
275275
},
276276
};
277277
let response: m.ResponseMessage = {
@@ -359,6 +359,24 @@ process.on("message", (msg: m.Message) => {
359359
process.send!(emptyDefinitionResponse);
360360
}
361361
});
362+
} else if (msg.method === p.CompletionRequest.method) {
363+
let emptyCompletionResponse: m.ResponseMessage = {
364+
jsonrpc: c.jsonrpcVersion,
365+
id: msg.id,
366+
result: null,
367+
};
368+
let code = getOpenedFileContent(msg.params.textDocument.uri);
369+
runCompletionCommand(msg, code, (result) => {
370+
if (result) {
371+
let definitionResponse: m.ResponseMessage = {
372+
...emptyCompletionResponse,
373+
result: result,
374+
};
375+
process.send!(definitionResponse);
376+
} else {
377+
process.send!(emptyCompletionResponse);
378+
}
379+
});
362380
} else if (msg.method === p.DocumentFormattingRequest.method) {
363381
// technically, a formatting failure should reply with the error. Sadly
364382
// the LSP alert box for these error replies sucks (e.g. doesn't actually

0 commit comments

Comments
 (0)