Files
.emacs.d/lisp/init-lsp.el
2026-04-02 19:21:30 +11:00

185 lines
7.9 KiB
EmacsLisp

;; -*- lexical-binding: t; -*-
;; LSP booster
(use-package lsp-mode
:diminish
:defines (lsp-diagnostics-disabled-modes lsp-clients-python-library-directories)
:autoload lsp-enable-which-key-integration
:commands (lsp-format-buffer lsp-organize-imports lsp lsp-deferred)
:hook ((prog-mode . (lambda ()
(unless (derived-mode-p
'emacs-lisp-mode 'lisp-mode
'makefile-mode 'snippet-mode
'ron-mode)
(lsp-deferred))))
((markdown-mode yaml-mode yaml-ts-mode) . lsp-deferred)
(lsp-mode . (lambda ()
;; Integrate `which-key'
(lsp-enable-which-key-integration)
;; (add-hook 'before-save-hook #'lsp-format-buffer t t)
(add-hook 'before-save-hook #'lsp-organize-imports t t))))
:bind (:map lsp-mode-map
("C-c c d" . lsp-describe-thing-at-point)
([remap xref-find-definitions] . lsp-find-definition)
([remap xref-find-references] . lsp-find-references))
:init (setq lsp-use-plists t
lsp-log-io nil
lsp-enable-suggest-server-download t
;; lsp-auto-configure t
lsp-keymap-prefix "C-c c"
lsp-keep-workspace-alive nil
lsp-signature-auto-activate nil
lsp-modeline-code-actions-enable nil
lsp-modeline-diagnostics-enable nil
lsp-modeline-workspace-status-enable nil
lsp-completion-enable t
lsp-completion-provider :none ;; using corfu
lsp-completion-enable-additional-text-edit t
lsp-enable-snippet t
lsp-completion-show-kind t
lsp-semantic-tokens-enable t
lsp-progress-spinner-type 'progress-bar-filled
lsp-enable-file-watchers nil
lsp-enable-folding nil
lsp-enable-symbol-highlighting nil
lsp-enable-text-document-color nil
lsp-enable-imenu t
lsp-enable-indentation nil
lsp-enable-on-type-formatting nil
;; For diagnostics
lsp-diagnostics-disabled-modes '(markdown-mode gfm-mode))
:config
(with-no-warnings
;; Disable `lsp-mode' in `git-timemachine-mode'
(defun my/lsp--init-if-visible (fn &rest args)
(unless (bound-and-true-p git-timemachine-mode)
(apply fn args)))
(advice-add #'lsp--init-if-visible :around #'my/lsp--init-if-visible))
;; Enable `lsp-mode' in sh/bash/zsh
(defun my/lsp-bash-check-sh-shell (&rest _)
(and (memq major-mode '(sh-mode bash-ts-mode))
(memq sh-shell '(sh bash zsh))))
(advice-add #'lsp-bash-check-sh-shell :override #'my/lsp-bash-check-sh-shell)
(add-to-list 'lsp-language-id-configuration '(bash-ts-mode . "shellscript"))
:preface
(defun lsp-booster--advice-json-parse (old-fn &rest args)
"Try to parse bytecode instead of json."
(or
(when (equal (following-char) ?#)
(let ((bytecode (read (current-buffer))))
(when (byte-code-function-p bytecode)
(funcall bytecode))))
(apply old-fn args)))
(advice-add (if (progn (require 'json)
(fboundp 'json-parse-buffer))
'json-parse-buffer
'json-read)
:around
#'lsp-booster--advice-json-parse)
(defun lsp-booster--advice-final-command (old-fn cmd &optional test?)
"Prepend emacs-lsp-booster command to lsp CMD."
(let ((orig-result (funcall old-fn cmd test?)))
(if (and (not test?) ;; for check lsp-server-present?
(not (file-remote-p default-directory)) ;; see lsp-resolve-final-command, it would add extra shell wrapper
lsp-use-plists
(not (functionp 'json-rpc-connection)) ;; native json-rpc
(executable-find "emacs-lsp-booster"))
(progn
(when-let ((command-from-exec-path (executable-find (car orig-result)))) ;; resolve command from exec-path (in case not found in $PATH)
(setcar orig-result command-from-exec-path))
(message "Using emacs-lsp-booster for %s!" orig-result)
(append (list "emacs-lsp-booster" "--") orig-result))
orig-result)))
(advice-add 'lsp-resolve-final-command :around #'lsp-booster--advice-final-command)
)
(use-package consult-lsp
:bind (:map lsp-mode-map
("C-M-." . consult-lsp-symbols)))
(use-package lsp-ui
:custom-face
(lsp-ui-sideline-code-action ((t (:inherit warning))))
:pretty-hydra
((:color amaranth :quit-key ("q" "C-g"))
("Doc"
(("d e" (progn
(lsp-ui-doc-enable (not lsp-ui-doc-mode))
(setq lsp-ui-doc-enable (not lsp-ui-doc-enable)))
"enable" :toggle lsp-ui-doc-mode)
("d s" (setq lsp-ui-doc-include-signature (not lsp-ui-doc-include-signature))
"signature" :toggle lsp-ui-doc-include-signature)
("d t" (setq lsp-ui-doc-position 'top)
"top" :toggle (eq lsp-ui-doc-position 'top))
("d b" (setq lsp-ui-doc-position 'bottom)
"bottom" :toggle (eq lsp-ui-doc-position 'bottom))
("d p" (setq lsp-ui-doc-position 'at-point)
"at point" :toggle (eq lsp-ui-doc-position 'at-point))
("d h" (setq lsp-ui-doc-header (not lsp-ui-doc-header))
"header" :toggle lsp-ui-doc-header)
("d f" (setq lsp-ui-doc-alignment 'frame)
"align frame" :toggle (eq lsp-ui-doc-alignment 'frame))
("d w" (setq lsp-ui-doc-alignment 'window)
"align window" :toggle (eq lsp-ui-doc-alignment 'window)))
"Sideline"
(("s e" (progn
(lsp-ui-sideline-enable (not lsp-ui-sideline-mode))
(setq lsp-ui-sideline-enable (not lsp-ui-sideline-enable)))
"enable" :toggle lsp-ui-sideline-mode)
("s h" (setq lsp-ui-sideline-show-hover (not lsp-ui-sideline-show-hover))
"hover" :toggle lsp-ui-sideline-show-hover)
("s d" (setq lsp-ui-sideline-show-diagnostics (not lsp-ui-sideline-show-diagnostics))
"diagnostics" :toggle lsp-ui-sideline-show-diagnostics)
("s s" (setq lsp-ui-sideline-show-symbol (not lsp-ui-sideline-show-symbol))
"symbol" :toggle lsp-ui-sideline-show-symbol)
("s c" (setq lsp-ui-sideline-show-code-actions (not lsp-ui-sideline-show-code-actions))
"code actions" :toggle lsp-ui-sideline-show-code-actions)
("s i" (setq lsp-ui-sideline-ignore-duplicate (not lsp-ui-sideline-ignore-duplicate))
"ignore duplicate" :toggle lsp-ui-sideline-ignore-duplicate))
"Action"
(("h" backward-char "")
("j" next-line "")
("k" previous-line "")
("l" forward-char "")
("C-a" mwim-beginning-of-code-or-line nil)
("C-e" mwim-end-of-code-or-line nil)
("C-b" backward-char nil)
("C-n" next-line nil)
("C-p" previous-line nil)
("C-f" forward-char nil)
("M-b" backward-word nil)
("M-f" forward-word nil)
("c" lsp-ui-sideline-apply-code-actions "apply code actions"))))
:bind (("C-c u" . lsp-ui-imenu)
:map lsp-ui-mode-map
("M-<f6>" . lsp-ui-hydra/body)
("s-<return>" . lsp-ui-sideline-apply-code-actions)
([remap xref-find-definitions] . lsp-ui-peek-find-definitions)
([remap xref-find-references] . lsp-ui-peek-find-references))
:hook ((lsp-mode . lsp-ui-mode)
(after-load-theme . lsp-ui-set-doc-border))
:init
(setq lsp-ui-sideline-show-diagnostics nil
lsp-ui-sideline-ignore-duplicate t
lsp-ui-doc-delay 0.1
lsp-ui-doc-show-with-cursor (not (display-graphic-p))
lsp-ui-imenu-auto-refresh 'after-save
lsp-ui-imenu-colors `(,(face-foreground 'font-lock-keyword-face)
,(face-foreground 'font-lock-string-face)
,(face-foreground 'font-lock-constant-face)
,(face-foreground 'font-lock-variable-name-face))))
(provide 'init-lsp)