Created core lsp minor mode keybindings

Replaced opt-in use of `spacemacs/lsp-bind-keys-for-mode` function with
keybindings for the lsp minor  mode, which should be enabled for all derived
layers.

<<Amendment 1 26/11/2018>>
Added call to (spacemacs//setup-lsp-jump-handler) to lsp-after-open-hook

<<Amendment 2 04/12/2018>>
Migrated to new lsp-mode package API.
Updated c-c++ layer accordingly.

<<Amendment 3 05/12/2018>>
Incorporated PR feedback / corrections from gessen

<<Amendment 4 05/12/2018>>
Incorporated further feedback / corrections from gessen
This commit is contained in:
cormacc 2018-11-22 10:56:35 +00:00 committed by Codruț Constantin Gușoi
parent 5b2e969b3b
commit aacf2a4cc1
7 changed files with 227 additions and 252 deletions

View File

@ -27,9 +27,10 @@
- [[#formatting-clang-format][Formatting (clang-format)]]
- [[#rtags-1][RTags]]
- [[#cquery--ccls][cquery / ccls]]
- [[#goto][goto]]
- [[#helphierarchy][help/hierarchy]]
- [[#backend-language-server][backend (language server)]]
- [[#goto][goto]]
- [[#gotohierarchy][goto/hierarchy]]
- [[#gotomember][goto/member]]
* Description
This layer adds configuration for C/C++ language.
@ -321,6 +322,14 @@ generally applicable.
** cquery / ccls
The key bindings listed below are in addition to the default key bindings defined by the [[file:../../+tools/lsp/README.org][LSP layer]].
A ~[ccls]~ or ~[cquery]~ suffix indicates that the binding is for the indicated backend only.
*** backend (language server)
| Key Binding | Description |
|-------------+------------------------------------------|
| ~SPC m b f~ | refresh index (e.g. after branch change) |
| ~SPC m b p~ | preprocess file |
*** goto
@ -332,23 +341,25 @@ The key bindings listed below are in addition to the default key bindings define
| ~SPC m g c~ | find callers |
| ~SPC m g C~ | find callees |
| ~SPC m g v~ | vars |
| ~SPC m g f~ | find file at point (ffap) |
| ~SPC m g F~ | ffap other window |
*** help/hierarchy
**** goto/hierarchy
| Key binding | Description |
|-------------+-----------------------------|
| ~SPC m h b~ | base class(es) |
| ~SPC m h d~ | derived class(es) |
| ~SPC m h c~ | call hierarchy |
| ~SPC m h C~ | call hierarchy (inv) |
| ~SPC m h i~ | inheritance hierarchy |
| ~SPC m h I~ | inheritance hierarchy (inv) |
| ~SPC m h m~ | member hierarchy |
| ~SPC m h M~ | member hierarchy (inv) |
| Key Binding | Description |
|---------------+-----------------------------|
| ~SPC m g h b~ | base class(es) |
| ~SPC m g h d~ | derived class(es) [ccls] |
| ~SPC m g h c~ | call hierarchy |
| ~SPC m g h C~ | call hierarchy (inv) |
| ~SPC m g h i~ | inheritance hierarchy |
| ~SPC m g h I~ | inheritance hierarchy (inv) |
*** backend (language server)
**** goto/member
| Key binding | Description |
|-------------+------------------------------------------|
| ~SPC m b f~ | refresh index (e.g. after branch change) |
| ~SPC m b p~ | preprocess file |
| Key Binding | Description |
|---------------+-----------------------------|
| ~SPC m g m h~ | member hierarchy |
| ~SPC m g m t~ | member types [ccls] |
| ~SPC m g m f~ | member functions [ccls] |
| ~SPC m g m v~ | member variables [ccls] |

View File

@ -76,10 +76,18 @@ if no pattern matches the project root, lsp-c-c++ will be initialized.")
(defvar c-c++-lsp-sem-highlight-rainbow nil
"When non-nil, use rainbow semantic highlighting")
(defvar c-c++-lsp-initialization-options nil
"Extra initialisation parameters to pass to the ccls backend. See
https://github.com/MaskRay/ccls/blob/master/src/config.hh
for details. N.B. cquery still uses the deprecated extra-init-params (below)")
;; I've left cquery/ccls -extra-init-params separate for now, as one has defaults while the other doesn't
;; Just to facilitate switching between the two easily
(defvar c-c++-lsp-extra-init-params '(:cacheFormat "msgpack")
"Extra initialisation parameters to pass to the backend. See
https://github.com/cquery-project/cquery/blob/master/src/config.h or
https://github.com/MaskRay/ccls/blob/master/src/config.h
for details.")
(defvar c-c++-lsp-extra-args nil
"Extra args to pass to the backend. E.g. to log to file.
https://github.com/MaskRay/ccls/wiki/Emacs for details")

View File

@ -225,28 +225,27 @@ and the arguments for flyckeck-clang based on a project-specific text file."
(spacemacs//c-c++-lsp-set-config (intern (concat "c-c++-lsp-" suffix)) nil (concat "-" suffix)))
;; -- END helper functions for common configuration of cquery and ccls backends
(defun spacemacs//c-c++-lsp-enable ()
"Enable the LSP backend specified by the `c-c++-backend' configuration variable."
(progn (condition-case nil
(spacemacs//c-c++-lsp-call-function "lsp-" "-enable")
(user-error nil))))
(defun spacemacs//c-c++-lsp-config ()
"Configure the LSP backend specified by the `c-c++-backend' configuration variable."
(progn
(spacemacs//c-c++-lsp-setup-company)
(spacemacs//c-c++-lsp-define-extensions)
(spacemacs//c-c++-lsp-wrap-functions)
(setq-default flycheck-disabled-checkers '(c/c++-clang c/c++-gcc))
(dolist (param '("executable" "extra-init-params" "initialization-options" "extra-args" "project-whitelist" "project-blacklist" "sem-highlight-method"))
(spacemacs//c-c++-lsp-apply-config param))
(if (eq c-c++-lsp-cache-dir nil)
(progn
(setq c-c++-lsp-cache-dir (file-truename(concat "~/.emacs.d/.cache/" (symbol-name c-c++-backend))))
(message (concat "c-c++: No c-c++-lsp-cache-dir specified: defaulting to " c-c++-lsp-cache-dir))))
(dolist (param '("executable" "extra-init-params" "cache-dir" "project-whitelist" "project-blacklist" "sem-highlight-method"))
(spacemacs//c-c++-lsp-apply-config param))
(ecase c-c++-backend
('lsp-cquery (setq cquery-cache-dir c-c++-lsp-cache-dir))
('lsp-ccls (setq ccls-initialization-options
(if ccls-initialization-options
(append ccls-initialization-options `(:cacheDirectory ,c-c++-lsp-cache-dir))
`(:cacheDirectory ,c-c++-lsp-cache-dir)))))
(when c-c++-lsp-sem-highlight-rainbow
(unless c-c++-lsp-sem-highlight-method
@ -258,23 +257,15 @@ and the arguments for flyckeck-clang based on a project-specific text file."
('lsp-ccls (ccls-use-default-rainbow-sem-highlight))))
(dolist (mode c-c++-modes)
(spacemacs/lsp-bind-keys-for-mode mode)
(spacemacs//c-c++-lsp-bind-keys-for-mode mode))
(evil-set-initial-state '(spacemacs//c-c++-lsp-symbol nil "-tree-mode") 'emacs)
;;evil-record-macro keybinding clobbers q in cquery-tree-mode-map for some reason?
(evil-make-overriding-map (symbol-value (spacemacs//c-c++-lsp-symbol nil "-tree-mode-map")))))
(defun spacemacs//c-c++-lsp-setup-company ()
"Setup LSP backend auto-completion."
(progn
(spacemacs|add-company-backends :backends company-lsp :modes c-mode-common)
;;Disable client-side cache and sorting, as server does a better job
(setq company-transformers nil company-lsp-async t company-lsp-cache-candidates nil)))
(defun spacemacs//c-c++-lsp-wrap-functions ()
"Wrap navigation functions for the LSP backend specified by the `c-c++-backend' configuration variable."
(defun c-c++/call-hierarchy () (interactive) (spacemacs//c-c++-lsp-funcall-interactively nil "-call-hierarchy" nil))
(defun c-c++/call-hierarchy () (interactive) (spacemacs//c-c++-lsp-funcall-interactively nil "-call-hierarchy"))
(defun c-c++/call-hierarchy-inv () (interactive) (spacemacs//c-c++-lsp-funcall-interactively nil "-call-hierarchy" t))
(defun c-c++/inheritance-hierarchy () (interactive) (spacemacs//c-c++-lsp-funcall-interactively nil "-inheritance-hierarchy"))
(defun c-c++/inheritance-hierarchy-inv () (interactive) (spacemacs//c-c++-lsp-funcall-interactively nil "-inheritance-hierarchy" t))
@ -302,6 +293,7 @@ and the arguments for flyckeck-clang based on a project-specific text file."
;; members
"gmh" #'c-c++/member-hierarchy)
;; goto/peek
(spacemacs/lsp-bind-extensions-for-mode mode "c-c++"
"&" 'refs-address
"R" 'refs-read
@ -312,10 +304,9 @@ and the arguments for flyckeck-clang based on a project-specific text file."
"hb" 'base) ;;Replace this with lsp-goto-implementation in lsp-layer?
(when (eq c-c++-backend 'lsp-ccls)
(spacemacs/set-leader-keys-for-major-mode mode
"bR" 'ccls-reload)
(spacemacs/lsp-bind-extensions-for-mode mode "c-c++"
"mc" 'member-classes
"hd" 'derived
"mt" 'member-types
"mf" 'member-functions
"mv" 'member-vars)))
@ -348,6 +339,7 @@ and the arguments for flyckeck-clang based on a project-specific text file."
(spacemacs/lsp-define-extensions "c-c++" 'callees "$ccls/call" '(:callee t))
(spacemacs/lsp-define-extensions "c-c++" 'base "$ccls/inheritance")
;;ccls features without a cquery analogue...
(spacemacs/lsp-define-extensions "c-c++" 'derived "$ccls/inheritance" '(:derived t))
(spacemacs/lsp-define-extensions "c-c++" 'member-types "$ccls/member" `(:kind 2))
(spacemacs/lsp-define-extensions "c-c++" 'member-functions "$ccls/member" `(:kind 3))
(spacemacs/lsp-define-extensions "c-c++" 'member-vars "$ccls/member" `(:kind 0)))

View File

@ -49,7 +49,7 @@
:init
(progn
(add-to-list 'auto-mode-alist
`("\\.h\\'" . ,c-c++-default-mode-for-headers))
`("\\.h\\'" . ,c-c++-default-mode-for-headers))
(when c-c++-enable-auto-newline
(add-hook 'c-mode-common-hook 'spacemacs//c-toggle-auto-newline)))
:config
@ -259,15 +259,15 @@
(spacemacs/set-leader-keys-for-major-mode mode "gi" 'cscope-index-files))))
;; BEGIN LSP BACKEND PACKAGES
;; See also https://github.com/cquery-project/cquery/wiki/Emacs
;; :mode "\\.c..'" appears to work for deferred loading, in terms of registration with lsp layer
;; however results in a warning in the log as the package doesn't define a function 'cquery'
;; So probably preferable not to defer
(defun c-c++/init-cquery ()
(use-package cquery
:if (eq c-c++-backend 'lsp-cquery)
:defer t
:commands lsp-cquery-enable
:init
(add-hook 'c-mode-common-hook #'spacemacs//c-c++-lsp-enable)
(add-hook 'c-mode-common-hook 'lsp)
:config
(spacemacs//c-c++-lsp-config)))
@ -275,10 +275,8 @@
(defun c-c++/init-ccls ()
(use-package ccls
:if (eq c-c++-backend 'lsp-ccls)
:defer t
:commands lsp-ccls-enable
:init
(add-hook 'c-mode-common-hook #'spacemacs//c-c++-lsp-enable)
(add-hook 'c-mode-common-hook 'lsp)
:config
(spacemacs//c-c++-lsp-config)))

View File

@ -6,16 +6,13 @@
- [[#configuration][Configuration]]
- [[#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-key-bindings-for-derived-layers][Core key bindings for derived layers]]
- [[#declared-prefixes][Declared prefixes]]
- [[#navigation-prefixes][Navigation prefixes]]
- [[#default-key-bindings][Default key bindings]]
- [[#diagnostics][Diagnostics]]
- [[#future-additionsimprovements][Future additions/improvements]]
- [[#make-spacemacslsp-bind-keys-for-mode-bind-conditionally][Make =spacemacs/lsp-bind-keys-for-mode= bind conditionally]]
- [[#key-bindings][Key bindings]]
- [[#key-binding-prefixes][Key binding prefixes]]
- [[#core-key-bindings][Core key bindings]]
- [[#language-specific-key-binding-extensions][Language-specific key binding extensions]]
- [[#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~]]
- [[#diagnostics][Diagnostics]]
- [[#references][References]]
* Description
@ -37,6 +34,7 @@ details.
- Signature help with eldoc
- Symbol documentation in a child frame (=lsp-ui-doc=)
- Navigation using imenu
- Consistent core keybindings in LSP modes
* Configuration
The LSP ecosystem is based on two packages: [[https://github.com/emacs-lsp/lsp-mode][lsp-mode]] and [[https://github.com/emacs-lsp/lsp-ui][lsp-ui]].
@ -53,7 +51,7 @@ under the derived mode t prefix by =(spacemacs/lsp-bind-keys-for-mode mode)=
| Variable name | Default | Description |
|---------------------------------+---------+-------------------------------------------------------------------------------------------|
| =lsp-navigation= | `both | `simple or `peek to bind xref OR lsp-ui-peek navigation functions |
| =lsp-navigation= | `both | `simple or `peek to bind only xref OR lsp-ui-peek navigation functions |
| =lsp-ui-remap-xref-keybindings= | nil | When non-nil, xref key bindings 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) |
@ -66,12 +64,82 @@ The ~lsp-navigation~ variable defined in =config.el= allows you to define a pref
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
* Key bindings
A number of lsp features useful for all/most modes have been bound to the lsp minor mode, meaning they'll be
available in all language layers based on the lsp layer.
** Key binding prefixes
The key bindings are grouped under the following prefixes:
| 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.) |
Some navigation keybindings (i.e. ~SPC m g~ / ~SPC m G~) use an additional level of grouping:
| 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 |
** Core key bindings
The lsp minor mode bindings are:
| binding | function |
|-------------+--------------------------------------------------------------------------------|
| ~SPC m = b~ | format buffer (lsp) |
|-------------+--------------------------------------------------------------------------------|
| ~SPC m g t~ | goto type-definition (lsp) |
| ~SPC m g k~ | goto viewport word (avy) (See Note 1) |
| ~SPC m g K~ | goto viewport symbol (avy) (See Note 1) |
| ~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 2) |
| ~SPC m G n~ | goto next (lsp-ui-peek stack - see Note 2) |
|-------------+--------------------------------------------------------------------------------|
| ~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: Your language server may not distinguish between the word and symbol variants of this binding.
Note 2: There is a window local jump list dedicated to cross references.
** Language-specific key binding extensions
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~
*** ~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
@ -84,7 +152,7 @@ This defines the following interactive functions:
- ~c-c++/find-refs-address~
- ~c-c++/peek-refs-address~
**** ~spacemacs/lsp-bind-extensions-for-mode~
*** ~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:
@ -130,76 +198,7 @@ whereas with ~lsp-navigation~ set to ~'peek~, this is equivalent to:
etc.
** Core key bindings 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 key bindings
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
* 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
@ -207,12 +206,6 @@ If some features do not work as expected, here is a common check list.
- =M-: completion-at-point-functions= should be =(lsp-completion-at-point)= for
completion
* Future additions/improvements
** Make =spacemacs/lsp-bind-keys-for-mode= bind conditionally
i.e. only bind keys if the language server supports the capability (queried using =lsp-capabilities=).
=lsp-capabilities= uses current buffer to determine the language server, so this would probably entail adding the bindings dynamically in
a mode hook.
* References
- [[https://github.com/emacs-lsp/lsp-mode][lsp-mode repo]]
- [[https://github.com/emacs-lsp/lsp-ui][lsp-ui repo]]

View File

@ -9,33 +9,11 @@
;;
;;; License: GPLv3
(defun spacemacs//lsp-sync-peek-face ()
"Synchronize the face used in `lsp-ui' peek window according to the theme."
(set-face-attribute 'lsp-ui-peek-list nil
:background (face-attribute 'hl-line :background nil t))
(set-face-attribute 'lsp-ui-peek-peek nil
:background (face-attribute 'hl-line :background nil t))
(set-face-attribute 'lsp-ui-peek-selection nil
:background (face-attribute 'highlight :background nil t)
:foreground (face-attribute 'default :foreground nil t))
(set-face-attribute 'lsp-ui-peek-filename nil
:foreground (face-attribute 'font-lock-constant-face
:foreground nil t))
(set-face-attribute 'lsp-ui-peek-highlight nil
:background (face-attribute 'highlight :background nil t)
:foreground (face-attribute 'highlight :foreground nil t)
:distant-foreground (face-attribute 'highlight
:foreground nil t))
(set-face-attribute 'lsp-ui-peek-header nil
:background (face-attribute 'highlight :background nil t)
:foreground (face-attribute 'default :foreground nil t))
)
(defun spacemacs//setup-lsp-jump-handler (&rest modes)
"Set jump handler for LSP with the given MODE."
(dolist (m modes)
(add-to-list (intern (format "spacemacs-jump-handlers-%S" m))
'(lsp-ui-peek-find-definitions :async t))))
'(lsp-ui-peek-find-definitions :async t))))
(defun fix-lsp-company-prefix ()
"fix lsp-javascript company prefix
@ -44,33 +22,28 @@ https://github.com/emacs-lsp/lsp-javascript/issues/9#issuecomment-379515379"
(defun lsp-prefix-company-transformer (candidates)
(let ((completion-ignore-case t))
(if (and (car candidates)
(get-text-property 0 'lsp-completion-prefix (car candidates)))
(all-completions (company-grab-symbol) candidates)
(get-text-property 0 'lsp-completion-prefix (car candidates)))
(all-completions (company-grab-symbol) candidates)
candidates)))
(make-local-variable 'company-transformers)
(add-to-list 'company-transformers 'lsp-prefix-company-transformer))
(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 "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"))
(defun spacemacs/lsp-bind-keys ()
"Define key bindings for the lsp minor mode."
(ecase lsp-navigation
('simple (spacemacs//lsp-bind-simple-navigation-functions "g"))
('peek (spacemacs//lsp-bind-peek-navigation-functions "g"))
('both
(spacemacs//lsp-bind-simple-navigation-functions "g")
(spacemacs//lsp-bind-peek-navigation-functions "G")))
(spacemacs//lsp-bind-navigation-keys-for-mode mode)
(spacemacs/set-leader-keys-for-major-mode mode
(spacemacs/set-leader-keys-for-minor-mode 'lsp-mode
;;format
"=b" #'lsp-format-buffer
;;goto
"gt" #'lsp-goto-type-definition
"gk" #'spacemacs/lsp-avy-document-symbol
"gk" #'spacemacs/lsp-avy-goto-word
"gK" #'spacemacs/lsp-avy-goto-symbol
"ge" #'lsp-ui-flycheck-list
"gM" #'lsp-ui-imenu
;;help
@ -89,24 +62,16 @@ https://github.com/emacs-lsp/lsp-javascript/issues/9#issuecomment-379515379"
"TS" #'spacemacs/lsp-ui-sideline-symb
"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
(defun spacemacs//lsp-bind-simple-navigation-functions (prefix-char)
(spacemacs/set-leader-keys-for-minor-mode 'lsp-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
(defun spacemacs//lsp-bind-peek-navigation-functions (prefix-char)
(spacemacs/set-leader-keys-for-minor-mode 'lsp-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
@ -114,6 +79,19 @@ https://github.com/emacs-lsp/lsp-javascript/issues/9#issuecomment-379515379"
(concat prefix-char "p") #'lsp-ui-peek-jump-backward
(concat prefix-char "n") #'lsp-ui-peek-jump-forward))
(defun spacemacs//lsp-declare-prefixes-for-mode (mode)
"Define key binding prefixes for the specific MODE."
(spacemacs/declare-prefix-for-mode mode "m=" "format")
(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")))
(defun spacemacs/lsp-ui-doc-func ()
"Toggle the function signature in the lsp-ui-doc overlay"
(interactive)
@ -139,35 +117,6 @@ https://github.com/emacs-lsp/lsp-javascript/issues/9#issuecomment-379515379"
(setq key (pop bindings)
def (pop bindings))))
;; From https://github.com/MaskRay/Config/blob/master/home/.config/doom/autoload/misc.el#L118
;;;###autoload
(defun spacemacs/lsp-avy-document-symbol ()
(interactive)
(let (ranges point0 point1 (line 0) (col 0) (w (selected-window)) candidates)
(save-excursion
(goto-char 1)
(dolist (loc
(lsp--send-request (lsp--make-request
"textDocument/documentSymbol"
;;;;;; I added :all t in ccls to return all symbols in the document
`(:textDocument ,(lsp--text-document-identifier) :all t))))
(let ((range (->> loc (gethash "location") (gethash "range"))))
(-let* [((&hash "line" l0 "character" c0) (gethash "start" range))
((&hash "line" l1 "character" c1) (gethash "end" range))]
(when (or (< line l0) (and (= line l0) (<= col c0)))
(forward-line (- l0 line))
(forward-char c0)
(setq point0 (point))
(forward-line (- l1 l0))
(forward-char c1)
(setq point1 (point))
(setq line l1 col c1)
(push `((,point0 . ,point1) . ,w) candidates))))))
(avy-with avy-document-symbol
(avy--process candidates
(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)
@ -209,3 +158,51 @@ 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))))
(defun spacemacs/lsp-avy-goto-word ()
(interactive)
(spacemacs//lsp-avy-document-symbol t))
(defun spacemacs/lsp-avy-goto-symbol ()
(interactive)
(spacemacs//lsp-avy-document-symbol nil))
;; From https://github.com/MaskRay/Config/blob/master/home/.config/doom/autoload/misc.el#L118
(defun spacemacs//lsp-avy-document-symbol (all)
(interactive)
(let ((line 0) (col 0) (w (selected-window))
(ccls (and (memq major-mode '(c-mode c++-mode objc-mode)) (eq c-c++-backend 'lsp-ccls)))
(start-line (1- (line-number-at-pos (window-start))))
(end-line (1- (line-number-at-pos (window-end))))
ranges point0 point1
candidates)
(save-excursion
(goto-char 1)
(cl-loop for loc in
(lsp--send-request (lsp--make-request
"textDocument/documentSymbol"
`(:textDocument ,(lsp--text-document-identifier)
:all ,(if all t :json-false)
:startLine ,start-line :endLine ,end-line)))
for range = (if ccls loc (->> loc (gethash "location") (gethash "range")))
for range_start = (gethash "start" range)
for range_end = (gethash "end" range)
for l0 = (gethash "line" range_start)
for c0 = (gethash "character" range_start)
for l1 = (gethash "line" range_end)
for c1 = (gethash "character" range_end)
while (<= l0 end-line)
when (>= l0 start-line)
do
(forward-line (- l0 line))
(forward-char c0)
(setq point0 (point))
(forward-line (- l1 l0))
(forward-char c1)
(setq point1 (point))
(setq line l1 col c1)
(push `((,point0 . ,point1) . ,w) candidates)))
;; (require 'avy)
(avy-with avy-document-symbol
(avy--process candidates
(avy--style-fn avy-style)))))

View File

@ -13,14 +13,7 @@
'(
lsp-mode
lsp-ui
(lsp-imenu :requires imenu :location built-in)
(lsp-ui-imenu :requires lsp-imenu :location built-in)
(company-lsp :requires company)
;; `flycheck-lsp' does not exist so we defined it as built-in to avoid
;; fetching it from ELPA repositories.
;; this logical package serves to hook all flycheck related configuration
;; for LSP.
(flycheck-lsp :requires flycheck :location built-in)
))
(defun lsp/init-lsp-mode ()
@ -28,33 +21,19 @@
:defer t
:config
(progn
(spacemacs|hide-lighter lsp-mode)
(spacemacs/lsp-bind-keys)
(add-hook 'lsp-after-open-hook (lambda ()
"Setup xref jump handler and declare keybinding prefixes"
(spacemacs//setup-lsp-jump-handler major-mode)
(spacemacs//lsp-declare-prefixes-for-mode major-mode)))
(evil-set-command-property 'lsp-goto-type-definition :jump t)
(evil-set-command-property 'lsp-goto-implementation :jump t))))
(defun lsp/init-company-lsp ()
(use-package company-lsp
:defer t
:init
;; Language servers have better idea filtering and sorting,
;; don't filter results on the client side.
(setq company-transformers nil
company-lsp-async t
company-lsp-cache-candidates nil)))
(defun lsp/init-flycheck-lsp ()
;; Disable lsp-flycheck.el in favor of lsp-ui-flycheck.el
(setq lsp-enable-flycheck nil))
(defun lsp/init-lsp-ui ()
(use-package lsp-ui
:defer t
:init (add-hook 'lsp-mode-hook #'lsp-ui-mode)
:config
(progn
(spacemacs//lsp-sync-peek-face)
(add-hook 'spacemacs-post-theme-change-hook #'spacemacs//lsp-sync-peek-face)
(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)))
@ -68,8 +47,5 @@
)
)))
(defun lsp/init-lsp-imenu ()
(use-package lsp-imenu :defer t :init (add-hook 'lsp-after-open-hook #'lsp-enable-imenu)))
(defun lsp/init-lsp-ui-imenu ()
(use-package lsp-ui-imenu :defer t :config (evil-make-overriding-map lsp-ui-imenu-mode-map)))
(defun lsp/init-company-lsp ()
(use-package company-lsp :defer t))