@@ -19,8 +19,9 @@ import * as chokidar from "chokidar";
1919import { assert } from "console" ;
2020import { fileURLToPath } from "url" ;
2121import { ChildProcess } from "child_process" ;
22- import { WorkspaceEdit } from "vscode-languageserver" ;
22+ import { WorkspaceEdit } from "vscode-languageserver" ;
2323import { 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+
246352function 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
0 commit comments