rokucommunity / brighterscript

A superset of Roku's BrightScript language
MIT License
151 stars 47 forks source link

distribute stand alone lsp #665

Closed ZeeD closed 1 year ago

ZeeD commented 1 year ago

Maybe I misunderstood, but I see that, while this project offer an implementation for lsp, this works only in vscode. I would prefer to continue to use my preferred IDE. My understanding is that other projects offers a stand alone executable that communicate back and forth with the client via stdin / stdout. Would it be possible to adapt the lsp implementation to run outside vscode?

ZeeD commented 1 year ago

I was "poking" at the project, and - inspired by https://github.com/rokucommunity/vscode-brightscript-language/blob/159fd098918d62a25591b4e55ea228c5ff40f0ab/src/LanguageServerRunner.ts#L15-L17 I tough I could have a dummy wrapper of https://github.com/rokucommunity/brighterscript/blob/1bfe31dae33f56518cf64e389847de2df8f4c56f/src/LanguageServer.ts , like

#!/usr/bin/env node

const { LanguageServer } = require('brighterscript');
const server = new LanguageServer();
server.run();

and run it with --stdio flag, but it seems that, while the server starts, and wait for input, if I try to "attach" a client the server terminate unexpectedly.

is this the "right" direction? it's possible to use the connection with --stdio or the LanguageServer have some assumptions (it seems to me that the vscode plugin relies on --node-ipc to communicate)?

TwitchBronBron commented 1 year ago

I haven't played with integrating the language server into any other IDEs, but the whole point of bundling the language server into brighterscript was for this exact purpose (to allow the brighterscript project to be THE BeightScript/BrighterScript language server for all other IDEs).

I've tried very hard to keep the language server built according to the spec and not depend on vscode. But obviously I've never tried it in another IDE to see if it actually works.

What IDE are you trying to integrate with?

ZeeD commented 1 year ago

my preferred IDE is eclipse, that support LSP, when I use Wild Web Developer, and I also tried kate, that has an LSP Client Plugin

is there a "message" that I can send to the language server to see if it works as expected? Or at least a way to have some "logs" to do some troubleshouting myself?

TwitchBronBron commented 1 year ago

To make this project work with vscode, I didn't really have to wire it up manually. I've never actually written code to interact directly with the language server, it's always just following the standard spec or the vscode language server apis on the vscode side. Here's how I wire up the language server and language client in vscode.

https://github.com/rokucommunity/vscode-brightscript-language/blob/159fd098918d62a25591b4e55ea228c5ff40f0ab/src/LanguageServerManager.ts#L122-L178

You communicate with the language server via JSON-RPC, but I think the EDITOR should really be responsible for doing that communication, not your code.

Looks like Eclipse has LSP support via Eclipse LSP4E, and there's a great tutorial on how to configure it here

ZeeD commented 1 year ago

Absolutely, you're right that the communication should be made from the IDE to the server. I was just trying to investigate. BTW: as you rightly say, WWD depends on LSP4E, that do the "low level" communication. I am able to connect a new standalone server (I followed the UI configuration as written on https://github.com/eclipse/lsp4e/blob/master/documentation/using-language-server-via-configuration-no-code.md) and I'm trying with the snippet I posted before. Unfortunately it seems there are some incompatibilities between the client and the server.

