Configure preference for lsp-ui-peek or xref/lsp navigation

<<Amendment 1 21/09/18>>
Added functions to facilitate keybindings in derived layers consistent
with navigation style preference.

<<Amendment 2 24/09/18>>
Incorporated feedback from yyoncho
Corrected error in peek binding extension definition

<<Amendment 3 24/09/18>>
Moved 'heirarchy' prefix/keybindings from 'SPC m h' to 'SPC m <g/p> h' for
consistency with navigation style preference selections.
Added 'members' prefix under 'SPC m <g/p> m'
Moved 'lsp-ui-imenu' from 'SPC m g m' to 'SPC m g M'

<<Amendment 4 20/10/18>>
Rebased. Updated README formatting for consistency with norms.

<<Amendment 5 25/10/18>>
Rebased. Moved 'peek' keybindings from 'SPC m p' to 'SPC m G'

<<Amendment 6 01/11/18>>
Reased. Updated for compatibility with upstream changes in lsp-ui.

<<Amendment 7 02/11/18>>
Corrected oversight -- was still binding some peek funcs under 'p'
rather than 'G'. Moved backend keybindings to 'b' (for backend)
rather than 'l' (for lsp)

<<Amendment 8 06/11/18>>
Documentation corrections -- based on feedback from sdwolfz
This commit is contained in:
cormacc 2018-09-20 16:59:40 +01:00 committed by Codruț Constantin Gușoi
parent ce27a36b42
commit 18eacf48a2
4 changed files with 243 additions and 81 deletions

View File

