feat(rust): add treesit support

This commit is contained in:
Henrik Lissner
2025-08-27 00:47:36 +02:00
parent 3b58741522
commit 086a0d30d0
3 changed files with 60 additions and 28 deletions

View File

@@ -26,6 +26,7 @@ e.g. ~cargo~.
editing. Requires [[doom-module::tools tree-sitter]]. editing. Requires [[doom-module::tools tree-sitter]].
** Packages ** Packages
- [[doom-package:rust-mode]]
- [[doom-package:rustic]] - [[doom-package:rustic]]
** Hacks ** Hacks

View File

@@ -8,15 +8,46 @@
;; ;;
;;; Packages ;;; Packages
(use-package! rustic ;; HACK: `rust-mode' and `rustic' add entries to `auto-mode-alist', but package
;; load order makes which gets precedence unpredictable. By removing them
;; early, we rely on our own entries in `auto-mode-alist' and
;; `major-mode-remap-defaults' to ensure correct order.
(cl-callf2 rassq-delete-all 'rust-mode auto-mode-alist)
(cl-callf2 rassq-delete-all 'rustic-mode auto-mode-alist)
(use-package! rust-mode
:mode ("\\.rs\\'" . rust-mode) :mode ("\\.rs\\'" . rust-mode)
:mode ("\\.rs\\'" . rustic-mode) :defer t
:preface :preface
;; HACK: `rust-mode' and `rustic' add entries to `auto-mode-alist', but ;; Ensure rust-mode derives from rust-ts-mode, b/c rustic-mode derives from
;; package load order makes which gets precedence unpredictable. By removing ;; rust-mode. This way, rustic-mode is the only major mode we have to worry
;; them early, we rely on the `:mode' directives above to re-insert them ;; about.
;; with the correct order. (setq rust-mode-treesitter-derive (modulep! +tree-sitter))
(setq auto-mode-alist (assoc-delete-all "\\.rs\\'" auto-mode-alist))
:config
(setq rust-indent-method-chain t)
;; Load order is important for these two packages.
(let (auto-mode-alist)
(require 'rustic-mode nil t)))
(use-package! rust-ts-mode
:when (modulep! +tree-sitter)
:when (fboundp 'rust-ts-mode) ; 29.1+ only
:defer t
:init
(set-tree-sitter! 'rust-mode 'rust-ts-mode 'rust)
(add-to-list 'major-mode-remap-defaults '(rust-mode . rust-ts-mode) t))
(use-package! rustic
:defer t
:preface
(unless (assq 'rust-mode major-mode-remap-defaults)
(add-to-list 'major-mode-remap-defaults '(rust-mode . rustic-mode)))
;; HACK `rustic' sets up some things too early. I'd rather disable it and let ;; HACK `rustic' sets up some things too early. I'd rather disable it and let
;; our respective modules standardize how they're initialized. ;; our respective modules standardize how they're initialized.
@@ -27,21 +58,20 @@
(remove-hook 'rustic-mode-hook #'flycheck-mode) (remove-hook 'rustic-mode-hook #'flycheck-mode)
(remove-hook 'rustic-mode-hook #'flymake-mode-off) (remove-hook 'rustic-mode-hook #'flymake-mode-off)
(remove-hook 'flycheck-mode-hook #'rustic-flycheck-setup)) (remove-hook 'flycheck-mode-hook #'rustic-flycheck-setup))
:init :init
;; HACK Certainly, `rustic-babel' does this, but the package (and many other ;; HACK Certainly, `rustic-babel' does this, but the package (and many other
;; rustic packages) must be loaded in order for them to take effect. To lazy ;; rustic packages) must be loaded in order for them to take effect. To lazy
;; load it all, we must do it early: ;; load it all, it must be done earlier:
(after! org-src (after! org-src
(defalias 'org-babel-execute:rust #'org-babel-execute:rustic) (defalias 'org-babel-execute:rust #'org-babel-execute:rustic)
(add-to-list 'org-src-lang-modes '("rust" . rustic))) (add-to-list 'org-src-lang-modes '("rust" . rustic)))
:config :config
(add-hook 'rustic-mode-hook #'rainbow-delimiters-mode)
(set-docsets! 'rustic-mode "Rust") (set-docsets! 'rustic-mode "Rust")
(set-popup-rule! "^\\*rustic-compilation" :vslot -1) (set-popup-rule! "^\\*rustic-compilation" :vslot -1)
(set-popup-rule! "^\\*cargo-run" :vslot -1) (set-popup-rule! "^\\*cargo-run" :vslot -1)
(setq rustic-indent-method-chain t)
;; Leave automatic reformatting to the :editor format module. ;; Leave automatic reformatting to the :editor format module.
(setq rustic-babel-format-src-block nil (setq rustic-babel-format-src-block nil
rustic-format-trigger nil) rustic-format-trigger nil)
@@ -60,7 +90,7 @@
;; response of Rust Analyzer, which is not stable enough for `lsp-mode' ;; response of Rust Analyzer, which is not stable enough for `lsp-mode'
;; maintainers (see emacs-lsp/lsp-mode#1740). ;; maintainers (see emacs-lsp/lsp-mode#1740).
(unless (modulep! :tools lsp +eglot) (unless (modulep! :tools lsp +eglot)
(defadvice! +rust--dont-cache-results-from-ra-a (fn &rest args) (defadvice! +rust--dont-cache-results-from-ra-a (&rest _)
:after #'lsp-eldoc-function :after #'lsp-eldoc-function
(when (derived-mode-p 'rust-mode 'rust-ts-mode) (when (derived-mode-p 'rust-mode 'rust-ts-mode)
(setq lsp--hover-saved-bounds nil))) (setq lsp--hover-saved-bounds nil)))
@@ -84,9 +114,6 @@
(s-join " ")))) (s-join " "))))
(lsp--render-element (concat "```rust\n" sig cmt "\n```")))))) (lsp--render-element (concat "```rust\n" sig cmt "\n```"))))))
(when (modulep! +tree-sitter)
(add-hook 'rustic-mode-local-vars-hook #'tree-sitter! 'append))
;; HACK If lsp/eglot isn't available, it attempts to install lsp-mode via ;; HACK If lsp/eglot isn't available, it attempts to install lsp-mode via
;; package.el. Doom manages its own dependencies through straight so disable ;; package.el. Doom manages its own dependencies through straight so disable
;; this behavior to avoid package-not-initialized errors. ;; this behavior to avoid package-not-initialized errors.
@@ -97,17 +124,17 @@
(map! :map rustic-mode-map (map! :map rustic-mode-map
:localleader :localleader
(:prefix ("b" . "build") (:prefix ("b" . "build")
:desc "cargo audit" "a" #'+rust/cargo-audit :desc "cargo audit" "a" #'+rust/cargo-audit
:desc "cargo build" "b" #'rustic-cargo-build :desc "cargo build" "b" #'rustic-cargo-build
:desc "cargo bench" "B" #'rustic-cargo-bench :desc "cargo bench" "B" #'rustic-cargo-bench
:desc "cargo check" "c" #'rustic-cargo-check :desc "cargo check" "c" #'rustic-cargo-check
:desc "cargo clippy" "C" #'rustic-cargo-clippy :desc "cargo clippy" "C" #'rustic-cargo-clippy
:desc "cargo doc" "d" #'rustic-cargo-build-doc :desc "cargo doc" "d" #'rustic-cargo-build-doc
:desc "cargo doc --open" "D" #'rustic-cargo-doc :desc "cargo doc --open" "D" #'rustic-cargo-doc
:desc "cargo fmt" "f" #'rustic-cargo-fmt :desc "cargo fmt" "f" #'rustic-cargo-fmt
:desc "cargo new" "n" #'rustic-cargo-new :desc "cargo new" "n" #'rustic-cargo-new
:desc "cargo outdated" "o" #'rustic-cargo-outdated :desc "cargo outdated" "o" #'rustic-cargo-outdated
:desc "cargo run" "r" #'rustic-cargo-run) :desc "cargo run" "r" #'rustic-cargo-run)
(:prefix ("t" . "cargo test") (:prefix ("t" . "cargo test")
:desc "all" "a" #'rustic-cargo-test :desc "all" "a" #'rustic-cargo-test
:desc "current test" "t" #'rustic-cargo-current-test))) :desc "current test" "t" #'rustic-cargo-current-test)))

View File

@@ -9,6 +9,10 @@
(modulep! :tools tree-sitter)) (modulep! :tools tree-sitter))
"This module requires (:tools tree-sitter)") "This module requires (:tools tree-sitter)")
(assert! (or (not (modulep! +tree-sitter))
(fboundp 'rust-ts-mode))
"Can't find `rust-ts-mode'; Emacs 29.1+ is required")
(unless (executable-find "rustc") (unless (executable-find "rustc")
(warn! "Couldn't find rustc binary")) (warn! "Couldn't find rustc binary"))