If this could help: I was able to capture the client "logs" with the communication details: it seems that the server asks the client for some "workspace/configuration" stuff and the client "blows up" (I'm looking at the lasts rows)

[t=1660741653658] LSP4E to brighterscript-language-server-bin:
Content-Length: 60

[t=1660741653658] LSP4E to brighterscript-language-server-bin:
{"jsonrpc":"2.0","id":"2","method":"shutdown","params":null}

[t=1660741653658] LSP4E to brighterscript-language-server-bin:
Content-Length: 60

[t=1660741653658] LSP4E to brighterscript-language-server-bin:
{"jsonrpc":"2.0","id":"3","method":"shutdown","params":null}

[t=1660741653659] LSP4E to brighterscript-language-server-bin:
Content-Length: 47

[t=1660741653659] LSP4E to brighterscript-language-server-bin:
{"jsonrpc":"2.0","method":"exit","params":null}

[t=1660741653659] LSP4E to brighterscript-language-server-bin:
Content-Length: 47

[t=1660741653659] LSP4E to brighterscript-language-server-bin:
{"jsonrpc":"2.0","method":"exit","params":null}

[t=1660741653667] LSP4E to brighterscript-language-server-bin:
Content-Length: 1580

[t=1660741653667] LSP4E to brighterscript-language-server-bin:
{"jsonrpc":"2.0","id":"1","method":"initialize","params":{"processId":3138,"rootPath":"/Users/a206719281/eclipse-workspace/ocellus-src/","rootUri":"file:///Users/a206719281/eclipse-workspace/ocellus-src/","capabilities":{"workspace":{"applyEdit":true,"workspaceEdit":{"documentChanges":true,"resourceOperations":["create","delete","rename"],"failureHandling":"undo"},"symbol":{"dynamicRegistration":true},"executeCommand":{"dynamicRegistration":true},"workspaceFolders":true},"textDocument":{"synchronization":{"willSave":true,"willSaveWaitUntil":true,"didSave":true},"completion":{"completionItem":{"snippetSupport":true,"documentationFormat":["markdown","plaintext"]}},"hover":{"contentFormat":["markdown","plaintext"]},"signatureHelp":{},"references":{},"documentHighlight":{},"documentSymbol":{"symbolKind":{"valueSet":[18,17,5,14,9,10,22,24,8,1,12,11,20,6,2,3,21,16,19,25,4,7,15,23,26,13]},"hierarchicalDocumentSymbolSupport":true},"formatting":{"dynamicRegistration":true},"rangeFormatting":{},"definition":{"linkSupport":true},"typeDefinition":{"linkSupport":true},"codeAction":{"codeActionLiteralSupport":{"codeActionKind":{"valueSet":["quickfix","refactor","refactor.extract","refactor.inline","refactor.rewrite","source","source.organizeImports"]}},"dataSupport":true,"resolveSupport":{"properties":["edit"]},"dynamicRegistration":true},"codeLens":{},"documentLink":{},"colorProvider":{},"rename":{},"foldingRange":{}}},"clientName":"Eclipse IDE","trace":"off","workspaceFolders":[{"uri":"file:///Users/a206719281/eclipse-workspace/ocellus-src/","name":"ocellus-src"}]}}

[t=1660741654105] brighterscript-language-server-bin to LSP4E:
{"jsonrpc":"2.0","id":"1","result":{"capabilities":{"textDocumentSync":1,"completionProvider":{"resolveProvider":true,"triggerCharacters":["."],"allCommitCharacters":[".","@"]},"documentSymbolProvider":true,"workspaceSymbolProvider":true,"semanticTokensProvider":{"legend":{"tokenTypes":["namespace","type","class","enum","interface","struct","typeParameter","parameter","variable","property","enumMember","event","function","method","macro","keyword","modifier","comment","string","number","regexp","operator"],"tokenModifiers":["declaration","definition","readonly","static","deprecated","abstract","async","modification","documentation","defaultLibrary"]},"full":true},"referencesProvider":true,"codeActionProvider":{"codeActionKinds":["refactor"]},"signatureHelpProvider":{"triggerCharacters":["(",","]},"definitionProvider":true,"hoverProvider":true,"executeCommandProvider":{"commands":["TranspileFile"]}}}}

[t=1660741654107] LSP4E to brighterscript-language-server-bin:
Content-Length: 52

[t=1660741654107] LSP4E to brighterscript-language-server-bin:
{"jsonrpc":"2.0","method":"initialized","params":{}}

[t=1660741654108] LSP4E to brighterscript-language-server-bin:
Content-Length: 744

[t=1660741654108] LSP4E to brighterscript-language-server-bin:
{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"file:///Users/a206719281/eclipse-workspace/ocellus-src/demo/roku-player/src/components/MainScene.bs","languageId":"bs","version":1,"text":"import \"pkg:/source/roku_modules/rodash/rodash.brs\"\n\nsub init()\n    foo \u003d rodash.add(3, 5)\n\n    videocontent \u003d createObject(\"RoSGNode\", \"ContentNode\")\n    videocontent.title \u003d `Example Video: [${foo}]`\n    videocontent.streamformat \u003d \"hls\"\n    videocontent.url \u003d \"https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8\"\n    video \u003d m.top.findNode(\"exampleVideo\")\n    video.content \u003d videocontent\n    video.setFocus(true)\n    video.control \u003d \"play\"\nend sub\n"}}}

[t=1660741654112] brighterscript-language-server-bin to LSP4E:
{"jsonrpc":"2.0","id":0,"method":"workspace/workspaceFolders"}

[t=1660741654113] LSP4E to brighterscript-language-server-bin:
Content-Length: 122

