LSP executeCommand and 'Method not found' alert - who's requesting who?!

In our Deno extension, there’s a certain code action which makes Nova throw up an error alert:

CleanShot 2022-05-23 at 15.32.32

The logs say the following:

Deno Language Server[15:32:40.040000] Sending JSON-RPC request: 82 workspace/executeCommand
{
  "jsonrpc" : "2.0",
  "id" : 82,
  "method" : "workspace\/executeCommand",
  "params" : {
    "command" : "deno.cache",
    "arguments" : [
      [
        "https:\/\/deno.land\/std\/bytes\/bytes_list.ts"
      ]
    ]
  }
}

Deno Language Server[15:32:40.040000] Got a workspace/executeCommand request, but it is not implemented

Deno Language Server[15:32:40.087000] Received JSON-RPC response: 82 workspace/executeCommand
{
  "error" : {
    "message" : "Method not found",
    "code" : -32601
  },
  "id" : 82,
  "jsonrpc" : "2.0"
}

Deno Language Server[15:32:40.087000] -32601 Method not found

The weird thing about this is that I think the Deno LSP is sending the deno.cache command to the client (Nova), and Nova is not set up to handle this (?)

From the Deno LSP docs:

There are several commands that might be issued by the language server to the client, which the client is expected to implement:

  • deno.cache - This is sent as a resolution code action when there is an un-cached module specifier that is being imported into a module. It will be sent with and argument that contains the resolved specifier as a string to be cached.

It’s weird, but I think all I want to do is issue back a deno/cache request using this information, but there’s no way for our extension to field this incoming command?

Or have I got this all wrong?

1 Like

Hi Sam,

You should be able to use the LanguageClient.onRequest() method to handle custom requests from the language server, documented here.

Let me know if you aren’t able to get this working as you’d expect.

Logan

The server —I think —sends a workspace/executeCommand request, which can not be handled by the extension. The documentation says:

Note: This should only be used for methods that are not part of the core Language Server Protocol specification. Attempting to register handlers for core methods will not invoke the provided callback.

Instead of adding special code to react to those requests, the Visual Studio Code Deno extension seemingly achieves the desired behavior by registering a deno.cache command. The command is called by VSCode when the associated workspace/executeCommand request is received. (Maybe? Sorry. I’m unsure.)

1 Like

I tried to make this work by registering a deno.cache command, but that was unsuccessful :frowning:.

Screenshots

Perhaps my assumptions are mistaken, or I’m doing something wrong.


Confusion about Deno which is maybe better suited to someplace else

The server —I think —sends a workspace/executeCommand request…

Nevermind. The LSP documentation says workspace/executeCommand is meant to be sent by the client —not by server. I have no idea of how the Deno Visual Studio Code extension works. I’m so sorry.


Nevermind the nevermind. I don’t understand this.

Deno Documentation:

Commands

There are several commands that might be issued by the language server to the client, which the client is expected to implement:

  • deno.cache - This is sent as a resolution code action when there is an un-cached module specifier that is being imported into a module. It will…

Thanks, I think our problem is that we’d like to handle a workspace/executeCommand request under one specific circumstance, which isn’t supported by Nova right now.

It’s a bit of an odd design to me, but the Deno LSP server sends a workspace/executeCommand to Nova instructing it to send a deno.cache command back to the LSP.

Because we can’t handle that request, we can’t get Nova to respond to this payload:

{
  "jsonrpc" : "2.0",
  "id" : 82,
  "method" : "workspace\/executeCommand",
  "params" : {
    "command" : "deno.cache",
    "arguments" : [
      [
        "https:\/\/deno.land\/std\/bytes\/bytes_list.ts"
      ]
    ]
  }
}

Fortunately this seems quite generic, and applicable to other LSPs. Could I lobby you to add support for Nova executing commands like this?

2 Likes

Note that what occurs in the Visual Studio Code extension is the invocation of a client-side deno.cache command, which itself sends a deno/cache request to the Language Server. The client-side command callback receives the contents of the arguments array as its arguments.

