LSP consistency
LSP is mostly code jumping with the xref, and I wanted to have some keybinding consistency. This also loads the LSP map only when eglot is turned on, making the menu more consistent as well.
This commit is contained in:
parent
9ec76b6888
commit
72cd815902
2 changed files with 140 additions and 53 deletions
|
@ -1295,13 +1295,14 @@ Emacs Completion is not obvious, and has lots of different interfaces, some dist
|
|||
We have two initial interfaces that may end up showing the same information (if configured correctly).
|
||||
|
||||
Emacs’ first option, called [[help:complete][complete]], is simple. It completes based on words you are most likely to type.
|
||||
|
||||
If the line is /indented/ (the default for the ~TAB~ key), let’s complete the word:
|
||||
#+begin_src emacs-lisp
|
||||
(setq tab-always-indent 'complete)
|
||||
#+end_src
|
||||
Let’s also use the ~Command~ key to call this directly :
|
||||
#+begin_src emacs-lisp
|
||||
(global-set-key (kbd "s-.") 'complete)
|
||||
(global-set-key (kbd "C-TAB") 'complete)
|
||||
#+end_src
|
||||
|
||||
The next interface is [[help:completion-at-point][completion-at-point]] (which I set to ~M-TAB~). This code (from mini-buffer) doubles with the other [[Vertico][completing processes]] (like [[help:completing-read][completing-read]]) and presents choices based on a series of functions (see [[https://with-emacs.com/posts/tutorials/customize-completion-at-point/][this essay]] for details).
|
||||
|
@ -1313,6 +1314,7 @@ What would be nice is that if =complete= doesn't have a match, =completion-at-po
|
|||
The [[file:ha-org.org::*Spell Checking][Flyspell package]] takes over ~M-TAB~, so let’s add another keybinding (or [[Corfu][use time-based menu option]]):
|
||||
#+begin_src emacs-lisp
|
||||
(global-set-key (kbd "s->") 'completion-at-point)
|
||||
(global-set-key (kbd "s-.") 'complete)
|
||||
#+end_src
|
||||
|
||||
The idea of cycling through candidates sounds like a good idea, but let’s start with a number before setting this to =t=:
|
||||
|
@ -1643,9 +1645,7 @@ Build the hydra as well as configure the =perspective= project.
|
|||
("l" persp-state-load)
|
||||
("w" ha-switch-to-special) ; The most special perspective
|
||||
("q" nil)
|
||||
("C-g" nil))
|
||||
|
||||
:bind ("C-<tab>" . hydra-workspace-leader/body))
|
||||
("C-g" nil)))
|
||||
#+end_src
|
||||
|
||||
I have no idea why this binding doesn’t work /within/ the =use-package= declaration, but oh well…
|
||||
|
|
|
@ -50,8 +50,8 @@ Farm off commands into /virtual environments/:
|
|||
The [[https://www.emacswiki.org/emacs/FlySpell#h5o-2][flyspell-prog-mode]] checks for misspellings in comments.
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
(use-package flyspell
|
||||
:hook (prog-mode . flyspell-prog-mode))
|
||||
(use-package flyspell
|
||||
:hook (prog-mode . flyspell-prog-mode))
|
||||
#+end_src
|
||||
** Flycheck
|
||||
Why use [[https://www.flycheck.org/][flycheck]] over the built-in =flymake=? Speed used to be the advantage, but I’m now pushing much of this to LSP, so speed is less of an issue. What about when I am not using LSP? Also, since I’ve hooked grammar checkers, I need this with global keybindings.
|
||||
|
@ -157,7 +157,7 @@ To take advantage of this, type:
|
|||
|
||||
Note: Yes, we could use [[https://github.com/mrkkrp/vimish-fold][vimish-fold]] (and its cousin, [[https://github.com/alexmurray/evil-vimish-fold][evil-vimish-fold]]) and we’ll see if I need those.
|
||||
** Navigation with dumb-jump
|
||||
Once upon a time, we use to create a =TAGS= file that contained the database for navigating code bases, but with new faster versions of grep, e.g. [[https://beyondgrep.com][ack]], [[https://github.com/ggreer/the_silver_searcher][ag]] (aka, the Silver Searcher), [[https://github.com/Genivia/ugrep][ugrep]] and [[https://github.com/BurntSushi/ripgrep][ripgrep]], we should just be able to use them. but I want to:
|
||||
Once upon a time, we use to create a =TAGS= file that contained the database for navigating code bases, but with new faster versions of grep, e.g. [[https://beyondgrep.com][ack]], [[https://github.com/ggreer/the_silver_searcher][ag]] (aka, the Silver Searcher), [[https://github.com/Genivia/ugrep][ugrep]] and [[https://github.com/BurntSushi/ripgrep][ripgrep]], we should be able to use them. but I want to:
|
||||
- Be in a function, and see its callers. For this, the [[help:rg-dwim][rg-dwim]] function is my bread-and-butter.
|
||||
- Be on a function, and jump to the definition. For this, I use [[https://github.com/jacktasia/dumb-jump][dumb-jump]], which uses the above utilities.
|
||||
|
||||
|
@ -168,42 +168,113 @@ Once upon a time, we use to create a =TAGS= file that contained the database for
|
|||
|
||||
:config
|
||||
(setq xref-show-definitions-function #'xref-show-definitions-completing-read)
|
||||
|
||||
(add-hook 'xref-backend-functions #'dumb-jump-xref-activate)
|
||||
;; (add-to-list 'evil-goto-definition-functions #'dumb-jump)
|
||||
|
||||
;; Remove this now that https://github.com/jacktasia/dumb-jump/issues/338
|
||||
;; (defun evil-set-jump-args (&rest ns) (evil-set-jump))
|
||||
;; (advice-add 'dumb-jump-goto-file-line :before #'evil-set-jump-args)
|
||||
|
||||
(ha-prog-leader
|
||||
"s" '(:ignore t :which-key "search")
|
||||
"s s" '("search" . xref-find-apropos)
|
||||
"s d" '("definitions" . xref-find-definitions)
|
||||
"s s" '("search" . xref-find-apropos)
|
||||
"s d" '("definitions" . xref-find-definitions)
|
||||
"s o" '("other window" . xref-find-definitions-other-window)
|
||||
"s r" '("references" . xref-find-references)
|
||||
"s b" '("back" . xref-pop-marker-stack))
|
||||
"s r" '("references" . xref-find-references)
|
||||
"s b" '("back" . xref-go-back)
|
||||
"s f" '("forward" . xref-go-forward))
|
||||
|
||||
:general (:states 'normal
|
||||
"g." 'xref-find-definitions
|
||||
"g>" 'xref-find-definitions-other-window
|
||||
"g," 'xref-go-back
|
||||
"g<" 'xref-go-forward
|
||||
"g/" 'xref-find-references
|
||||
"g?" 'xref-find-references-and-replace
|
||||
"gh" 'xref-find-apropos
|
||||
"gb" 'xref-pop-marker-stack))
|
||||
"gb" 'xref-go-back))
|
||||
#+end_src
|
||||
|
||||
I have two different /jumping/ systems, the [[info:emacs#Xref][Xref interface]] and Evil’s. While comparable goals, they are behave different. Let’s compare evil keybindings:
|
||||
| ~M-.~ | ~g .~ | [[help:xref-find-definitions][xref-find-definitions]] (also ~g d~ for [[help:evil-goto-definition][evil-goto-definition]])† |
|
||||
| | ~g >~ | =xref-find-definitions-other-window= |
|
||||
| ~M-,~ | ~g ,~ | [[help:xref-go-back][xref-go-back]] (see [[help:xref-pop-marker-stack][xref-pop-marker-stack]]) |
|
||||
| ~C-M-,~ | ~g <~ | [[help:xref-go-forward][xref-go-forward]] (kinda like =xref-find-definitions=) |
|
||||
| ~M-?~ | ~g /~ | [[help:xref-find-references][xref-find-references]] to go from definition to code calls‡ |
|
||||
| | ~g ?~ | [[help:xref-find-references-and-replace][xref-find-references-and-replace]] could be more accurate than [[*iEdit][iEdit]]. |
|
||||
| ~C-M-.~ | ~g h~ | [[help:xref-find-apropos][xref-find-apropos]] … doesn’t work well without LSP |
|
||||
| ~C-TAB~ | | perform completion around point (also ~M-TAB~), see [[file:ha-config.org::*Auto Completion][Auto Completion]]. |
|
||||
|
||||
† Prefix to prompt for the term \
|
||||
‡ If it finds more than one definition, Emacs displays the [[info:emacs#Xref Commands][*xref* buffer]], allowing you to select the definition.
|
||||
** Language Server Protocol (LSP) Integration
|
||||
The [[https://microsoft.github.io/language-server-protocol/][LSP]] is a way to connect /editors/ (like Emacs) to /languages/ (like Lisp)… wait, no, it was originally designed for VS Code and probably Python, but we now abstract away [[https://github.com/davidhalter/jedi][Jedi]] and the [[http://tkf.github.io/emacs-jedi/latest/][Emacs integration to Jedi]] (and duplicate everything for Ruby, and Clojure, and…).
|
||||
The [[https://microsoft.github.io/language-server-protocol/][LSP]] is a way to connect /editors/ (like Emacs) to /languages/ (like Lisp)… wait, no. While originally designed for VS Code and probably Python, we can abstract away [[https://github.com/davidhalter/jedi][Jedi]] and the [[http://tkf.github.io/emacs-jedi/latest/][Emacs integration to Jedi]] (and duplicate everything for Ruby, and Clojure, and…).
|
||||
|
||||
Emacs has two LSP projects, and while I have used [[LSP Mode]], but since I don’t have heavy IDE requirements, I am finding that [[eglot]] to be simpler.
|
||||
*** eglot
|
||||
The [[https://github.com/joaotavora/eglot][eglot]] package usually connects to Emacs’ standard command interface, so the eglot-specific code is mostly in controlling the backend servers. That said, it has a couple of =eglot-= commands that I want easy access to:
|
||||
The [[https://github.com/joaotavora/eglot][eglot]] package connects to Emacs’ standard command interface, so the eglot-specific code is connects the [[https://www.gnu.org/software/emacs/manual/html_node/emacs/Xref.html][xref interface]] to controlling backend servers. That said, it has a couple of =eglot-= commands that I want easy access to:
|
||||
#+begin_src emacs-lisp
|
||||
(use-package eglot
|
||||
:init
|
||||
(setq eglot-connect-timeout 10
|
||||
eglot-autoshutdown t)
|
||||
|
||||
:config
|
||||
(ha-prog-leader
|
||||
"w" '(:ignore t :which-key "eglot")
|
||||
"ws" '("start" . eglot)
|
||||
"wr" '("restart" . eglot-reconnect)
|
||||
"wb" '("events" . eglot-events-buffer)
|
||||
"we" '("errors" . eglot-stderr-buffer)
|
||||
"wq" '("quit" . eglot-shutdown)
|
||||
"wQ" '("quit all" . eglot-shutdown-all)
|
||||
"ws" '("start" . eglot))
|
||||
|
||||
"r" '("rename" . eglot-rename)
|
||||
"=" '("format" . eglot-format)
|
||||
"a" '("code actions" . eglot-code-actions)
|
||||
"i" '("imports" . eglot-code-action-organize-imports)))
|
||||
;; The following leader-like keys, are only available when I have started LSP:
|
||||
:general
|
||||
(:states 'normal :keymaps 'eglot-mode-map
|
||||
"SPC m w r" '("restart" . eglot-reconnect)
|
||||
"SPC m w b" '("events" . eglot-events-buffer)
|
||||
"SPC m w e" '("errors" . eglot-stderr-buffer)
|
||||
"SPC m w q" '("quit" . eglot-shutdown)
|
||||
"SPC m w Q" '("quit all" . eglot-shutdown-all)
|
||||
|
||||
"SPC m l" '(:ignore t :which-key "lsp")
|
||||
"SPC m l r" '("rename" . eglot-rename)
|
||||
"SPC m l f" '("format" . eglot-format)
|
||||
"SPC m l a" '("actions" . eglot-code-actions)
|
||||
"SPC m l i" '("imports" . eglot-code-action-organize-imports)
|
||||
"SPC m l d" '("doc" . eglot-lookup-documentation)))
|
||||
#+end_src
|
||||
|
||||
The following was stolen from Doom’s configuration:
|
||||
#+begin_src emacs-lisp
|
||||
(defvar eglot--help-buffer nil)
|
||||
|
||||
(defun eglot-lookup-documentation ()
|
||||
"Request documentation for the thing at point."
|
||||
(interactive)
|
||||
(eglot--dbind ((Hover) contents range)
|
||||
(jsonrpc-request (eglot--current-server-or-lose) :textDocument/hover
|
||||
(eglot--TextDocumentPositionParams))
|
||||
(let ((blurb (and (not (seq-empty-p contents))
|
||||
(eglot--hover-info contents range)))
|
||||
(hint (thing-at-point 'symbol)))
|
||||
(if blurb
|
||||
(with-current-buffer
|
||||
(or (and (buffer-live-p eglot--help-buffer)
|
||||
eglot--help-buffer)
|
||||
(setq eglot--help-buffer (generate-new-buffer "*eglot-help*")))
|
||||
(with-help-window (current-buffer)
|
||||
(rename-buffer (format "*eglot-help for %s*" hint))
|
||||
(with-current-buffer standard-output (insert blurb))
|
||||
(setq-local nobreak-char-display nil)))
|
||||
(display-local-help))))
|
||||
'deferred)
|
||||
#+end_src
|
||||
*** eglot with Consult
|
||||
The [[https://github.com/mohkale/consult-eglot][consult-eglot]] project adds a [[file:ha-config.org::*Consult][Consult]] interface to lookup symbols from the LSP server.
|
||||
#+begin_src emacs-lisp
|
||||
(use-package consult-eglot
|
||||
:general
|
||||
(:states 'normal :keymaps 'eglot-mode-map
|
||||
"g h" '("find apropos" . consult-eglot-symbols)
|
||||
"SPC m l s" '("find symbol" . consult-eglot-symbols)))
|
||||
#+end_src
|
||||
*** Display Configuration
|
||||
Using the [[https://github.com/seagle0128/doom-modeline][Doom Modeline]] to add notifications:
|
||||
|
@ -248,20 +319,23 @@ While there are language-specific ways to rename variables and functions, [[http
|
|||
I like =comment-dwim= (~M-;~), and I like =comment-box=, but I have an odd personal style that I like to codify:
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
(defun ha-comment-line (&optional start end)
|
||||
(interactive "r")
|
||||
(when (or (null start) (not (region-active-p)))
|
||||
(setq start (line-beginning-position))
|
||||
(setq end (line-end-position)))
|
||||
(save-excursion
|
||||
(narrow-to-region start end)
|
||||
(upcase-region start end)
|
||||
(goto-char (point-min))
|
||||
(insert "------------------------------------------------------------------------\n")
|
||||
(goto-char (point-max))
|
||||
(insert "\n------------------------------------------------------------------------")
|
||||
(comment-region (point-min) (point-max))
|
||||
(widen)))
|
||||
(defun ha-comment-line (&optional start end)
|
||||
"Comment a line or region with a block-level format.
|
||||
Calls `comment-region' with START and END set to the region or
|
||||
the start and end of the line."
|
||||
(interactive)
|
||||
(when (or (null start) (not (region-active-p)))
|
||||
(setq start (line-beginning-position))
|
||||
(setq end (line-end-position)))
|
||||
(save-excursion
|
||||
(narrow-to-region start end)
|
||||
(upcase-region start end)
|
||||
(goto-char (point-min))
|
||||
(insert "------------------------------------------------------------------------\n")
|
||||
(goto-char (point-max))
|
||||
(insert "\n------------------------------------------------------------------------")
|
||||
(comment-region (point-min) (point-max))
|
||||
(widen)))
|
||||
#+end_src
|
||||
And a keybinding:
|
||||
#+begin_src emacs-lisp
|
||||
|
@ -272,8 +346,8 @@ While I like [[help:eval-print-last-sexp][eval-print-last-sexp]], I would like a
|
|||
#+begin_src emacs-lisp
|
||||
(defun ha-eval-print-last-sexp (&optional internal-arg)
|
||||
"Evaluate the expression located before the point.
|
||||
The results are inserted back into the buffer at the end
|
||||
of the line after a comment."
|
||||
Insert results back into the buffer at the end of the line after
|
||||
a comment."
|
||||
(interactive)
|
||||
(save-excursion
|
||||
(eval-print-last-sexp internal-arg))
|
||||
|
@ -311,7 +385,7 @@ The idea of using math symbols for a programming languages keywords is /cute/, b
|
|||
|
||||
(add-hook 'prog-mode-hook 'ha-prettify-prog)
|
||||
#+end_src
|
||||
Eventually, I want to follow [[https://www.masteringemacs.org/article/unicode-ligatures-color-emoji][Mickey Petersen's essay]] on getting full ligatures working, but right now, they don’t work on the Mac, and that is my current workhorse.
|
||||
Hopefully I can follow [[https://www.masteringemacs.org/article/unicode-ligatures-color-emoji][Mickey Petersen's essay]] on getting full ligatures working, but right now, they don’t work on the Mac, and that is my current workhorse.
|
||||
** Task Runner
|
||||
I've replaced my home-grown compilation list code with a more versatile [[https://github.com/emacs-taskrunner/emacs-taskrunner][Taskrunner project]].
|
||||
#+begin_src emacs-lisp :tangle no
|
||||
|
@ -327,18 +401,18 @@ Doom provides basic support, but we need more keybindings:
|
|||
:desc "Reun last task" "z" 'ivy-taskrunner-rerun-last-command)
|
||||
#+end_src
|
||||
|
||||
While my company is typically using =Rakefile= and =Makefile= in the top-level project, I want to have my personal tasks set per-project as well. For that, I thought about using [[https://pydoit.org/][doit]], where I would just create a =dodo.py= file that contains:
|
||||
While my company is typically using =Rakefile= and =Makefile= in the top-level project, I want to have my personal tasks set per-project as well. For that, I thought about using [[https://pydoit.org/][doit]], where I would create a =dodo.py= file that contains:
|
||||
|
||||
#+begin_src python :tangle no
|
||||
def hello():
|
||||
"""This command greets you."""
|
||||
return {
|
||||
'actions': [ 'echo hello' ],
|
||||
}
|
||||
def hello():
|
||||
"""This command greets you."""
|
||||
return {
|
||||
'actions': [ 'echo hello' ],
|
||||
}
|
||||
#+end_src
|
||||
|
||||
* Languages
|
||||
Simple to configure languages go here. More advanced stuff will go in their own files… eventually.
|
||||
Simple to configure languages go here. More advanced languages go into their own files… eventually.
|
||||
** Markdown
|
||||
All the READMEs and other documentation use [[https://jblevins.org/projects/markdown-mode/][markdown-mode]].
|
||||
#+begin_src emacs-lisp
|
||||
|
@ -357,14 +431,14 @@ Note that the markdown-specific commands use the ~C-c C-c~ and ~C-c C-s~ prefix
|
|||
** Ansible
|
||||
Doing a lot of [[https://github.com/yoshiki/yaml-mode][YAML work]], but this project needs a new maintainer.
|
||||
#+begin_src emacs-lisp
|
||||
(use-package yaml-mode
|
||||
:mode (rx ".y" (optional "a") "ml" string-end))
|
||||
(use-package yaml-mode
|
||||
:mode (rx ".y" (optional "a") "ml" string-end))
|
||||
#+end_src
|
||||
|
||||
Ansible uses Jinja, so we install the [[https://github.com/paradoxxxzero/jinja2-mode][jinja2-mode]]:
|
||||
#+begin_src emacs-lisp
|
||||
(use-package jinja2-mode
|
||||
:mode (rx ".j2" string-end))
|
||||
(use-package jinja2-mode
|
||||
:mode (rx ".j2" string-end))
|
||||
#+end_src
|
||||
|
||||
Do I consider all YAML files an Ansible file needing [[https://github.com/k1LoW/emacs-ansible][ansible-mode]]?
|
||||
|
@ -382,7 +456,7 @@ The [[help:ansible-vault-password-file][ansible-vault-password-file]] variable n
|
|||
|
||||
#+end_src
|
||||
|
||||
However, let’s have all YAML files able to access Ansible’s documentation using the [[https://github.com/emacsorphanage/ansible-doc][ansible-doc]] project:
|
||||
The YAML files get access Ansible’s documentation using the [[https://github.com/emacsorphanage/ansible-doc][ansible-doc]] project:
|
||||
#+begin_src emacs-lisp
|
||||
(use-package ansible-doc
|
||||
:hook (yaml-mode . ansible-doc-mode)
|
||||
|
@ -403,6 +477,19 @@ The [[https://github.com/emacsmirror/poly-ansible][poly-ansible]] project uses [
|
|||
(poly-ansible-mode . font-lock-update)))
|
||||
#+end_src
|
||||
|
||||
Can we integrate Ansible with LSP using [[https://github.com/ansible/ansible-language-server][ansible-language-server]] project (see [[https://emacs-lsp.github.io/lsp-mode/page/lsp-ansible/][this documentation]])?
|
||||
|
||||
First, use =npm= to install the program:
|
||||
#+begin_src sh
|
||||
npm installl -g @ansible/ansible-language-server
|
||||
#+end_src
|
||||
|
||||
Let’s assume that all YAML files can have access to this:
|
||||
#+begin_src emacs-lisp
|
||||
(use-package eglot
|
||||
:config
|
||||
(add-to-list 'eglot-server-programs '(yaml-mode "ansible-language-server" "--stdio")))
|
||||
#+end_src
|
||||
** Shell Scripts
|
||||
While I don't like writing them, I can't get away from them. Check out the goodies in [[https://www.youtube.com/watch?v=LTC6SP7R1hA&t=5s][this video]].
|
||||
|
||||
|
|
Loading…
Reference in a new issue