[t=1660741654113] LSP4E to brighterscript-language-server-bin:
{"jsonrpc":"2.0","id":0,"result":[{"uri":"file:///Users/a206719281/eclipse-workspace/ocellus-src/","name":"ocellus-src"}]}

[t=1660741654119] brighterscript-language-server-bin to LSP4E:
{"jsonrpc":"2.0","id":1,"method":"workspace/configuration","params":{"items":[{"scopeUri":"/Users/a206719281/eclipse-workspace/ocellus-src/","section":"files"}]}}

[t=1660741654120] LSP4E to brighterscript-language-server-bin:
Content-Length: 1915

[t=1660741654120] LSP4E to brighterscript-language-server-bin:
{"jsonrpc":"2.0","id":1,"error":{"code":-32603,"message":"Internal error.","data":"java.lang.RuntimeException: java.lang.reflect.InvocationTargetException\n\tat org.eclipse.lsp4j.jsonrpc.services.GenericEndpoint.lambda$null$0(GenericEndpoint.java:67)\n\tat org.eclipse.lsp4j.jsonrpc.services.GenericEndpoint.request(GenericEndpoint.java:120)\n\tat org.eclipse.lsp4j.jsonrpc.RemoteEndpoint.handleRequest(RemoteEndpoint.java:261)\n\tat org.eclipse.lsp4j.jsonrpc.RemoteEndpoint.consume(RemoteEndpoint.java:190)\n\tat org.eclipse.lsp4e.LanguageServerWrapper.lambda$3(LanguageServerWrapper.java:270)\n\tat org.eclipse.lsp4j.jsonrpc.json.StreamMessageProducer.handleMessage(StreamMessageProducer.java:194)\n\tat org.eclipse.lsp4j.jsonrpc.json.StreamMessageProducer.listen(StreamMessageProducer.java:94)\n\tat org.eclipse.lsp4j.jsonrpc.json.ConcurrentMessageProcessor.run(ConcurrentMessageProcessor.java:113)\n\tat java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539)\n\tat java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)\n\tat java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)\n\tat java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)\n\tat java.base/java.lang.Thread.run(Thread.java:833)\nCaused by: java.lang.reflect.InvocationTargetException\n\tat java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:119)\n\tat java.base/java.lang.reflect.Method.invoke(Method.java:577)\n\tat org.eclipse.lsp4j.jsonrpc.services.GenericEndpoint.lambda$null$0(GenericEndpoint.java:65)\n\t... 12 more\nCaused by: java.lang.UnsupportedOperationException\n\tat org.eclipse.lsp4j.services.LanguageClient.configuration(LanguageClient.java:138)\n\tat java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)\n\t... 14 more\n"}}

[t=1660741654893] LSP4E to brighterscript-language-server-bin:
Content-Length: 60

[t=1660741654893] LSP4E to brighterscript-language-server-bin:
{"jsonrpc":"2.0","id":"2","method":"shutdown","params":null}

[t=1660741654893] LSP4E to brighterscript-language-server-bin:
Content-Length: 60

[t=1660741654893] LSP4E to brighterscript-language-server-bin:
{"jsonrpc":"2.0","id":"3","method":"shutdown","params":null}

[t=1660741654894] LSP4E to brighterscript-language-server-bin:
Content-Length: 47

[t=1660741654894] LSP4E to brighterscript-language-server-bin:
{"jsonrpc":"2.0","method":"exit","params":null}

[t=1660741654895] LSP4E to brighterscript-language-server-bin:
Content-Length: 47

[t=1660741654895] LSP4E to brighterscript-language-server-bin:
{"jsonrpc":"2.0","method":"exit","params":null}

[t=1660741654904] LSP4E to brighterscript-language-server-bin:
Content-Length: 1580

