Skip to content

Commit 4cdc64a

Browse files
committed
2 parents dc7a8a7 + f20f8e3 commit 4cdc64a

File tree

2 files changed

+156
-124
lines changed

2 files changed

+156
-124
lines changed

server/src/server.ts

Lines changed: 114 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,9 @@ import * as chokidar from "chokidar";
1919
import { assert } from "console";
2020
import { fileURLToPath } from "url";
2121
import { ChildProcess } from "child_process";
22-
import { WorkspaceEdit } from "vscode-languageserver";
22+
import { WorkspaceEdit } from "vscode-languageserver";
2323
import { TextEdit } from "vscode-languageserver-types";
24+
import { OnReadOpts } from "node:net";
2425

2526
// https://microsoft.github.io/language-server-protocol/specification#initialize
2627
// According to the spec, there could be requests before the 'initialize' request. Link in comment tells how to handle them.
@@ -243,6 +244,111 @@ if (process.argv.includes("--stdio")) {
243244
send = (msg: m.Message) => process.send!(msg);
244245
process.on("message", onMessage);
245246
}
247+
248+
function hover(msg: p.RequestMessage) {
249+
let params = msg.params as p.HoverParams;
250+
let filePath = fileURLToPath(params.textDocument.uri);
251+
let response = utils.runAnalysisCommand(
252+
filePath,
253+
["hover", filePath, params.position.line, params.position.character],
254+
msg
255+
);
256+
return response;
257+
}
258+
259+
function definition(msg: p.RequestMessage) {
260+
// https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_definition
261+
let params = msg.params as p.DefinitionParams;
262+
let filePath = fileURLToPath(params.textDocument.uri);
263+
let response = utils.runAnalysisCommand(
264+
filePath,
265+
["definition", filePath, params.position.line, params.position.character],
266+
msg
267+
);
268+
return response;
269+
}
270+
271+
function references(msg: p.RequestMessage) {
272+
// https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_references
273+
let params = msg.params as p.ReferenceParams;
274+
let filePath = fileURLToPath(params.textDocument.uri);
275+
let result: typeof p.ReferencesRequest.type = utils.getReferencesForPosition(
276+
filePath,
277+
params.position
278+
);
279+
let response: m.ResponseMessage = {
280+
jsonrpc: c.jsonrpcVersion,
281+
id: msg.id,
282+
result,
283+
// error: code and message set in case an exception happens during the definition request.
284+
};
285+
return response;
286+
}
287+
288+
function rename(msg: p.RequestMessage) {
289+
// https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_rename
290+
let params = msg.params as p.RenameParams;
291+
let filePath = fileURLToPath(params.textDocument.uri);
292+
let locations: p.Location[] | null = utils.getReferencesForPosition(
293+
filePath,
294+
params.position
295+
);
296+
let result: WorkspaceEdit | null;
297+
if (locations === null) {
298+
result = null;
299+
} else {
300+
let changes: { [uri: string]: TextEdit[] } = {};
301+
locations.forEach(({ uri, range }) => {
302+
let textEdit: TextEdit = { range, newText: params.newName };
303+
if (uri in changes) {
304+
changes[uri].push(textEdit);
305+
} else {
306+
changes[uri] = [textEdit];
307+
}
308+
});
309+
result = { changes };
310+
}
311+
let response: m.ResponseMessage = {
312+
jsonrpc: c.jsonrpcVersion,
313+
id: msg.id,
314+
result,
315+
};
316+
return response;
317+
}
318+
319+
function documentSymbol(msg: p.RequestMessage) {
320+
// https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_documentSymbol
321+
let params = msg.params as p.DocumentSymbolParams;
322+
let filePath = fileURLToPath(params.textDocument.uri);
323+
let response = utils.runAnalysisCommand(
324+
filePath,
325+
["documentSymbol", filePath],
326+
msg
327+
);
328+
return response;
329+
}
330+
331+
function completion(msg: p.RequestMessage) {
332+
let params = msg.params as p.ReferenceParams;
333+
let filePath = fileURLToPath(params.textDocument.uri);
334+
let code = getOpenedFileContent(params.textDocument.uri);
335+
let tmpname = utils.createFileInTempDir();
336+
fs.writeFileSync(tmpname, code, { encoding: "utf-8" });
337+
let response = utils.runAnalysisCommand(
338+
filePath,
339+
[
340+
"completion",
341+
filePath,
342+
params.position.line,
343+
params.position.character,
344+
tmpname,
345+
],
346+
msg
347+
);
348+
fs.unlink(tmpname, () => null);
349+
return response;
350+
}
351+
246352
function onMessage(msg: m.Message) {
247353
if (m.isNotificationMessage(msg)) {
248354
// notification message, aka the client ends it and doesn't want a reply
@@ -353,118 +459,17 @@ function onMessage(msg: m.Message) {
353459
send(response);
354460
}
355461
} else if (msg.method === p.HoverRequest.method) {
356-
let params = msg.params as p.HoverParams;
357-
let filePath = fileURLToPath(params.textDocument.uri);
358-
let result: typeof p.HoverRequest.type = utils.runAnalysisAfterSanityCheck(
359-
filePath,
360-
["hover", filePath, params.position.line, params.position.character]
361-
);
362-
let hoverResponse: m.ResponseMessage = {
363-
jsonrpc: c.jsonrpcVersion,
364-
id: msg.id,
365-
// type result = Hover | null
366-
// type Hover = {contents: MarkedString | MarkedString[] | MarkupContent, range?: Range}
367-
result,
368-
};
369-
send(hoverResponse);
462+
send(hover(msg));
370463
} else if (msg.method === p.DefinitionRequest.method) {
371-
// https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_definition
372-
let params = msg.params as p.DefinitionParams;
373-
let filePath = fileURLToPath(params.textDocument.uri);
374-
let result: typeof p.DefinitionRequest.type = utils.runAnalysisAfterSanityCheck(
375-
filePath,
376-
[
377-
"definition",
378-
filePath,
379-
params.position.line,
380-
params.position.character,
381-
]
382-
);
383-
let definitionResponse: m.ResponseMessage = {
384-
jsonrpc: c.jsonrpcVersion,
385-
id: msg.id,
386-
result,
387-
// error: code and message set in case an exception happens during the definition request.
388-
};
389-
send(definitionResponse);
390-
} else if (msg.method === p.RenameRequest.method) {
391-
// https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_rename
392-
let params = msg.params as p.RenameParams;
393-
let filePath = fileURLToPath(params.textDocument.uri);
394-
let locations: p.Location[] | null = utils.getReferencesForPosition(filePath, params.position);
395-
let result: WorkspaceEdit | null;
396-
if (locations === null) {
397-
result = null;
398-
} else {
399-
let changes: { [uri: string]: TextEdit[] } = {};
400-
locations.forEach(({ uri, range }) => {
401-
let textEdit: TextEdit = {range, newText: params.newName};
402-
if (uri in changes) {
403-
changes[uri].push(textEdit);
404-
} else {
405-
changes[uri] = [textEdit]
406-
}
407-
});
408-
409-
result = {changes};
410-
}
411-
412-
let renameResponse: m.ResponseMessage = {
413-
jsonrpc: c.jsonrpcVersion,
414-
id: msg.id,
415-
result,
416-
};
417-
418-
send(renameResponse);
464+
send(definition(msg));
419465
} else if (msg.method === p.ReferencesRequest.method) {
420-
// https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_references
421-
let params = msg.params as p.ReferenceParams;
422-
let filePath = fileURLToPath(params.textDocument.uri);
423-
let result: typeof p.ReferencesRequest.type = utils.getReferencesForPosition(filePath, params.position);
424-
let definitionResponse: m.ResponseMessage = {
425-
jsonrpc: c.jsonrpcVersion,
426-
id: msg.id,
427-
result,
428-
// error: code and message set in case an exception happens during the definition request.
429-
};
430-
send(definitionResponse);
466+
send(references(msg));
467+
} else if (msg.method === p.RenameRequest.method) {
468+
send(rename(msg));
431469
} else if (msg.method === p.DocumentSymbolRequest.method) {
432-
// https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_documentSymbol
433-
let params = msg.params as p.DocumentSymbolParams;
434-
let filePath = fileURLToPath(params.textDocument.uri);
435-
let result: typeof p.DocumentSymbolRequest.type = utils.runAnalysisAfterSanityCheck(
436-
filePath,
437-
["documentSymbol", filePath]
438-
);
439-
let definitionResponse: m.ResponseMessage = {
440-
jsonrpc: c.jsonrpcVersion,
441-
id: msg.id,
442-
result,
443-
};
444-
send(definitionResponse);
470+
send(documentSymbol(msg));
445471
} else if (msg.method === p.CompletionRequest.method) {
446-
let params = msg.params as p.ReferenceParams;
447-
let filePath = fileURLToPath(params.textDocument.uri);
448-
let code = getOpenedFileContent(params.textDocument.uri);
449-
let tmpname = utils.createFileInTempDir();
450-
fs.writeFileSync(tmpname, code, { encoding: "utf-8" });
451-
let result: typeof p.CompletionRequest.type = utils.runAnalysisAfterSanityCheck(
452-
filePath,
453-
[
454-
"completion",
455-
filePath,
456-
params.position.line,
457-
params.position.character,
458-
tmpname,
459-
]
460-
);
461-
fs.unlink(tmpname, () => null);
462-
let completionResponse: m.ResponseMessage = {
463-
jsonrpc: c.jsonrpcVersion,
464-
id: msg.id,
465-
result,
466-
};
467-
send(completionResponse);
472+
send(completion(msg));
468473
} else if (msg.method === p.DocumentFormattingRequest.method) {
469474
// technically, a formatting failure should reply with the error. Sadly
470475
// the LSP alert box for these error replies sucks (e.g. doesn't actually

server/src/utils.ts

Lines changed: 42 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@ import * as childProcess from "child_process";
33
import * as p from "vscode-languageserver-protocol";
44
import * as path from "path";
55
import * as t from "vscode-languageserver-types";
6+
import {
7+
RequestMessage,
8+
ResponseMessage,
9+
} from "vscode-languageserver-protocol";
610
import fs from "fs";
711
import * as os from "os";
812

@@ -82,13 +86,13 @@ export let findNodeBuildOfProjectRoot = (
8286

8387
type execResult =
8488
| {
85-
kind: "success";
86-
result: string;
87-
}
89+
kind: "success";
90+
result: string;
91+
}
8892
| {
89-
kind: "error";
90-
error: string;
91-
};
93+
kind: "error";
94+
error: string;
95+
};
9296
export let formatUsingValidBscNativePath = (
9397
code: string,
9498
bscNativePath: p.DocumentUri,
@@ -144,12 +148,34 @@ export let runAnalysisAfterSanityCheck = (
144148
return JSON.parse(stdout.toString());
145149
};
146150

147-
export let getReferencesForPosition = (filePath: p.DocumentUri, position: p.Position) =>
148-
runAnalysisAfterSanityCheck(filePath, ['references', filePath, position.line, position.character]);
151+
export let runAnalysisCommand = (
152+
filePath: p.DocumentUri,
153+
args: Array<any>,
154+
msg: RequestMessage
155+
) => {
156+
let result = runAnalysisAfterSanityCheck(filePath, args);
157+
let response: ResponseMessage = {
158+
jsonrpc: c.jsonrpcVersion,
159+
id: msg.id,
160+
result,
161+
};
162+
return response;
163+
};
164+
165+
export let getReferencesForPosition = (
166+
filePath: p.DocumentUri,
167+
position: p.Position
168+
) =>
169+
runAnalysisAfterSanityCheck(filePath, [
170+
"references",
171+
filePath,
172+
position.line,
173+
position.character,
174+
]);
149175

150176
export let replaceFileExtension = (filePath: string, ext: string): string => {
151177
let name = path.basename(filePath, path.extname(filePath));
152-
return path.format({ dir: path.dirname(filePath), name, ext })
178+
return path.format({ dir: path.dirname(filePath), name, ext });
153179
};
154180

155181
export let createInterfaceFileUsingValidBscExePath = (
@@ -158,13 +184,14 @@ export let createInterfaceFileUsingValidBscExePath = (
158184
bscExePath: p.DocumentUri
159185
): execResult => {
160186
try {
161-
let resiString = childProcess.execFileSync(
162-
bscExePath,
163-
["-color", "never", cmiPath]
164-
);
187+
let resiString = childProcess.execFileSync(bscExePath, [
188+
"-color",
189+
"never",
190+
cmiPath,
191+
]);
165192

166-
let resiPath = replaceFileExtension(filePath, c.resiExt)
167-
fs.writeFileSync(resiPath, resiString, { encoding: "utf-8"});
193+
let resiPath = replaceFileExtension(filePath, c.resiExt);
194+
fs.writeFileSync(resiPath, resiString, { encoding: "utf-8" });
168195

169196
return {
170197
kind: "success",

0 commit comments

Comments
 (0)