Open noklam opened 4 months ago
The 2-step process is just a quirk from the fact the playground tries to make it possible to call a command from any server, without knowing up front what those commands are called.
Assuming that your command does not require any arguments, you should be able to replace the value of command
in
https://github.com/openlawlibrary/pygls/blob/a40a3c3ad18943503e29cbd61586545974d4dbc8/.vscode/extensions/pygls-playground/package.json#L29-L32
with the id of your custom command (the string you pass to @server.command()
). It should then be possible to call your command directly from the VSCode command palette.
However, if your command does take arguments or you need to process the return value in any way then I don't think you can avoid writing some TS! 😅
Coming back to this after one month! I haven't tried this yet. We are working on a visual component and currently exploring if it's possible to add interaction between a webview and the LSP.
I have been thinking there is two possible ways:
Send request directly through the language client, but I cannot find any API that I can use.
There are generic sendRequest
and sendNotification
methods on the VSCode language client.
I use them to send a few custom messages to esbonio
, but I imagine they would work fine for standard LSP messages also
add interaction between a webview and the LSP
It's also possible to setup a web socket connection with a pygls powered server
Yes, it's more complicated than routing the message via VSCode's Webview API, but it does open the door to the webview working with editors other than VSCode.
There are generic sendRequest and sendNotification methods on the VSCode language client.
Thanks for giving some pointer. I tried to implement this today and using the lsClient
in Typescript directly to sendRequest
. It seems like the the server is communicating properly but VSCode UI does not respond to it at all.
The request looks like this in the client (it's hard coded now as I just want to test if this mechanism works)
lsClient?.sendRequest("textDocument/definition",
{
"textDocument": {
"uri": "file:///Users/Nok_Lam_Chan/dev/kedro/tmp/spaceflights/src/spaceflights/pipelines/data_science/pipeline.py"
},
"position": {
"line": 11,
"character": 29
}
}
);
I register this function in a command so I can invoke it with the UI.
export async function sendDefinitionRequest(lsClient: LanguageClient | undefined) {
lsClient?.sendRequest("textDocument/definition",
...
After that, the server respond with the correct response but the cursor didn't move.
2024-08-13 14:35:54.996 [info] [Trace - 14:35:54] Received response 'textDocument/definition - (47)' in 22ms. 2024-08-13 14:35:54.996 [info] Result: [ { "uri": "file:///Users/Nok_Lam_Chan/dev/kedro/tmp/spaceflights/conf/base/catalog.yml", "range": { "start": { "line": 43, "character": 0 }, "end": { "line": 44, "character": 0 } } } ]
Do I need to handle the response from the client side or is that something VSCode take care of automatically?
The command is mainly for testing, it mimics when I do cmd+click
on a string. I manage to reproduce the navigation function, but I wonder is this necessary. Since in the case of using pygls
, I only need to declare @LSP_SERVER.feature(TEXT_DOCUMENT_DEFINITION)
and the UI know how to respond to the server.
For now I am using the vscode.window
api on the client side.
Do I need to handle the response from the client side or is that something VSCode take care of automatically?
Yes, you would need to handle the response as using sendRequest
is going to bypass the "internal wiring" setup by VSCode's language client. Here for example is how the client usually handles TEXT_DOCUMENT_DEFINITION
.
To be honest... I don't know what the "right" way to call TEXT_DOCUMENT_DEFINITION
programmatically so that the result is automatically handled. Since the example above is implementing an API that allows VSCode to decide when TEXT_DOCUMENT_DEFINITION
should be called.
The command is mainly for testing,
Maybe I'm reading too much into your example, but from the gif it looks like you might want to implement the workspace/symbol
request?
@alcarney Adding symbol would be interesting but I don't think it's suitable in this case. The idea in mind is to embedded this into webview and triggering the Go to Definition from the graph. So the command is temporary for testing just because it is handy to trigger it manually. It won't be needed once we integrate it properly.
bypass the "internal wiring" setup by VSCode's language client.
This is the logic that I was looking for, but at the end I implemented a simple one just to get started. It roughly looks like this.
if (result && result.length > 0) {
const location = result[0];
const uri: vscode.Uri = vscode.Uri.parse(location.uri);
const range = location.range;
vscode.window.showTextDocument(uri,
{
selection: range,
viewColumn: vscode.ViewColumn.One,
}
);
Maybe I'm reading too much into your example, but from the gif it looks like you might want to implement the https://github.com/openlawlibrary/pygls/pull/470 request?
Since you mentioned symbol, is there any example that I can look into. Right now the LSP do the analysis on the demand, I think I will need to build these symbols with cache.
Since you mentioned symbol, is there any example that I can look into. Right now the LSP do the analysis on the demand, I think I will need to build these symbols with cache.
There is the example symbols.py
server which maintains an internal index of all the known symbols.
Other than that you could go through some of the servers in Implementations.md and see if/how they handle it
We actually implemented a custom command that that a word
as an argument. But seems like we could just use vscode.executeDefinitionProvider
, since our own LSP is already registered as a definition provider, it's not necessary to call the LSP directly. Our LSP is build around a Python DSL with YAML.
vscode.commands.executeCommand<vscode.Location[]>(
'vscode.executeDefinitionProvider',
document.uri,
position,
);
This is what it looks like now.
I found this section in the docs: https://pygls.readthedocs.io/en/v0.10.2/pages/advanced_usage.html#commands The entrypoint is registered in the playground: https://github.com/openlawlibrary/pygls/blob/a40a3c3ad18943503e29cbd61586545974d4dbc8/.vscode/extensions/pygls-playground/package.json#L29-L32
While this works fine, it involves two steps to execute a command:
Is there a way to combine these into 1 step? The alternative is using the VSCode API directly https://code.visualstudio.com/api/extension-guides/command, but it has some downside:
It seems like this is possible by modifying https://github.com/openlawlibrary/pygls/blob/a40a3c3ad18943503e29cbd61586545974d4dbc8/.vscode/extensions/pygls-playground/src/extension.ts#L244-L248, is there any tradeoff implementing this on the server side instead of client?