[t=1660741654904] LSP4E to brighterscript-language-server-bin:
{"jsonrpc":"2.0","id":"1","method":"initialize","params":{"processId":3138,"rootPath":"/Users/a206719281/eclipse-workspace/ocellus-src/","rootUri":"file:///Users/a206719281/eclipse-workspace/ocellus-src/","capabilities":{"workspace":{"applyEdit":true,"workspaceEdit":{"documentChanges":true,"resourceOperations":["create","delete","rename"],"failureHandling":"undo"},"symbol":{"dynamicRegistration":true},"executeCommand":{"dynamicRegistration":true},"workspaceFolders":true},"textDocument":{"synchronization":{"willSave":true,"willSaveWaitUntil":true,"didSave":true},"completion":{"completionItem":{"snippetSupport":true,"documentationFormat":["markdown","plaintext"]}},"hover":{"contentFormat":["markdown","plaintext"]},"signatureHelp":{},"references":{},"documentHighlight":{},"documentSymbol":{"symbolKind":{"valueSet":[18,17,5,14,9,10,22,24,8,1,12,11,20,6,2,3,21,16,19,25,4,7,15,23,26,13]},"hierarchicalDocumentSymbolSupport":true},"formatting":{"dynamicRegistration":true},"rangeFormatting":{},"definition":{"linkSupport":true},"typeDefinition":{"linkSupport":true},"codeAction":{"codeActionLiteralSupport":{"codeActionKind":{"valueSet":["quickfix","refactor","refactor.extract","refactor.inline","refactor.rewrite","source","source.organizeImports"]}},"dataSupport":true,"resolveSupport":{"properties":["edit"]},"dynamicRegistration":true},"codeLens":{},"documentLink":{},"colorProvider":{},"rename":{},"foldingRange":{}}},"clientName":"Eclipse IDE","trace":"off","workspaceFolders":[{"uri":"file:///Users/a206719281/eclipse-workspace/ocellus-src/","name":"ocellus-src"}]}}

[t=1660741655321] brighterscript-language-server-bin to LSP4E:
{"jsonrpc":"2.0","id":"1","result":{"capabilities":{"textDocumentSync":1,"completionProvider":{"resolveProvider":true,"triggerCharacters":["."],"allCommitCharacters":[".","@"]},"documentSymbolProvider":true,"workspaceSymbolProvider":true,"semanticTokensProvider":{"legend":{"tokenTypes":["namespace","type","class","enum","interface","struct","typeParameter","parameter","variable","property","enumMember","event","function","method","macro","keyword","modifier","comment","string","number","regexp","operator"],"tokenModifiers":["declaration","definition","readonly","static","deprecated","abstract","async","modification","documentation","defaultLibrary"]},"full":true},"referencesProvider":true,"codeActionProvider":{"codeActionKinds":["refactor"]},"signatureHelpProvider":{"triggerCharacters":["(",","]},"definitionProvider":true,"hoverProvider":true,"executeCommandProvider":{"commands":["TranspileFile"]}}}}

[t=1660741655323] LSP4E to brighterscript-language-server-bin:
Content-Length: 52

[t=1660741655323] LSP4E to brighterscript-language-server-bin:
{"jsonrpc":"2.0","method":"initialized","params":{}}

[t=1660741655323] LSP4E to brighterscript-language-server-bin:
Content-Length: 744

[t=1660741655323] LSP4E to brighterscript-language-server-bin:
{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"file:///Users/a206719281/eclipse-workspace/ocellus-src/demo/roku-player/src/components/MainScene.bs","languageId":"bs","version":1,"text":"import \"pkg:/source/roku_modules/rodash/rodash.brs\"\n\nsub init()\n    foo \u003d rodash.add(3, 5)\n\n    videocontent \u003d createObject(\"RoSGNode\", \"ContentNode\")\n    videocontent.title \u003d `Example Video: [${foo}]`\n    videocontent.streamformat \u003d \"hls\"\n    videocontent.url \u003d \"https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8\"\n    video \u003d m.top.findNode(\"exampleVideo\")\n    video.content \u003d videocontent\n    video.setFocus(true)\n    video.control \u003d \"play\"\nend sub\n"}}}

[t=1660741655324] LSP4E to brighterscript-language-server-bin:
Content-Length: 337

[t=1660741655324] LSP4E to brighterscript-language-server-bin:
{"jsonrpc":"2.0","id":"2","method":"textDocument/hover","params":{"textDocument":{"uri":"file:///Users/a206719281/eclipse-workspace/ocellus-src/demo/roku-player/src/components/MainScene.bs"},"uri":"file:///Users/a206719281/eclipse-workspace/ocellus-src/demo/roku-player/src/components/MainScene.bs","position":{"line":0,"character":11}}}

[t=1660741655329] brighterscript-language-server-bin to LSP4E:
{"jsonrpc":"2.0","id":0,"method":"workspace/workspaceFolders"}

[t=1660741655329] LSP4E to brighterscript-language-server-bin:
Content-Length: 122

[t=1660741655329] LSP4E to brighterscript-language-server-bin:
{"jsonrpc":"2.0","id":0,"result":[{"uri":"file:///Users/a206719281/eclipse-workspace/ocellus-src/","name":"ocellus-src"}]}

[t=1660741655335] brighterscript-language-server-bin to LSP4E:
{"jsonrpc":"2.0","id":1,"method":"workspace/configuration","params":{"items":[{"scopeUri":"/Users/a206719281/eclipse-workspace/ocellus-src/","section":"files"}]}}

