Skip to content

Commit a1b4c75

Browse files
authored
Add a new action-filer client parameter (#4194)
This lets us fix #4184 by selectively changing `nil` code action argument values to `:json-false`. Once this is merged, HLS needs to set the field to `'(:withSig)` (and possibly some other values).
1 parent 171d5a6 commit a1b4c75

File tree

2 files changed

+51
-1
lines changed

2 files changed

+51
-1
lines changed

CHANGELOG.org

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
* Add SQL support
55
* Add support for Meson build system. (~meson-mode~).
66
* Add support for go to definition for external files (.dll) in CSharp projects for OmniSharp server.
7+
* Added a new optional ~:action-filter~ argument when defining LSP clients that allows code action requests to be modified before they are sent to the server. This is used by the Haskell language server client to work around an ~lsp-mode~ parsing quirk that incorrectly sends ~null~ values instead of ~false~ in code action requests.
78

89
** 9.0.0
910
* Add language server config for QML (Qt Modeling Language) using qmlls.

lsp-mode.el

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1625,6 +1625,13 @@ return value of `body' or nil if interrupted."
16251625
;; to the server.
16261626
(action-handlers (make-hash-table :test 'equal))
16271627

1628+
;; `action-filter' can be set to a function that modifies any incoming
1629+
;; `CodeAction' in place before it is executed. The return value is ignored.
1630+
;; This can be used to patch up broken code action requests before they are
1631+
;; sent back to the LSP server. See `lsp-fix-code-action-booleans' for an
1632+
;; example of a function that can be useful here.
1633+
(action-filter nil)
1634+
16281635
;; major modes supported by the client.
16291636
major-modes
16301637
;; Function that will be called to decide if this language client
@@ -6005,7 +6012,49 @@ Request codeAction/resolve for more info if server supports."
60056012

60066013
(cond
60076014
((stringp command?) (lsp--execute-command action))
6008-
((lsp-command? command?) (lsp--execute-command command?))))
6015+
((lsp-command? command?) (progn
6016+
(when-let ((action-filter (->> (lsp-workspaces)
6017+
(cl-first)
6018+
(or lsp--cur-workspace)
6019+
(lsp--workspace-client)
6020+
(lsp--client-action-filter))))
6021+
(funcall action-filter command?))
6022+
(lsp--execute-command command?)))))
6023+
6024+
(lsp-defun lsp-fix-code-action-booleans ((&Command :arguments?) boolean-action-arguments)
6025+
"Patch incorrect boolean argument values in the provided `CodeAction' command
6026+
in place, based on the BOOLEAN-ACTION-ARGUMENTS list. The values
6027+
in this list can be either symbols or lists of symbols that
6028+
represent paths to boolean arguments in code actions:
6029+
6030+
> (lsp-fix-code-action-booleans command '(:foo :bar (:some :nested :boolean)))
6031+
6032+
When there are available code actions, the server sends
6033+
`lsp-mode' a list of possible command names and arguments as
6034+
JSON. `lsp-mode' parses all boolean false values as `nil'. As a
6035+
result code action arguments containing falsy values don't
6036+
roundtrip correctly because `lsp-mode' will end up sending null
6037+
values back to the client. This list makes it possible to
6038+
selectively transform `nil' values back into `:json-false'."
6039+
(seq-doseq (path boolean-action-arguments)
6040+
(seq-doseq (args arguments?)
6041+
(lsp--fix-nested-boolean args (if (listp path) path (list path))))))
6042+
6043+
(defun lsp--fix-nested-boolean (structure path)
6044+
"Traverse STRUCTURE using the paths from the PATH list, changing the value to
6045+
`:json-false' if it was `nil'. PATH should be a list containing
6046+
one or more symbols, and STRUCTURE should be compatible with
6047+
`lsp-member?', `lsp-get', and `lsp-put'."
6048+
(let ((key (car path))
6049+
(rest (cdr path)))
6050+
(if (null rest)
6051+
;; `lsp-put' returns `nil' both when the key doesn't exist and when the
6052+
;; value is `nil', so we need to explicitly check its presence here
6053+
(when (and (lsp-member? structure key) (not (lsp-get structure key)))
6054+
(lsp-put structure key :json-false))
6055+
;; If `key' does not exist, then we'll silently ignore it
6056+
(when-let ((child (lsp-get structure key)))
6057+
(lsp--fix-nested-boolean child rest)))))
60096058

60106059
(defvar lsp--formatting-indent-alist
60116060
;; Taken from `dtrt-indent-mode'

0 commit comments

Comments
 (0)