complete-computing-environment/emacs_and_the_language_serv...

71 lines
3.1 KiB
Org Mode

:PROPERTIES:
:ID: cce/emacs_and_the_language_server_protocol
:ROAM_ALIASES: "Language Server Protocol" LSP
:END:
#+TITLE: Emacs and the Language Server Protocol
#+filetags: :Emacs:CCE:Coding:
#+PROPERTY: header-args :mkdirp yes :results none
#+PROPERTY: header-args:emacs-lisp :tangle lsp-base.el
#+ARCOLOGY_KEY: cce/lsp-base
#+ARCOLOGY_ALLOW_CRAWL: t
#+ARROYO_EMACS_MODULE: lsp-base
#+ARROYO_MODULE_WANTS: cce/hydra.org
#+ARROYO_MODULE_WANTS: cce/evil_mode.org
#+ARROYO_MODULE_WANTS: cce/company_code_completion.org
#+begin_src emacs-lisp
(provide 'cce/lsp-base)
#+end_src
[[https://langserver.org][Language Server Protocol]] is a semi-standard protocol for IDEs and tools to be able to reason about code without having to implement direct support for that language. The complexity of language integration is handled in a server (usually written in the same language) which exposes smart information and functionality to work with the code.
What this means for me is that there is always a basic amount of support that can be implied -- there are packages which integrate [[id:cce/emacs][Emacs]] better with a language than LSP, perhaps, but that is also perhaps not necessary. I work through programming philosophy of arbitrary languages in their own pages, and focus here instead on configuring =lsp-mode= and =company-mode=
[[https://github.com/scalameta/metals/issues/2641][company-lsp is deprecated]]...
#+begin_src emacs-lisp
(use-package lsp-mode
:config
(setq lsp-file-watch-threshold nil)
(add-to-list 'company-backends 'company-capf))
(use-package lsp-ui
:config
(setq lsp-ui-doc-enable nil))
#+end_src
With =lsp-mode= installed, language support pages can just add =lsp-mode= to their programming language's mode-hook to enable it. It'll try to connect to the language server or start one, and then present functionality. I present that functionality to myself with =hydra-lsp=:
#+begin_src emacs-lisp
(defhydra hydra-lsp (:exit t :hint nil)
"
Buffer^^ Server^^ Symbol
-------------------------------------------------------------------------------------
[_f_] format [_M-r_] restart [_d_] declaration [_i_] implementation [_o_] documentation
[_m_] imenu [_S_] shutdown [_D_] definition [_t_] type [_r_] rename
[_x_] execute action [_M-s_] describe session [_R_] references [_s_] signature [_e_] flycheck"
("d" lsp-find-declaration)
("D" lsp-ui-peek-find-definitions)
("R" lsp-ui-peek-find-references)
("i" lsp-ui-peek-find-implementation)
("t" lsp-find-type-definition)
("s" lsp-signature-help)
("o" lsp-describe-thing-at-point)
("r" lsp-rename)
("e" lsp-ui-flycheck-list)
("f" lsp-format-buffer)
("m" lsp-ui-imenu)
("x" lsp-execute-code-action)
("M-s" lsp-describe-session)
("M-r" lsp-restart-workspace)
("S" lsp-shutdown-workspace))
(add-hook 'lsp-mode-hook (lambda ()
(evil-local-set-key 'normal (kbd "<SPC>l") #'hydra-lsp/body)))
#+end_src
and so in languages which support =lsp-mode=, I can hit =<SPC>ld= to jump to the declaration of a the function my point is underneath. useful stuff.