@ -4,11 +4,15 @@
- [[#description][Description]]
- [[#features][Features:]]
- [[#configuration][Configuration]]
- [[#derived-layers][Derived layers]]
- [[#spacemacslsp-bind-keys-for-mode-mode][=spacemacs/lsp-bind-keys-for-mode mode=]]
- [[#declared-prefixes][Declared prefixes]]
- [[#default-key-bindings][Default key bindings]]
- [[#variables][Variables]]
- [[#navigation-mode][Navigation mode]]
- [[#extended-navigation-functions-for-derived-layers][Extended navigation functions for derived layers]]
- [[#spacemacslsp-define-extensions-layer-name-kind-request-optional-extra-parameters][~spacemacs/lsp-define-extensions layer-name kind request &optional extra-parameters~]]
- [[#spacemacslsp-bind-extensions-for-mode][~spacemacs/lsp-bind-extensions-for-mode~]]
- [[#core-keybindings-for-derived-layers][Core keybindings for derived layers]]
- [[#declared-prefixes][Declared prefixes]]
- [[#navigation-prefixes][Navigation prefixes]]
- [[#default-keybindings][Default keybindings]]
- [[#diagnostics][Diagnostics]]
- [[#future-additionsimprovements][Future additions/improvements]]
- [[#make-spacemacslsp-bind-keys-for-mode-bind-conditionally][Make =spacemacs/lsp-bind-keys-for-mode= bind conditionally]]
@ -42,59 +46,6 @@ If you add =lsp-*-enable= to major mode hooks for auto initialization of
language clients, customize =lsp-project-whitelist= =lsp-project-blacklist= to
disable projects you dont want to enable LSP.
** Derived layers
A number of elisp functions have been added to facilitate development of derived layers.
*** =spacemacs/lsp-bind-keys-for-mode mode=
This function binds keys to a number of lsp features useful for all/most modes for the given major mode.
It also declares some relevant keyboard shortcut prefixes.
**** Declared prefixes
The following prefixes have been declared:
| prefix | name | functional area |
|--------+----------------+----------------------------------------------------------------------------|
| ~m =~ | format | Source formatting |
| ~m g~ | goto | Source navigation |
| ~m h~ | help/hierarchy | Help and functions related to hierarchy (class relationships etc.) |
| ~m l~ | lsp/backend | Catchall. Restart LSP backend, other implementation-specific functionality |
| ~m r~ | refactor | What it says on the tin |
| ~m T~ | toggle | Toggle LSP backend features (documentation / symbol info overlays etc.) |
**** Default key bindings
The default bindings are listed below. Derived language server layers should extend this list.
| binding | function |
|---------+-------------------------------------------------|
| ~m = b~ | format buffer (lsp) |
|---------+-------------------------------------------------|
| ~m g i~ | goto implementation (lsp) |
| ~m g t~ | goto type-definition (lsp) |
| ~m g k~ | goto viewport symbol (avy) |
| ~m g m~ | browse file symbols (lsp-ui-imenu) |
| ~m g d~ | find definitions (lsp-ui-peek) |
| ~m g l~ | find implementations (lsp-ui-peek) |
| ~m g r~ | find references (lsp-ui-peek) |
| ~m g s~ | find-workspace-symbol (lsp-ui-peek) |
| ~m g p~ | jump prev (lsp-ui-peek stack - see Note 1) |
| ~m g n~ | jump next (lsp-ui-peek stack - see Note 1) |
| ~m g f~ | jump to flycheck error |
|---------+-------------------------------------------------|
| ~m h h~ | describe thing at point |
|---------+-------------------------------------------------|
| ~m l r~ | lsp-restart-workspace |
| ~m l a~ | execute code action |
|---------+-------------------------------------------------|
| ~m r r~ | rename |
|---------+-------------------------------------------------|
| ~m T d~ | toggle documentation overlay |
| ~m T F~ | toggle documentation overlay function signature |
| ~m T s~ | toggle symbol info overlay |
| ~m T S~ | toggle symbol info overlay symbol name |
| ~m T I~ | toggle symbol info overlay duplicates |
Note 1: There is a window local jump list dedicated to cross references
** Variables
A number of configuration variables have been exposed via the LSP layer =config.el=.
Sensible defaults have been provided, however they may all be overridden in your .spacemacs, or dynamically using the bindings added
@ -102,14 +53,154 @@ under the derived mode t prefix by =(spacemacs/lsp-bind-keys-for-mode mode)=
| Variable name | Default | Description |
|---------------------------------+---------+-------------------------------------------------------------------------------------------|
| =lsp-ui-remap-xref-keybindings= | nil | When non-nil, xref key bindings remapped to lsp-ui-peek-find-{definition,references} |
| =lsp-navigation= | `both' | `simple' or `peek' to bind xref OR lsp-ui-peek navigation functions |
| =lsp-ui-remap-xref-keybindings= | nil | When non-nil, xref keybindings remapped to lsp-ui-peek-find-{definition,references} |
| =lsp-ui-doc-enable= | t | When non-nil, the documentation overlay is displayed |
| =lsp-ui-doc-include-signature= | nil | When nil, signature omitted from lsp-ui-doc overlay (this is usually redundant) |
| =lsp-ui-sideline-enable= | t | When non-nil, the symbol information overlay is displayed |
| =lsp-ui-sideline-show-symbol= | nil | When non-nil, the symbol information overlay includes symbol name (redundant for c-modes) |
** Navigation mode
The ~lsp-navigation~ variable defined in =config.el= allows you to define a preference for lightweight or pretty
(using =lsp-ui-peek=) source navigation styles. By default, the lightweight functions are bound under ~SPC m g~
and the =lsp-ui-peek= variants under ~SPC m G~. Setting ~lsp-navigation~ to either ~'simple~ or ~'peek~ eliminates
the bindings under ~SPC m G~ and creates bindings under ~SPC m g~ according to the specified preference.
*** Extended navigation functions for derived layers
Some LSP server implementations provide extensions to the protocol, which can be leveraged using ~lsp-find-custom~
or ~lsp-ui-peek-find-custom~. A number of additional functions have been provided to facilitate wrapping these extensions
in a manner consistent with the ~lsp-navigation~ setting.
**** ~spacemacs/lsp-define-extensions layer-name kind request &optional extra-parameters~
Use this to define an extension to the lsp find functions. An example from the c-c++ layer:
#+BEGIN_SRC elisp
(spacemacs/lsp-define-extensions "c-c++" 'refs-address
"textDocument/references"
'(plist-put (lsp--text-document-position-params) :context '(:role 128)))
#+END_SRC
This defines the following interactive functions:
- ~c-c++/find-refs-address~
- ~c-c++/peek-refs-address~
**** ~spacemacs/lsp-bind-extensions-for-mode~
Use this to bind one or more extensions under ~SPC m g~ and/or ~SPC m G~, as dictated by the value of ~lsp-navigation~.
Using another example from the c-c++ layer:
#+BEGIN_SRC elisp
(spacemacs/lsp-bind-extensions-for-mode mode "c-c++"
"&" 'refs-address
"R" 'refs-read
"W" 'refs-write
"c" 'callers
"C" 'callees
"v" 'vars)
#+END_SRC
With ~lsp-navigation~ set to ~'both~ (the default), this is equivalent to:
#+BEGIN_SRC elisp
(spacemacs/set-leader-keys-for-major-mode mode
"g&" 'c-c++/find-refs-address
"gR" 'c-c++/find-refs-read
"gW" 'c-c++/find-refs-write
"gc" 'c-c++/find-callers
"gC" 'c-c++/find-callees
"gv" 'c-c++/find-vars
"G&" 'c-c++/peek-refs-address
"GR" 'c-c++/peek-refs-read
"GW" 'c-c++/peek-refs-write
"Gc" 'c-c++/peek-callers
"GC" 'c-c++/peek-callees
"Gv" 'c-c++/peek-vars)
#+END_SRC
whereas with ~lsp-navigation~ set to ~'peek~, this is equivalent to:
#+BEGIN_SRC elisp
(spacemacs/set-leader-keys-for-major-mode mode
"g&" 'c-c++/peek-refs-address
"gR" 'c-c++/peek-refs-read
"gW" 'c-c++/peek-refs-write
"gc" 'c-c++/peek-callers
"gC" 'c-c++/peek-callees
"gv" 'c-c++/peek-vars)
#+END_SRC
etc.
** Core keybindings for derived layers
The ~spacemacs/lsp-bind-keys-for-mode mode~ function binds keys to a number of lsp features useful for all/most modes
for the given major mode. It also declares some relevant keyboard shortcut prefixes.
*** Declared prefixes
The following prefixes have been declared:
| prefix | name | functional area |
|-----------+-------------+----------------------------------------------------------------------------|
| ~SPC m =~ | format | Source formatting |
| ~SPC m g~ | goto | Source navigation |
| ~SPC m G~ | peek | Source navigation (lsp-ui-peek overlay) |
| ~SPC m h~ | help | Help |
| ~SPC m b~ | lsp/backend | Catchall. Restart LSP backend, other implementation-specific functionality |
| ~SPC m r~ | refactor | What it says on the tin |
| ~SPC m T~ | toggle | Toggle LSP backend features (documentation / symbol info overlays etc.) |
**** Navigation prefixes
The following prefixes have been declared under each of the navigation prefixes (i.e. ~SPC m g~ / ~SPC m G~)
| prefix | name | functional area |
|-----------------+------------------+----------------------------------------------------------|
| ~SPC m <g/G> h~ | hierarchy | Heirarchy (i.e. call/inheritance hierarchy etc. ) |
| ~SPC m <g/G> m~ | member hierarchy | Class/namespace members (functions, nested classes, vars |
*** Default keybindings
The default bindings are listed below. Derived language server layers should extend this list.
| binding | function |
|-------------+------------------------------------------------------------------------------|
| ~SPC m = b~ | format buffer (lsp) |
|-------------+------------------------------------------------------------------------------|
| ~SPC m g t~ | goto type-definition (lsp) |
| ~SPC m g k~ | goto viewport symbol (avy) |
| ~SPC m g e~ | browse flycheck errors |
| ~SPC m g M~ | browse file symbols (lsp-ui-imenu) |
|-------------+------------------------------------------------------------------------------|
| Note | /Replaced by the lsp-ui-peek equivalents when ~lsp-navigation~ == 'peek/ |
| ~SPC m g i~ | find implementations (lsp) |
| ~SPC m g d~ | find definitions (xref/lsp) |
| ~SPC m g r~ | find references (xref/lsp) |
| ~SPC m g s~ | find-workspace-symbol (lsp-ui) |
| ~SPC m g p~ | goto previous (xref-pop-marker-stack) |
|-------------+------------------------------------------------------------------------------|
| Note | /Omitted when ~lsp-navigation~ == 'peek or 'simple/ |
| | /Bound under ~SPC m g~ rather than ~SPC m G~ when ~lsp-navigation~ == 'peek/ |
| ~SPC m G i~ | find implementation (lsp-ui-peek) |
| ~SPC m G d~ | find definitions (lsp-ui-peek) |
| ~SPC m G r~ | find references (lsp-ui-peek) |
| ~SPC m G s~ | find-workspace-symbol (lsp-ui-peek) |
| ~SPC m G p~ | goto previous (lsp-ui-peek stack - see Note 1) |
| ~SPC m G n~ | goto next (lsp-ui-peek stack - see Note 1) |
|-------------+------------------------------------------------------------------------------|
| ~SPC m h h~ | describe thing at point |
|-------------+------------------------------------------------------------------------------|
| ~SPC m b r~ | lsp-restart-workspace |
| ~SPC m b a~ | execute code action |
| ~SPC m b c~ | lsp-capabilities |
|-------------+------------------------------------------------------------------------------|
| ~SPC m r r~ | rename |
|-------------+------------------------------------------------------------------------------|
| ~SPC m T d~ | toggle documentation overlay |
| ~SPC m T F~ | toggle documentation overlay function signature |
| ~SPC m T s~ | toggle symbol info overlay |
| ~SPC m T S~ | toggle symbol info overlay symbol name |
| ~SPC m T I~ | toggle symbol info overlay duplicates |
Note 1: There is a window local jump list dedicated to cross references
** Diagnostics
If some features do not work as expected, here is a common check list.
- =M-x lsp-capabilities= If the LSP workspace is initialized correctly
- =M-: xref-backend-functions= should be =(lsp--xref-backend)= for cross
references

View File

@ -9,8 +9,14 @@
;;
;;; License: GPLv3
;; ;; These all have toggles bound under 't' in spacemacs/lsp-define-keys-for-mode
(defvar lsp-ui-remap-xref-keybindings nil "When non-nil, xref keybindings remapped to lsp-ui-peek-find-*")
(defvar lsp-remap-xref-keybindings nil "When non-nil, xref keybindings remapped to lsp-ui-peek-find-*")
(defvar lsp-navigation 'both
"If `simple' binds lightweight navigation functions under `SPC m g'.
If `peek' binds lsp-ui navigation functions under `SPC m g'.
If `both', binds lightweight navigation functions under `SPC m g' and lsp-ui functions under `SPC m G'")
;; These are config variables exposed by the lsp-ui package
;; They all have toggles bound under 't' in spacemacs/lsp-define-keys-for-mode
(defvar lsp-ui-doc-enable t "Enable/disable lsp-ui-doc overlay")
(defvar lsp-ui-doc-include-signature nil "When non-nil, type signature included in the lsp-ui-doc overlay")
(defvar lsp-ui-sideline-enable t "Enable/disable lsp-ui-sideline overlay")

View File

@ -53,33 +53,33 @@ https://github.com/emacs-lsp/lsp-javascript/issues/9#issuecomment-379515379"
(defun spacemacs/lsp-bind-keys-for-mode (mode)
"Define key bindings for the specific MODE."
(spacemacs/declare-prefix-for-mode mode "m=" "format")
(spacemacs/declare-prefix-for-mode mode "mg" "goto")
(spacemacs/declare-prefix-for-mode mode "mh" "help/hierarchy")
(spacemacs/declare-prefix-for-mode mode "ml" "lsp/backend")
(spacemacs/declare-prefix-for-mode mode "mh" "help")
(spacemacs/declare-prefix-for-mode mode "mb" "backend")
(spacemacs/declare-prefix-for-mode mode "mr" "refactor")
(spacemacs/declare-prefix-for-mode mode "mT" "toggle")
(spacemacs/declare-prefix-for-mode mode "mg" "goto")
(spacemacs/declare-prefix-for-mode mode "mG" "peek")
(dolist (prefix '("mg" "mG"))
(spacemacs/declare-prefix-for-mode mode (concat prefix "h") "hierarchy")
(spacemacs/declare-prefix-for-mode mode (concat prefix "m") "members"))
(spacemacs//lsp-bind-navigation-keys-for-mode mode)
(spacemacs/set-leader-keys-for-major-mode mode
;;format
"=b" #'lsp-format-buffer
;;goto
"gi" #'lsp-goto-implementation
"gt" #'lsp-goto-type-definition
"gk" #'spacemacs/lsp-avy-document-symbol
"gm" #'lsp-ui-imenu
"gd" #'lsp-ui-peek-find-definitions
"gi" #'lsp-ui-peek-find-implementation
"gr" #'lsp-ui-peek-find-references
"gs" #'lsp-ui-peek-find-workspace-symbol
"gp" #'lsp-ui-peek-jump-backward
"gn" #'lsp-ui-peek-jump-forward
"gf" #'lsp-ui-flycheck-list
;;hierarchy
"ge" #'lsp-ui-flycheck-list
"gM" #'lsp-ui-imenu
;;help
"hh" #'lsp-describe-thing-at-point
;;jump
;;lsp/backend
"la" #'lsp-execute-code-action
"lr" #'lsp-restart-workspace
;;backend
"ba" #'lsp-execute-code-action
"bc" #'lsp-capabilities
"br" #'lsp-restart-workspace
;;refactor
"rr" #'lsp-rename
;;toggles
@ -87,11 +87,32 @@ https://github.com/emacs-lsp/lsp-javascript/issues/9#issuecomment-379515379"
"Ts" #'lsp-ui-sideline-mode
"TF" #'spacemacs/lsp-ui-doc-func
"TS" #'spacemacs/lsp-ui-sideline-symb
"TI" #'spacemacs/lsp-ui-sideline-ignore-duplicate
)
"TI" #'spacemacs/lsp-ui-sideline-ignore-duplicate))
)
(defun spacemacs//lsp-bind-navigation-keys-for-mode (mode)
(ecase lsp-navigation
('simple (spacemacs//lsp-bind-simple-navigation-functions-for-mode mode "g"))
('peek (spacemacs//lsp-bind-peek-navigation-functions-for-mode mode "g"))
('both
(spacemacs//lsp-bind-simple-navigation-functions-for-mode mode "g")
(spacemacs//lsp-bind-peek-navigation-functions-for-mode mode "G"))))
(defun spacemacs//lsp-bind-simple-navigation-functions-for-mode (mode prefix-char)
(spacemacs/set-leader-keys-for-major-mode mode
(concat prefix-char "i") #'lsp-goto-implementation
(concat prefix-char "d") #'xref-find-definitions
(concat prefix-char "r") #'xref-find-references
(concat prefix-char "s") #'lsp-ui-find-workspace-symbol
(concat prefix-char "p") #'xref-pop-marker-stack))
(defun spacemacs//lsp-bind-peek-navigation-functions-for-mode (mode prefix-char)
(spacemacs/set-leader-keys-for-major-mode mode
(concat prefix-char "i") #'lsp-ui-peek-find-implementation
(concat prefix-char "d") #'lsp-ui-peek-find-definitions
(concat prefix-char "r") #'lsp-ui-peek-find-references
(concat prefix-char "s") #'lsp-ui-peek-find-workspace-symbol
(concat prefix-char "p") #'lsp-ui-peek-jump-backward
(concat prefix-char "n") #'lsp-ui-peek-jump-forward))
(defun spacemacs/lsp-ui-doc-func ()
"Toggle the function signature in the lsp-ui-doc overlay"
@ -144,4 +165,47 @@ https://github.com/emacs-lsp/lsp-javascript/issues/9#issuecomment-379515379"
(push `((,point0 . ,point1) . ,w) candidates))))))
(avy-with avy-document-symbol
(avy--process candidates
(avy--style-fn avy-style)))))
(avy--style-fn avy-style)))))
;; These functions facilitate extension of the navigation-mode keybindings in derived layers
;; See c/c++ layer for a usage example
(defun spacemacs//lsp-get-extension-name (layer-name nav-mode kind)
(intern (concat layer-name "/" nav-mode "-" (symbol-name kind))))
(defun spacemacs//lsp-define-custom-extension (layer-name nav-mode kind request &optional extra)
(let ((lsp-extension-fn (if (eq nav-mode "find")
'lsp-find-custom
'lsp-ui-peek-find-custom))
(extension-name (spacemacs//lsp-get-extension-name layer-name nav-mode kind))
(extension-descriptor (format (concat nav-mode " %s") (symbol-name kind))))
(if extra
(defalias extension-name `(lambda () ,extension-descriptor (interactive) (funcall ',lsp-extension-fn ,request ',extra)))
(defalias extension-name `(lambda () ,extension-descriptor (interactive) (funcall ',lsp-extension-fn ,request))))))
(defun spacemacs/lsp-define-extensions (layer-name kind request &optional extra)
"Wrap backend-specific LSP extensions using lsp-find-custom and lsp-ui-peek-find-custom.
The function names will be <layer-name>/find-<kind> and <layer-name>/peek-<kind>, respectively."
(dolist (nav-mode '("find" "peek"))
(if extra
(spacemacs//lsp-define-custom-extension layer-name nav-mode kind request extra)
(spacemacs//lsp-define-custom-extension layer-name nav-mode kind request))))
(defun spacemacs//lsp-bind-extensions (mode layer-name key kind)
(ecase lsp-navigation
('simple (spacemacs/set-leader-keys-for-major-mode mode
(concat "g" key) (spacemacs//lsp-get-extension-name layer-name "find" kind)))
('peek (spacemacs/set-leader-keys-for-major-mode mode
(concat "g" key) (spacemacs//lsp-get-extension-name layer-name "peek" kind)))
('both (spacemacs/set-leader-keys-for-major-mode mode
(concat "g" key) (spacemacs//lsp-get-extension-name layer-name "find" kind)
(concat "G" key) (spacemacs//lsp-get-extension-name layer-name "peek" kind)))))
(defun spacemacs/lsp-bind-extensions-for-mode (mode layer-name key kind &rest bindings)
"Bind find/peek extensions under the appropriate prefix(es) for the major-mode
MODE. MODE should be a quoted symbol corresponding to a valid major mode.
LAYER-NAME and KEY should be quoted strings. KIND should be quoted symbol corresponding to
a find extension defined using `lsp-define-extensions'"
(while key
(spacemacs//lsp-bind-extensions mode layer-name key kind)
(setq key (pop bindings) kind (pop bindings))))

View File

@ -28,6 +28,7 @@
:defer t
:config
(progn
(spacemacs|hide-lighter lsp-mode)
(evil-set-command-property 'lsp-goto-type-definition :jump t)
(evil-set-command-property 'lsp-goto-implementation :jump t))))
@ -54,7 +55,7 @@
(spacemacs//lsp-sync-peek-face)
(add-hook 'spacemacs-post-theme-change-hook #'spacemacs//lsp-sync-peek-face)
(if lsp-ui-remap-xref-keybindings
(if lsp-remap-xref-keybindings
(progn (define-key lsp-ui-mode-map [remap xref-find-definitions] #'lsp-ui-peek-find-definitions)
(define-key lsp-ui-mode-map [remap xref-find-references] #'lsp-ui-peek-find-references)))