(Sorry to reiterate that; it’ll be terribly embarrassing if I’m mistaken. See my comment in this issue for details on how I came to that conclusion.)

1 Like

+1 for this feature from me

I’m not sure what happened, whether this was a change on Nova’s part, the Deno LSP, or both, but this code action now works without any intervention on my part.

1 Like

I wanted to follow up on this issue as I think the Deno LSP must’ve been changed to not require external commands to be registered with the LSP client.

I’ve been working on adding LSP support for Java using JDTLS and ran into a very similar issue with executing code actions. The error message is “-32601 No delegateCommandHandler for java.apply.workspaceEdit”.

This error message is sent from the LSP server (JDTLS) to the Nova LSP client in response to a “workspace/executeCommand” request from the Nova LSP client. Here is an example back-and-forth conversation between the Nova LSP client and the JDTLS server:

JDTLS --- Received JSON-RPC response: number(1) textDocument/codeAction
{
  "id" : 1,
  "result" : [
    {
      "title" : "Add Javadoc comment",
      "command" : "java.apply.workspaceEdit",
      "arguments" : [
        {
          "documentChanges" : [
            {
              "textDocument" : {
                "uri" : "file:\/\/\/Users\/branden.vennes\/code\/oss\/OpenLineage\/client\/java\/generator\/src\/main\/java\/io\/openlineage\/client\/Generator.java",
                "version" : null
              },
              "edits" : [
                {
                  "newText" : "\/**\n *\n *\/\n",
                  "range" : {
                    "end" : {
                      "character" : 2,
                      "line" : 39
                    },
                    "start" : {
                      "character" : 2,
                      "line" : 39
                    }
                  }
                }
              ]
            }
          ],
          "changes" : {
          }
        }
      ]
    }
  ]
}
JDTLS --- Sending JSON-RPC request: number(11) workspace/executeCommand
{
  "id" : 11,
  "params" : {
    "arguments" : [
      {
        "changes" : {

        },
        "documentChanges" : [
          {
            "textDocument" : {
              "version" : null,
              "uri" : "file:\/\/\/Users\/branden.vennes\/code\/oss\/OpenLineage\/client\/java\/generator\/src\/main\/java\/io\/openlineage\/client\/Generator.java"
            },
            "edits" : [
              {
                "newText" : "\/**\n *\n *\/\n",
                "range" : {
                  "start" : {
                    "character" : 2,
                    "line" : 39
                  },
                  "end" : {
                    "character" : 2,
                    "line" : 39
                  }
                }
              }
            ]
          }
        ]
      }
    ],
    "command" : "java.apply.workspaceEdit"
  },
  "method" : "workspace\/executeCommand",
  "jsonrpc" : "2.0"
}
JDTLS --- Received JSON-RPC response: number(11) workspace/executeCommand
{
  "jsonrpc" : "2.0",
  "id" : 11,
  "error" : {
    "message" : "No delegateCommandHandler for java.apply.workspaceEdit",
    "code" : -32601
  }
}

I looked into why JDTLS would respond with this error and discovered that other LSP clients (VS Code and Neovim) have support for defining custom command handlers which the LSP server can execute directly. See nvim-jdtls/lua/jdtls.lua at ad5ab1c9246caa9e2c69a7c13d2be9901b5c02aa · mfussenegger/nvim-jdtls · GitHub and vscode-java/src/extension.ts at 9b0f0aca80cbefabad4c034fb5dd365d029f6170 · redhat-developer/vscode-java · GitHub.

In the case of VS Code, these commands are standard command-palette commands you’d register in your extension. For Neovim there is a vim.lsp.commands variable which can be used to register custom LSP commands: Lsp - Neovim docs.

Nova could have similar functionality where registering a command in Nova java.apply.workspaceEdit also allows the command to be used by the LSP server. In the case of the original issue here, the deno.cache command could be registered with Nova as a standard Command and be used by the Deno LSP server.