[t=1660741655336] LSP4E to brighterscript-language-server-bin:
Content-Length: 1915

[t=1660741655336] LSP4E to brighterscript-language-server-bin:
{"jsonrpc":"2.0","id":1,"error":{"code":-32603,"message":"Internal error.","data":"java.lang.RuntimeException: java.lang.reflect.InvocationTargetException\n\tat org.eclipse.lsp4j.jsonrpc.services.GenericEndpoint.lambda$null$0(GenericEndpoint.java:67)\n\tat org.eclipse.lsp4j.jsonrpc.services.GenericEndpoint.request(GenericEndpoint.java:120)\n\tat org.eclipse.lsp4j.jsonrpc.RemoteEndpoint.handleRequest(RemoteEndpoint.java:261)\n\tat org.eclipse.lsp4j.jsonrpc.RemoteEndpoint.consume(RemoteEndpoint.java:190)\n\tat org.eclipse.lsp4e.LanguageServerWrapper.lambda$3(LanguageServerWrapper.java:270)\n\tat org.eclipse.lsp4j.jsonrpc.json.StreamMessageProducer.handleMessage(StreamMessageProducer.java:194)\n\tat org.eclipse.lsp4j.jsonrpc.json.StreamMessageProducer.listen(StreamMessageProducer.java:94)\n\tat org.eclipse.lsp4j.jsonrpc.json.ConcurrentMessageProcessor.run(ConcurrentMessageProcessor.java:113)\n\tat java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539)\n\tat java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)\n\tat java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)\n\tat java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)\n\tat java.base/java.lang.Thread.run(Thread.java:833)\nCaused by: java.lang.reflect.InvocationTargetException\n\tat java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:119)\n\tat java.base/java.lang.reflect.Method.invoke(Method.java:577)\n\tat org.eclipse.lsp4j.jsonrpc.services.GenericEndpoint.lambda$null$0(GenericEndpoint.java:65)\n\t... 12 more\nCaused by: java.lang.UnsupportedOperationException\n\tat org.eclipse.lsp4j.services.LanguageClient.configuration(LanguageClient.java:138)\n\tat java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)\n\t... 14 more\n"}}

[t=1660741655409] LSP4E to brighterscript-language-server-bin:
Content-Length: 60

[t=1660741655409] LSP4E to brighterscript-language-server-bin:
{"jsonrpc":"2.0","id":"3","method":"shutdown","params":null}

[t=1660741655409] LSP4E to brighterscript-language-server-bin:
Content-Length: 60

[t=1660741655409] LSP4E to brighterscript-language-server-bin:
{"jsonrpc":"2.0","id":"4","method":"shutdown","params":null}

[t=1660741655410] LSP4E to brighterscript-language-server-bin:
Content-Length: 47

[t=1660741655410] LSP4E to brighterscript-language-server-bin:
{"jsonrpc":"2.0","method":"exit","params":null}

[t=1660741655410] LSP4E to brighterscript-language-server-bin:
Content-Length: 47

[t=1660741655410] LSP4E to brighterscript-language-server-bin:
{"jsonrpc":"2.0","method":"exit","params":null}

[t=1660741655421] LSP4E to brighterscript-language-server-bin:
Content-Length: 1580

[t=1660741655421] LSP4E to brighterscript-language-server-bin:
{"jsonrpc":"2.0","id":"1","method":"initialize","params":{"processId":3138,"rootPath":"/Users/a206719281/eclipse-workspace/ocellus-src/","rootUri":"file:///Users/a206719281/eclipse-workspace/ocellus-src/","capabilities":{"workspace":{"applyEdit":true,"workspaceEdit":{"documentChanges":true,"resourceOperations":["create","delete","rename"],"failureHandling":"undo"},"symbol":{"dynamicRegistration":true},"executeCommand":{"dynamicRegistration":true},"workspaceFolders":true},"textDocument":{"synchronization":{"willSave":true,"willSaveWaitUntil":true,"didSave":true},"completion":{"completionItem":{"snippetSupport":true,"documentationFormat":["markdown","plaintext"]}},"hover":{"contentFormat":["markdown","plaintext"]},"signatureHelp":{},"references":{},"documentHighlight":{},"documentSymbol":{"symbolKind":{"valueSet":[18,17,5,14,9,10,22,24,8,1,12,11,20,6,2,3,21,16,19,25,4,7,15,23,26,13]},"hierarchicalDocumentSymbolSupport":true},"formatting":{"dynamicRegistration":true},"rangeFormatting":{},"definition":{"linkSupport":true},"typeDefinition":{"linkSupport":true},"codeAction":{"codeActionLiteralSupport":{"codeActionKind":{"valueSet":["quickfix","refactor","refactor.extract","refactor.inline","refactor.rewrite","source","source.organizeImports"]}},"dataSupport":true,"resolveSupport":{"properties":["edit"]},"dynamicRegistration":true},"codeLens":{},"documentLink":{},"colorProvider":{},"rename":{},"foldingRange":{}}},"clientName":"Eclipse IDE","trace":"off","workspaceFolders":[{"uri":"file:///Users/a206719281/eclipse-workspace/ocellus-src/","name":"ocellus-src"}]}}

