Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to ExecuteCommand for servers which provides custom commands #563

Open
itsraian opened this issue Oct 9, 2024 · 5 comments
Open

How to ExecuteCommand for servers which provides custom commands #563

itsraian opened this issue Oct 9, 2024 · 5 comments

Comments

@itsraian
Copy link

itsraian commented Oct 9, 2024

TSServer implements custom commands which can be used to trigger some actions.
https://github.com/typescript-language-server/typescript-language-server?tab=readme-ov-file#workspace-commands-workspaceexecutecommand

Is there a way in the client to call those custom actions?
Maybe a :LspExecuteCommand _typescript.organizeImports?

@Konfekt
Copy link
Contributor

Konfekt commented Oct 10, 2024

The whole setup could be more filetype specific, see also #562

As a new user, the list of :Lsp... commands felt long, and often redundant. Aftplugin/&ft.vim suggesting sensible default mappings could foster adaption.

@itsraian
Copy link
Author

I suggested a new command for it, but not sure if we really need it. I mean, LSP sends the available custom commands through the executeCommandProvider capability.

We could have those commands appended to the Code Actions (since they work pretty similar)?

btw, I used tsserver as example, but figured out that ruff server used for python formatting also has some custom commands.

@Konfekt
Copy link
Contributor

Konfekt commented Oct 14, 2024

I am new to this plug-in. What was missing in :help lsp-custom-commands then to implement something similar to g:LspRegisterCmdHandler('java.apply.workspaceEdit', WorkspaceEdit) for tsserver or ruff server?

doc/lsp.txt (lines 1750-1773)
14. Custom Command Handlers			*lsp-custom-commands*

When applying a code action, the language server may issue a non-standard
command.  For example, the Java language server uses non-standard commands
(e.g. java.apply.workspaceEdit).  To handle these commands, you can register a
callback function for each command using the LspRegisterCmdHandler() function.
For example: >

    vim9script
    import autoload "lsp/textedit.vim"

    def WorkspaceEdit(cmd: dict<any>)
      for editAct in cmd.arguments
	  textedit.ApplyWorkspaceEdit(editAct)
      endfor
    enddef
    g:LspRegisterCmdHandler('java.apply.workspaceEdit', WorkspaceEdit)
<
Place the above code in a file named lsp_java/plugin/lsp_java.vim and load
this plugin.

The callback function should accept a Dict argument.  The Dict argument
contains the LSP Command interface fields.  Refer to the LSP specification for
more information about the "Command" interface.

@itsraian
Copy link
Author

itsraian commented Oct 14, 2024

I don't believe it has the behavior I need. RegisterCmdHandler listen to commands that comes from the server and do actions as needed. The example you shared (from the doc) wait for a java.apply.workspaceEdit from the server and calls textedit.Apply.. to current buffer. Its a communication Server => Client.

What I need is a way to call a command from the client. Calling a source.removeUnused.ts from the client, by example, would ask to the server remove all unused variables, which would generate a response and the client would apply as usual.

@Konfekt
Copy link
Contributor

Konfekt commented Oct 14, 2024

Okay, so this is for receiving from the server instead of sending. I wonder how :help LspCodeAction solves this as it can only be applied to a diagnostic in the current line:

#  doc/lsp.txt (lines 704-718)
:LspCodeAction [query]	Apply the code action supplied by the language server
			to the diagnostic in the current line. This works only
			if there is a diagnostic message for the current line.
			You can use the ":LspDiag current" command to display
			the diagnostic for the current line.

			When [query] is given the code action starting with
			[query] will be applied. [query] can be a regexp
			pattern, or a digit corresponding to the index of the
			code actions in the created prompt.

			When [query] is not given you will be prompted to
			select one of the actions supplied by the language
			server.

But in principle

#  autoload/lsp/codeaction.vim (lines 15-26)
export def DoCommand(lspserver: dict<any>, cmd: dict<any>)
  if cmd->has_key('command') && CommandHandlers->has_key(cmd.command)
    var CmdHandler: func = CommandHandlers[cmd.command]
    try
      call CmdHandler(cmd)
    catch
      util.ErrMsg($'"{cmd.command}" handler raised exception {v:exception}')
    endtry
  else
    lspserver.executeCommand(cmd)
  endif
enddef

could be used, which at the moment is only used in CodeAction/Lens. Maybe that's what you meant with

I suggested a new command for it, but not sure if we really need it. I mean, LSP sends the available custom commands through the executeCommandProvider capability.
We could have those commands appended to the Code Actions (since they work pretty similar)?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants