;;; 15-lsp.el --- Setup LSP -*- no-byte-compile: t; lexical-binding: t; -*- ;;; Commentary: ;; Despite the name, this file not only sets up LSP integration, but ;; also native Emacs modes for various programming lanuguages, such as ;; Prolog, that do not use LSP. ;;; Code: ;; This package provides syntax highlighting and some utilities for ;; working with rust code. (use-package rust-mode :ensure t :defer t :commands (rust-mode)) (add-hook 'rust-mode-hook #'eglot-ensure) ;; Clippy backend for flymake so we get propa error reporting in Rust (use-package flymake-clippy :hook (rust-mode . flymake-clippy-setup-backend)) (defun manually-activate-flymake () (add-hook 'flymake-diagnostic-functions #'eglot-flymake-backend nil t) (flymake-mode 1)) ;; Eglot is the built-in LSP client. (use-package eglot :ensure nil :defer t :commands (eglot eglot-rename eglot-ensure eglot-rename eglot-format-buffer) :hook ((eglot-managed-mode . manually-activate-flymake)) :custom (eglot-report-progress nil) ; Prevent minibuffer spam :config (add-to-list 'eglot-server-programs '((rust-mode) . ("rust-analyzer" :initializationOptions ( :procMacro (:enable t) :cargo ( :buildScripts (:enable t) ))))) (add-to-list 'eglot-server-programs '(nix-mode . ("nil"))) (add-to-list 'eglot-stay-out-of 'flymake) ;; Optimizations (fset #'jsonrpc--log-event #'ignore) (setq jsonrpc-event-hook nil) ) ;; This function raises the window to the front using KDE KWin. (defun my-raise-window () "Raises the window to the front using KDE KWin. Won't work if the script is not there." (call-process-shell-command "~/wayland-window -f emacs &" nil 0)) ;; Usually, when I open a file with emacsclient and the frame already exists, I ;; want it to be raised to the top. Unfortunately, that does not happen by ;; default. Here is my solution. (add-hook 'server-visit-hook #'my-raise-window) ;; This package provides syntax highlighting for gdscript. (use-package gdscript-mode :ensure t :defer t :commands (gdscript-mode)) (add-hook 'gdscript-mode-hook #'eglot-ensure) ;; This package provides integration with Prolog (SWI). (use-package sweeprolog :straight (sweeprolog :type git :host nil :repo "https://git.sr.ht/~eshel/sweep" :branch "main" :files ("*.el" "sweep.pl" "sweep.texi")) ; Custom recipe because ; the normal one did not ; build properly. :ensure t :defer t :commands (sweeprolog-mode sweeprolog-top-level) :init (setq sweeprolog-swipl-path "swipl")) ;; This package provides integration with Prolog (scryer) Note that editing ;; prolog is supported through built-in prolog-mode, this only allows actually ;; consulting prolog from within emacs. (use-package ediprolog :ensure t :defer t :commands (prolog-mode) :config (my-ediprolog-select-system "swi-prolog")) (defun ediprolog-set-term-type (orig &rest args) "Advice to set the TERM env var to dumb for the function call. Originally created for scryer prolog, as either it itself or systemd-run used to constrain its resources assumed that the terminal supports escape codes (it does not in this case), so this was used as an \":around\" advice on 'ediprolog-run-prolog', to clearly indicate that control codes are not supported." (let ((process-environment process-environment)) (setenv "TERM" "dumb") (apply orig args))) (with-eval-after-load "prolog" (bind-key "C-c C-e" #'ediprolog-dwim prolog-mode-map) (advice-add 'ediprolog-run-prolog :around #'ediprolog-set-term-type)) (add-to-list 'auto-mode-alist '("\\.plt?\\'" . prolog-mode)) (add-to-list 'auto-mode-alist '("\\.axaml?\\'" . nxml-mode)) ;; Nix language (use-package nix-mode :ensure t :defer t :commands (nix-mode) :hook (nix-mode . eglot-ensure)) ;; Common Lisp (use-package sly :ensure t :defer t :commands (sly) :init (setq inferior-lisp-program "sbcl")) ;; Racket lisp (use-package racket-mode :ensure t :defer t :commands (racket-mode racket-xp-mode) :hook ((racket-mode . racket-xp-mode)) :bind (("C-c C-n" . racket-run-and-switch-to-repl)) :config (setq racket-xp-eldoc-level 'summary)) (defun racket-restart () "Restarts the backend and reinitializes the mode to cope with the consequences of direnv activating after racket-mode(-s)." (interactive) (when (eq major-mode 'racket-mode) (racket-stop-back-end) (racket-start-back-end) (racket-mode))) ;; Markdown (use-package markdown-mode :ensure t :defer t) (if (memq 'lispy-autoloads features) (add-hook 'emacs-lisp-mode-hook (lambda () (lispy-mode 1)))) ;; This package adds indent bars. Currently only configured for rust and python. (use-package indent-bars :ensure t :defer t :custom (indent-bars-no-descend-lists t) ; no extra bars in continued func arg lists (indent-bars-treesit-support t) (indent-bars-treesit-ignore-blank-lines-types '("module")) ;; Add other languages as needed (indent-bars-treesit-scope '((python function_definition class_definition for_statement if_statement with_statement while_statement) (rust trait_item impl_item macro_definition macro_invocation struct_item enum_item mod_item const_item let_declaration function_item for_expression if_expression loop_expression while_expression match_expression match_arm call_expression token_tree token_tree_pattern token_repetition))) (indent-bars-treesit-wrap '((rust arguments parameters))) :hook ((python-base-mode yaml-mode rust-mode) . indent-bars-mode)) ;; Configure Tempel (use-package tempel :bind (("C-S-e" . tempel-complete) ;; Alternative tempel-expand ("M-*" . tempel-insert)) :init ;; Setup completion at point (defun tempel-setup-capf () ;; Add the Tempel Capf to `completion-at-point-functions'. `tempel-expand' ;; only triggers on exact matches. We add `tempel-expand' *before* the main ;; programming mode Capf, such that it will be tried first. (setq-local completion-at-point-functions (cons #'tempel-expand completion-at-point-functions)) ;; Alternatively use `tempel-complete' if you want to see all matches. Use ;; a trigger prefix character in order to prevent Tempel from triggering ;; unexpectly. ;; (setq-local corfu-auto-trigger "/" ;; completion-at-point-functions ;; (cons (cape-capf-trigger #'tempel-complete ?/) ;; completion-at-point-functions)) ) (add-hook 'conf-mode-hook 'tempel-setup-capf) (add-hook 'prog-mode-hook 'tempel-setup-capf) (add-hook 'text-mode-hook 'tempel-setup-capf) (setq tempel-path (concat minimal-emacs-user-directory "templates")) ;; Optionally make the Tempel templates available to Abbrev, ;; either locally or globally. `expand-abbrev' is bound to C-x '. ;; (add-hook 'prog-mode-hook #'tempel-abbrev-mode) ;; (global-tempel-abbrev-mode) ) ;; Optional: Add tempel-collection if you want ready-made templates. Yes sir, I ;; do. (use-package tempel-collection) ;;; 15-lsp.el end here