[t=1660741655916] brighterscript-language-server-bin to LSP4E:
{"jsonrpc":"2.0","id":"1","result":{"capabilities":{"textDocumentSync":1,"completionProvider":{"resolveProvider":true,"triggerCharacters":["."],"allCommitCharacters":[".","@"]},"documentSymbolProvider":true,"workspaceSymbolProvider":true,"semanticTokensProvider":{"legend":{"tokenTypes":["namespace","type","class","enum","interface","struct","typeParameter","parameter","variable","property","enumMember","event","function","method","macro","keyword","modifier","comment","string","number","regexp","operator"],"tokenModifiers":["declaration","definition","readonly","static","deprecated","abstract","async","modification","documentation","defaultLibrary"]},"full":true},"referencesProvider":true,"codeActionProvider":{"codeActionKinds":["refactor"]},"signatureHelpProvider":{"triggerCharacters":["(",","]},"definitionProvider":true,"hoverProvider":true,"executeCommandProvider":{"commands":["TranspileFile"]}}}}

[t=1660741655917] LSP4E to brighterscript-language-server-bin:
Content-Length: 52

[t=1660741655917] LSP4E to brighterscript-language-server-bin:
{"jsonrpc":"2.0","method":"initialized","params":{}}

[t=1660741655918] LSP4E to brighterscript-language-server-bin:
Content-Length: 744

[t=1660741655918] LSP4E to brighterscript-language-server-bin:
{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"file:///Users/a206719281/eclipse-workspace/ocellus-src/demo/roku-player/src/components/MainScene.bs","languageId":"bs","version":1,"text":"import \"pkg:/source/roku_modules/rodash/rodash.brs\"\n\nsub init()\n    foo \u003d rodash.add(3, 5)\n\n    videocontent \u003d createObject(\"RoSGNode\", \"ContentNode\")\n    videocontent.title \u003d `Example Video: [${foo}]`\n    videocontent.streamformat \u003d \"hls\"\n    videocontent.url \u003d \"https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8\"\n    video \u003d m.top.findNode(\"exampleVideo\")\n    video.content \u003d videocontent\n    video.setFocus(true)\n    video.control \u003d \"play\"\nend sub\n"}}}

[t=1660741655923] brighterscript-language-server-bin to LSP4E:
{"jsonrpc":"2.0","id":0,"method":"workspace/workspaceFolders"}

[t=1660741655923] LSP4E to brighterscript-language-server-bin:
Content-Length: 122

[t=1660741655923] LSP4E to brighterscript-language-server-bin:
{"jsonrpc":"2.0","id":0,"result":[{"uri":"file:///Users/a206719281/eclipse-workspace/ocellus-src/","name":"ocellus-src"}]}

[t=1660741655928] brighterscript-language-server-bin to LSP4E:
{"jsonrpc":"2.0","id":1,"method":"workspace/configuration","params":{"items":[{"scopeUri":"/Users/a206719281/eclipse-workspace/ocellus-src/","section":"files"}]}}

[t=1660741655930] LSP4E to brighterscript-language-server-bin:
Content-Length: 1915

