1

LSP servers may send suggestions for fixing the code, things like "Add missing import <foo>", "Sort the list", etc. They can be "applied" by executing (lsp-execute-code-action).

When (lsp-execute-code-action) is invoked interactively it either asks which action to apply or applies if there's just one.

For example, given this C code with clangd server, putting caret over puts and executing M-x lsp-execute-code-action would add #include <stdio.h> line.

int main() {puts("hello");} 

But how do I invoke (lsp-execute-code-action) programmatically and pass it the action to execute? For example, I might want to bind a key to certain action I frequently use, which would require wrapping (lsp-execute-code-action) with some explicit argument.

The current function documentation is unhelpful, and the code uses a lot of DSL, so I couldn't figure out that offhand.

1 Answer 1

1

If you know what kind of action your action is going to be -- and it seems to be the case -- you can pass it to lsp-execute-code-action-by-kind, for example:

(lsp-execute-code-action-by-kind "refactor.inline.call") 

If you want more insight in how the actions look like from the lsp-mode point of view, you can eval (lsp-code-actions-at-point) which returns a list of actions. Each of those may be passed to lsp-execute-code-action as an arg.

For example, I use this for inlining:

(bind-key "C-c p r k" (lambda () (interactive) (lsp-execute-code-action-by-kind "refactor.inline.call"))) 

UPD: If you'd like to be more flexible in using the actions programmatically, you can do something like this (if you have deserialization to plists enabled as per https://emacs-lsp.github.io/lsp-mode/page/performance/#use-plists-for-deserialization):

(defun my/find-action-by-title (actions-list title) (car (seq-filter (lambda (action) (string= title (plist-get action :title))) actions-list))) (defun my/lsp-run-apply-all-suggestions () (interactive) (let ((actions (lsp-code-actions-at-point))) (if-let ((apply-all-action (my/find-action-by-title actions "Apply all suggestions"))) (lsp-execute-code-action apply-all-action) (error "No apply all suggestions action found!")))) 

UPD2: If lsp-mode uses hashtables for deserialization (default), as @Hi-Angel pointed out below,

(plist-get action :title) 

should read

(gethash "title" action) 

instead.

8
  • Thanks, I confirm this works! So e.g. with purescript lsp server to remove unused imports executing (lsp-execute-code-action-by-kind "source.organizeImports") works. Worth noting that (lsp-code-actions-at-point) returns a poorly readable hashtable with (in my case) lots of different actions — one way to make sense off of it might be to search for literal dot, i.e. .. That's because the only places where dot seem to appear are the kinds (which you're interested in) and sometimes in filenames. Commented Jun 10 at 18:36
  • 1
    Hmm, you seem to be right, (type-of (lsp-code-actions-at-point)) says cons. However, my confusion wasn't without a reason and your update requires a small tweak to work: the (plist-get action :title) has to be (gethash "title" action). For reference, here's the content of lsp-code-actions-at-point: 1st line is whole content and 2nd line is "Apply all suggestions" action. Perhaps, are you using older lsp-mode? I tested that with latest lsp-mode-20250610.1238. Btw, if-let is deprecated in favor of if-let* since Emacs 31 Commented Jun 11 at 5:21
  • 1
    Ah, I know what's the difference! I totally forgot I followed emacs-lsp.github.io/lsp-mode/page/performance/… and turned this on. You haven't, so your lsp-mode indeed uses hashtables. I'm sorry for the confusion. I'll add this bit to the answer. And thanks for pointing out if-let is deprecated; I can find mentions of deprecations all the way back from 26... Commented Jun 11 at 9:34
  • 1
    An interesting link! I would never have expected plist to be faster than hash-tables. I'd expect plist access time O(n) as opposed to O(1) in hash table. Presumably plists are too implemented via something like hash table…? Either way, an odd but interesting discovery, might look at potentially using it in color-identifiers-mode I maintain… Commented Jun 11 at 9:41
  • 1
    Speculation: AFAIK, plist is just a regular list layout. I think plists here are beneficial in terms of simpler operation (although I don't know the elisp hashtable implementation details), I mean at least you don't have to compute the hash of the key. So the constant multiplier is lower for plist than hashtable. And these plists are small anyways, so probably even O(n) access time is fast enough. Commented Jun 11 at 10:43

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.