[t=1660741655930] LSP4E to brighterscript-language-server-bin:
{"jsonrpc":"2.0","id":1,"error":{"code":-32603,"message":"Internal error.","data":"java.lang.RuntimeException: java.lang.reflect.InvocationTargetException\n\tat org.eclipse.lsp4j.jsonrpc.services.GenericEndpoint.lambda$null$0(GenericEndpoint.java:67)\n\tat org.eclipse.lsp4j.jsonrpc.services.GenericEndpoint.request(GenericEndpoint.java:120)\n\tat org.eclipse.lsp4j.jsonrpc.RemoteEndpoint.handleRequest(RemoteEndpoint.java:261)\n\tat org.eclipse.lsp4j.jsonrpc.RemoteEndpoint.consume(RemoteEndpoint.java:190)\n\tat org.eclipse.lsp4e.LanguageServerWrapper.lambda$3(LanguageServerWrapper.java:270)\n\tat org.eclipse.lsp4j.jsonrpc.json.StreamMessageProducer.handleMessage(StreamMessageProducer.java:194)\n\tat org.eclipse.lsp4j.jsonrpc.json.StreamMessageProducer.listen(StreamMessageProducer.java:94)\n\tat org.eclipse.lsp4j.jsonrpc.json.ConcurrentMessageProcessor.run(ConcurrentMessageProcessor.java:113)\n\tat java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539)\n\tat java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)\n\tat java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)\n\tat java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)\n\tat java.base/java.lang.Thread.run(Thread.java:833)\nCaused by: java.lang.reflect.InvocationTargetException\n\tat java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:119)\n\tat java.base/java.lang.reflect.Method.invoke(Method.java:577)\n\tat org.eclipse.lsp4j.jsonrpc.services.GenericEndpoint.lambda$null$0(GenericEndpoint.java:65)\n\t... 12 more\nCaused by: java.lang.UnsupportedOperationException\n\tat org.eclipse.lsp4j.services.LanguageClient.configuration(LanguageClient.java:138)\n\tat java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)\n\t... 14 more\n"}}
TwitchBronBron commented 1 year ago

Interesting. We're checking to see if the client "supports" configuration here.

A nice way to hack at this would be to manually edit the node_modules/brighterscript/dist/LanguageServer.js file. You can easily comment out certain code until you narrow down on what's causing the issue, then we can discuss how to fix it. For now, I'd suggest forcing that this.hasConfigurationCapability to false in onInitialize to see if that helps mitigate the current issue.

TwitchBronBron commented 1 year ago

Ok, so after thinking about this a little more, I might know what's wrong. I'm guessing eclipse DOES support the "workspace/configuration". However, I'm trying to read a vscode-specific configuration section called "files". I use this to help filter the files used in the language server based on what the user configured in their include/exclude filters from vscode. Here's the method that handles it: https://github.com/rokucommunity/brighterscript/blob/1bfe31dae33f56518cf64e389847de2df8f4c56f/src/LanguageServer.ts#L233

You could play around with that method to see if there's a runtime exception causing the problem.

ZeeD commented 1 year ago

uhm... I think there is a problem: following your advice I changed (the transpiled) .js file adding


        this.hasConfigurationCapability = !!(clientCapabilities.workspace && !!clientCapabilities.workspace.configuration);

        console.error('XXXX1', clientCapabilities.workspace);
        console.error('XXXX2', this.hasConfigurationCapability);
        this.hasConfigurationCapability = false;

just to check the value before the override. And unfortunately hasConfigurationCapability was already false:

XXXX1 {
  applyEdit: true,
  workspaceEdit: {
    documentChanges: true,
    resourceOperations: [ 'create', 'delete', 'rename' ],
    failureHandling: 'undo'
  },
  symbol: { dynamicRegistration: true },
  executeCommand: { dynamicRegistration: true },
  workspaceFolders: true
}
XXXX2 false
Content-Length: 913

{"jsonrpc":"2.0","id":"1","result":{"capabilities":{"textDocumentSync":1,"completionProvider":{"resolveProvider":true,"triggerCharacters":["."],"allCommitCharacters":[".","@"]},"documentSymbolProvider":true,"workspaceSymbolProvider":true,"semanticTokensProvider":{"legend":{"tokenTypes":["namespace","type","class","enum","interface","struct","typeParameter","parameter","variable","property","enumMember","event","function","method","macro","keyword","modifier","comment","string","number","regexp","operator"],"tokenModifiers":["declaration","definition","readonly","static","deprecated","abstract","async","modification","documentation","defaultLibrary"]},"full":true},"referencesProvider":true,"codeActionProvider":{"codeActionKinds":["refactor"]},"signatureHelpProvider":{"triggerCharacters":["(",","]},"definitionProvider":true,"hoverProvider":true,"executeCommandProvider":{"commands":["TranspileFile"]}}}}Content-Length: 62

{"jsonrpc":"2.0","id":0,"method":"workspace/workspaceFolders"}Content-Length: 162

{"jsonrpc":"2.0","id":1,"method":"workspace/configuration","params":{"items":[{"scopeUri":"/Users/a206719281/eclipse-workspace/ocellus-src/","section":"files"}]}}
...
TwitchBronBron commented 1 year ago

Ah. Ok, so then, we probably need to guard getWorkspaceExcludeGlobs with a check for this.hasConfigurationCapability. Perhaps something like this (typescript code):

let config = {
    exclude: {} as Record<string, boolean>
};
if (this.hasConfigurationCapability) {
    config = await this.connection.workspace.getConfiguration({
        scopeUri: workspaceFolder,
        section: 'files'
    });
}
ZeeD commented 1 year ago

I have changed the code with your suggestion, and now it seems it goes a bit further, but now I have other errors:

    async getWorkspaceExcludeGlobs(workspaceFolder) {
...
        let config = { exclude: {} };
        console.error('XXXX hasConfigurationCapability', this.hasConfigurationCapability);
        if (this.hasConfigurationCapability) {
            config = await this.connection.workspace.getConfiguration({
                scopeUri: workspaceFolder,
                section: 'files'
            });
        }
        console.error('XXXX config', config);

now I see in the logs

{"jsonrpc":"2.0","id":0,"method":"workspace/workspaceFolders"}
XXXX hasConfigurationCapability false
XXXX config { exclude: {} }
Content-Length: 192

{"jsonrpc":"2.0","id":1,"method":"workspace/configuration","params":{"items":[{"scopeUri":"file:///Users/a206719281/eclipse-workspace/ocellus-src/demo/roku-player","section":"brightscript"}]}}Content-Length: 195

{"jsonrpc":"2.0","id":2,"method":"workspace/configuration","params":{"items":[{"scopeUri":"file:///Users/a206719281/eclipse-workspace/ocellus-src/sdks/brighterscript","section":"brightscript"}]}}Content-Length: 204

{"jsonrpc":"2.0","id":3,"method":"workspace/configuration","params":{"items":[{"scopeUri":"file:///Users/a206719281/eclipse-workspace/ocellus-src/utils/protoc-gen-bs/test-buf","section":"brightscript"}]}}
node:internal/process/promises:279
            triggerUncaughtException(err, true /* fromPromise */);

where the 3 scopeUri paths are actually 3 projects I am working on! (I am in a monorepo)

so... now do you happen to know where the server ask for these configurations?

TwitchBronBron commented 1 year ago

Yep, I just found those and am working on a fix for them as well. It's the same issue, just in a different spot.

image

Here's how to fix that (typescript code):

private async getConfigFilePath(workspacePath: string) {
    let scopeUri: string;
    if (workspacePath.startsWith('file:')) {
        scopeUri = URI.parse(workspacePath).toString();
    } else {
        scopeUri = URI.file(workspacePath).toString();
    }
    let config = {
        configFile: undefined
    };
    //if the client supports configuration, look for config group called "brightscript"
    if (this.hasConfigurationCapability) {
        await this.connection.workspace.getConfiguration({
            scopeUri: scopeUri,
            section: 'brightscript'
        });
    }
    let configFilePath: string;
ZeeD commented 1 year ago
image

it works :) thank you!

TwitchBronBron commented 1 year ago

Great! I'm currently working on a PR that will resolve both of these issues. #667

ZeeD commented 1 year ago

FWIW it suspect it's an lsp4j bug, as Configuration Request has been added to LSP 3.6.0, and lsp4j support LSP 3.17.0 (I'm using lsp4j 0.14.0)

TwitchBronBron commented 1 year ago

I know this is a bit unrelated to the PR, but do you think you can add another binary that expose the language server as a standalone application? Or do you prefer to keep it outside the project?

In response to the question on #667.

So the language server is written in javascript and runs on NodeJS. Are you asking for A) a zip that includes a specific version of NodeJS executable and also the compiled javascript files? B) a way to run the lsp via the npm command line (like you currently do for npx bsc). We could have something like npx bsc --lsp to spin up a listening language server

ZeeD commented 1 year ago

I'm asking for B: it's not a problem to me to install "globally" an npm package, and I see that also other npm packages offers the same functionality, like typescript-language-server

TwitchBronBron commented 1 year ago

Ah, ok. Yes, I'm 100% open to adding B. Feel free to open a PR to add this functionality. I think I'd like to see it as a cli arg, like this:

npx bsc --lsp

And then you'd implement that inside of the src/cli.ts somewhere as a new action. But I'm open to discussion alternatives if you have any better ideas.

ZeeD commented 1 year ago

I'm trying with #668

ZeeD commented 1 year ago

as that with release 0.56.0 there is this new feature, I think this issue can be closed