diff --git a/lisp/doom-compat.el b/lisp/doom-compat.el index f367a0727..1584811f7 100644 --- a/lisp/doom-compat.el +++ b/lisp/doom-compat.el @@ -109,23 +109,6 @@ and return the value found in PLACE instead." (unless (fboundp 'pos-bol) (defalias 'pos-bol #'line-beginning-position)) (unless (fboundp 'pos-eol) (defalias 'pos-eol #'line-end-position)) -;; Introduced in 29.1 -(unless (boundp 'major-mode-remap-alist) - (defvar major-mode-remap-alist nil) - (defvar-local set-auto-mode--last nil) - (define-advice set-auto-mode-0 (:override (mode &optional keep-mode-if-same) backport-major-mode-remap) - (unless (and keep-mode-if-same - (or (eq (indirect-function mode) - (indirect-function major-mode)) - (and set-auto-mode--last - (eq mode (car set-auto-mode--last)) - (eq major-mode (cdr set-auto-mode--last))))) - (when mode - (funcall (major-mode-remap mode)) - (unless (eq mode major-mode) - (setq set-auto-mode--last (cons mode major-mode))) - mode)))) - ;; Introduced in 29.1 (unless (boundp 'enable-theme-functions) (defcustom enable-theme-functions nil @@ -153,12 +136,26 @@ The functions in the hook are called with one parameter -- the ;;; From Emacs >= 30 ;; Introduced in 30.1 (unless (fboundp 'major-mode-remap) + (defvar major-mode-remap-alist nil) ; introduced in 29.1 (defvar major-mode-remap-defaults nil) (defun major-mode-remap (mode) "Return the function to use to enable MODE." (or (cdr (or (assq mode major-mode-remap-alist) (assq mode major-mode-remap-defaults))) - mode))) + mode)) + (defvar-local set-auto-mode--last nil) + (define-advice set-auto-mode-0 (:override (mode &optional keep-mode-if-same) backport-major-mode-remap) + (unless (and keep-mode-if-same + (or (eq (indirect-function mode) + (indirect-function major-mode)) + (and set-auto-mode--last + (eq mode (car set-auto-mode--last)) + (eq major-mode (cdr set-auto-mode--last))))) + (when mode + (funcall (major-mode-remap mode)) + (unless (eq mode major-mode) + (setq set-auto-mode--last (cons mode major-mode))) + mode)))) ;; Introduced in 30.1 (unless (boundp 'safe-local-variable-directories) diff --git a/modules/editor/fold/autoload/fold.el b/modules/editor/fold/autoload/fold.el index de31a5711..e6dd63241 100644 --- a/modules/editor/fold/autoload/fold.el +++ b/modules/editor/fold/autoload/fold.el @@ -41,10 +41,11 @@ Return non-nil if successful in doing so." (end-of-line) (+fold--hideshow-fold-p))))))) -;; NOTE: does this need more? -(defun +fold--ts-fold-p () - (and (bound-and-true-p tree-sitter-mode) - (featurep 'ts-fold))) +(defun +fold--treesit-fold-p () + (and (treesit-available-p) + (treesit-parser-list) + (require 'treesit-fold nil t) + (treesit-fold-usable-mode-p))) (defun +fold--invisible-points (count) (let (points) @@ -102,18 +103,17 @@ Return non-nil if successful in doing so." ov (hs-overlay-at start))) (when ov (list (cons (overlay-start ov) (overlay-end ov)))))) - (when (+fold--ts-fold-p) - (when-let* ((node (ts-fold--foldable-node-at-pos)) - (beg (tsc-node-start-position node)) - (end (tsc-node-end-position node))) + (when (+fold--treesit-fold-p) + (when-let* ((node (treesit-fold--foldable-node-at-pos)) + (beg (treesit-node-start node)) + (end (treesit-node-end node))) (list (cons beg end))))))) (defun +fold--open-rec-between (beg end) "Recursively open all folds betwen BEG and END." (when (featurep 'vimish-fold) ;; from `vimish-fold-unfold-all' - (mapc #'vimish-fold--unfold - (vimish-fold--folds-in beg end))) + (mapc #'vimish-fold--unfold (vimish-fold--folds-in beg end))) (and (+fold--outline-fold-p) (outline-show-subtree)) (hs-life-goes-on @@ -121,13 +121,13 @@ Return non-nil if successful in doing so." (let ((hs-allow-nesting nil)) (hs-discard-overlays beg end)) (run-hooks 'hs-show-hook)) - (when (bound-and-true-p ts-fold-mode) - ;; from `ts-fold-open-all' - (ts-fold--ensure-ts + (when (+fold--treesit-fold-p) + (treesit-fold--ensure-ts + ;; from `ts-fold-open-all' (thread-last (overlays-in beg end) (seq-filter (lambda (ov) - (eq (overlay-get ov 'invisible) 'ts-fold))) + (eq (overlay-get ov 'invisible) 'treesit-fold))) (mapc #'delete-overlay))))) ;; @@ -146,7 +146,7 @@ Targets `vimmish-fold', `hideshow', `ts-fold' and `outline' folds." (symbol-function #'outline-hide-entry))) (outline-toggle-children))) ((+fold--hideshow-fold-p) (+fold-from-eol (hs-toggle-hiding))) - ((+fold--ts-fold-p) (ts-fold-toggle))))) + ((+fold--treesit-fold-p) (treesit-fold-toggle))))) ;;;###autoload (defun +fold/open-rec () @@ -169,7 +169,7 @@ Targets `vimmish-fold', `hideshow', `ts-fold' and `outline' folds." (outline-show-branches) (outline-show-entry)) ((+fold--hideshow-fold-p) (+fold-from-eol (hs-show-block))) - ((+fold--ts-fold-p) (ts-fold-open))))) + ((+fold--treesit-fold-p) (treesit-fold-open))))) ;;;###autoload (defun +fold/close () @@ -181,15 +181,15 @@ Targets `vimmish-fold', `hideshow', `ts-fold' and `outline' folds." (cond ((+fold--vimish-fold-p) (vimish-fold-refold)) ((+fold--outline-fold-p) (outline-hide-subtree)) ((+fold--hideshow-fold-p) (+fold-from-eol (hs-hide-block))) - ((+fold--ts-fold-p) (ts-fold-close))))) + ((+fold--treesit-fold-p) (treesit-fold-close))))) ;;;###autoload (defun +fold/open-all (&optional level) "Open folds at LEVEL (or all folds if LEVEL is nil)." (interactive (list (if current-prefix-arg (prefix-numeric-value current-prefix-arg)))) - (cond ((+fold--ts-fold-p) - (ts-fold-open-all)) + (cond ((+fold--treesit-fold-p) + (treesit-fold-open-all)) ((and (featurep 'vimish-fold) (+fold--vimish-fold-p)) (vimish-fold-unfold-all)) ((save-excursion @@ -209,20 +209,19 @@ Targets `vimmish-fold', `hideshow', `ts-fold' and `outline' folds." (interactive (list (if current-prefix-arg (prefix-numeric-value current-prefix-arg)))) (save-excursion - (if (+fold--ts-fold-p) - (ts-fold-close-all) - (progn - (when (featurep 'vimish-fold) - (vimish-fold-refold-all)) - (when (+fold--ensure-hideshow-mode) - (hs-life-goes-on - (if (integerp level) - (hs-hide-level-recursive level (point-min) (point-max)) - (hs-hide-all)))) - (if (integerp level) - (outline--show-headings-up-to-level level) - (when (fboundp 'outline-hide-sublevels) - (outline-show-only-headings))))))) + (if (+fold--treesit-fold-p) + (treesit-fold-close-all) + (when (featurep 'vimish-fold) + (vimish-fold-refold-all)) + (when (+fold--ensure-hideshow-mode) + (hs-life-goes-on + (if (integerp level) + (hs-hide-level-recursive level (point-min) (point-max)) + (hs-hide-all)))) + (if (integerp level) + (outline--show-headings-up-to-level level) + (when (fboundp 'outline-hide-sublevels) + (outline-show-only-headings)))))) ;;;###autoload (defun +fold/next (count) @@ -260,8 +259,9 @@ region." (outline-end-of-heading)))) (point))) (lambda () - ;; ts-fold does not define movement functions so we need to do it ourselves - (when (+fold--ts-fold-p) + ;; {ts,treesit}-fold does not define movement functions so + ;; we need to do it ourselves + (when (+fold--treesit-fold-p) (let* ((arg-list (if (> count 0) ;; depending on direction we need to change the ranges (list (point) (point-max)) (list (point-min) (point)))) @@ -270,9 +270,11 @@ region." #'>)) (ovs (cl-remove-if-not (lambda (ov) - (eq (overlay-get ov 'creator) 'ts-fold)) - ;; `overlays-in' does not provide a list that is sorted - ;; (in the way we need it atleast) so we need to sort it based on direction + (eq (overlay-get ov 'creator) 'treesit-fold)) + ;; `overlays-in' does not provide a list + ;; that is sorted (in the way we need it + ;; atleast) so we need to sort it based on + ;; direction (cl-sort (apply #'overlays-in arg-list) comp-fun :key #'overlay-start)))) (if (and ovs (<= (abs count) (length ovs))) (goto-char (overlay-start (nth (- (abs count) 1) ovs)))))))) diff --git a/modules/editor/fold/config.el b/modules/editor/fold/config.el index c063ecef7..3212ae147 100644 --- a/modules/editor/fold/config.el +++ b/modules/editor/fold/config.el @@ -3,8 +3,7 @@ (defcustom +fold-ellipsis " [...] " "The ellipsis to show for ellided regions (folds). -`org-ellipsis', `truncate-string-ellipsis', and `ts-fold-replacement' are set to -this." +`org-ellipsis' and `truncate-string-ellipsis' are set to this." :type 'string :group '+fold) @@ -106,9 +105,8 @@ this." (vimish-fold-global-mode +1)) -(use-package! ts-fold - :when (modulep! :tools tree-sitter) - :after tree-sitter - :config - (setq ts-fold-replacement +fold-ellipsis) - (global-ts-fold-mode +1)) +;; Will be autoloaded by fold commands +(use-package! treesit-fold + :when (modulep! :tools tree-sitter -compat) + :defer t + :config (global-treesit-fold-mode +1)) diff --git a/modules/editor/fold/packages.el b/modules/editor/fold/packages.el index 7ae5c80f6..fb7d5fe88 100644 --- a/modules/editor/fold/packages.el +++ b/modules/editor/fold/packages.el @@ -7,5 +7,4 @@ (when (modulep! :editor evil) (package! evil-vimish-fold :pin "b6e0e6b91b8cd047e80debef1a536d9d49eef31a")) (when (modulep! :tools tree-sitter) - (package! ts-fold :pin "af50e738ea249a36f5aeca123c29dae946944b1e" - :recipe (:host github :repo "emacs-tree-sitter/ts-fold"))) + (package! treesit-fold :pin "6628b7cce585328e05d810b5505e4fdb9306f24f")) diff --git a/modules/lang/agda/config.el b/modules/lang/agda/config.el index fc6a6d863..1a9fe07ad 100644 --- a/modules/lang/agda/config.el +++ b/modules/lang/agda/config.el @@ -11,11 +11,7 @@ (set-lookup-handlers! 'agda2-mode :definition #'agda2-goto-definition-keyboard) - (when (modulep! +tree-sitter) - (set-tree-sitter-lang! 'agda2-mode 'agda) - (add-hook! '(agda-mode-local-vars-hook - agda2-mode-local-vars-hook) - :append #'tree-sitter!)) + ;; TODO: agda2-ts-mode (map! :map agda2-mode-map :localleader diff --git a/modules/lang/cc/autoload.el b/modules/lang/cc/autoload.el index e809ed225..24e5af191 100644 --- a/modules/lang/cc/autoload.el +++ b/modules/lang/cc/autoload.el @@ -54,32 +54,34 @@ preceded by the opening brace or a comma (disregarding whitespace in between)." This is meant to replace `c-or-c++-mode' (introduced in Emacs 26.1), which doesn't support specification of the fallback mode and whose heuristics are simpler." - (let ((base (file-name-sans-extension (buffer-file-name (buffer-base-buffer))))) - (cond ((file-exists-p! (or (concat base ".cpp") - (concat base ".cc"))) - (c++-mode)) - ((or (file-exists-p! (or (concat base ".m") - (concat base ".mm"))) - (+cc--re-search-for - (concat "^[ \t\r]*\\(?:" - "@\\(?:class\\|interface\\|property\\|end\\)\\_>" - "\\|#import +" - "\\|[-+] ([a-zA-Z0-9_]+)" + (funcall + (major-mode-remap + (let ((base (file-name-sans-extension (buffer-file-name (buffer-base-buffer))))) + (cond ((file-exists-p! (or (concat base ".cpp") + (concat base ".cc"))) + 'c++-mode) + ((or (file-exists-p! (or (concat base ".m") + (concat base ".mm"))) + (+cc--re-search-for + (concat "^[ \t\r]*\\(?:" + "@\\(?:class\\|interface\\|property\\|end\\)\\_>" + "\\|#import +" + "\\|[-+] ([a-zA-Z0-9_]+)" + "\\)"))) + 'objc-mode) + ((+cc--re-search-for + (let ((id "[a-zA-Z0-9_]+") (ws "[ \t\r]+") (ws-maybe "[ \t\r]*")) + (concat "^" ws-maybe "\\(?:" + "using" ws "\\(?:namespace" ws "std;\\|std::\\)" + "\\|" "namespace" "\\(?:" ws id "\\)?" ws-maybe "{" + "\\|" "class" ws id ws-maybe "[:{\n]" + "\\|" "template" ws-maybe "<.*>" + "\\|" "#include" ws-maybe "<\\(?:string\\|iostream\\|map\\)>" "\\)"))) - (objc-mode)) - ((+cc--re-search-for - (let ((id "[a-zA-Z0-9_]+") (ws "[ \t\r]+") (ws-maybe "[ \t\r]*")) - (concat "^" ws-maybe "\\(?:" - "using" ws "\\(?:namespace" ws "std;\\|std::\\)" - "\\|" "namespace" "\\(?:" ws id "\\)?" ws-maybe "{" - "\\|" "class" ws id ws-maybe "[:{\n]" - "\\|" "template" ws-maybe "<.*>" - "\\|" "#include" ws-maybe "<\\(?:string\\|iostream\\|map\\)>" - "\\)"))) - (c++-mode)) - ((functionp +cc-default-header-file-mode) - (funcall +cc-default-header-file-mode)) - ((c-mode))))) + 'c++-mode) + ((functionp +cc-default-header-file-mode) + +cc-default-header-file-mode) + ('c-mode)))))) (defun +cc-resolve-include-paths () (cl-loop with path = (or buffer-file-name default-directory) @@ -137,15 +139,6 @@ the children of class at point." ;; ;; Hooks -;;;###autoload -(defun +cc-fontify-constants-h () - "Better fontification for preprocessor constants" - (when (memq major-mode '(c-mode c++-mode)) - (font-lock-add-keywords - nil '(("\\<[A-Z]*_[0-9A-Z_]+\\>" . font-lock-constant-face) - ("\\<[A-Z]\\{3,\\}\\>" . font-lock-constant-face)) - t))) - (defvar +cc--project-includes-alist nil) ;;;###autoload (defun +cc-init-ffap-integration-h () diff --git a/modules/lang/cc/config.el b/modules/lang/cc/config.el index 49cfd6942..ffe67686e 100644 --- a/modules/lang/cc/config.el +++ b/modules/lang/cc/config.el @@ -25,16 +25,24 @@ This is ignored by ccls.") ;; set up before lsp is initialized. Also, we use local-vars hooks to ensure ;; these only run in their respective major modes, and not derived modes. :hook ((c-mode-local-vars c++-mode-local-vars objc-mode-local-vars) . +cc-init-ffap-integration-h) + :hook ((c-ts-mode-local-vars c++-ts-mode-local-vars) . +cc-init-ffap-integration-h) ;;; Improve fontification in C/C++ (also see `modern-cpp-font-lock') - :hook ((c-mode c++-mode) . +cc-fontify-constants-h) + :init + (when (modulep! +tree-sitter) + (set-tree-sitter! 'c-mode 'c-ts-mode + '((c :url "https://github.com/tree-sitter/tree-sitter-c"))) + (set-tree-sitter! 'c++-mode 'c++-ts-mode + '((cpp :url "https://github.com/tree-sitter/tree-sitter-cpp")))) :config - (set-docsets! 'c-mode "C") - (set-docsets! 'c++-mode "C++" "Boost") - (set-electric! '(c-mode c++-mode objc-mode java-mode) :chars '(?\n ?\} ?\{)) - (set-rotate-patterns! 'c++-mode + (set-docsets! '(c-mode c-ts-mode) "C") + (set-docsets! '(c++-mode c++-ts-mode) "C++" "Boost") + (set-electric! '(c-mode c++-mode objc-mode java-mode + c-ts-mode c++-ts-mode java-ts-mode) + :chars '(?\n ?\} ?\{)) + (set-rotate-patterns! '(c++-mode c++-ts-mode) :symbols '(("public" "protected" "private") ("class" "struct"))) - (set-ligatures! '(c-mode c++-mode) + (set-ligatures! '(c-mode c-ts-mode c++-mode c++-ts-mode) ;; Functional ;; :def "void " ;; Types @@ -53,11 +61,6 @@ This is ignored by ccls.") (add-to-list 'find-sibling-rules '("/\\([^/]+\\)\\.c\\(c\\|pp\\)?\\'" "\\1.h\\(h\\|pp\\)?\\'")) (add-to-list 'find-sibling-rules '("/\\([^/]+\\)\\.h\\(h\\|pp\\)?\\'" "\\1.c\\(c\\|pp\\)?\\'")) - (when (modulep! +tree-sitter) - (add-hook! '(c-mode-local-vars-hook - c++-mode-local-vars-hook) - :append #'tree-sitter!)) - ;; HACK Suppress 'Args out of range' error in when multiple modifications are ;; performed at once in a `c++-mode' buffer, e.g. with `iedit' or ;; multiple cursors. @@ -100,52 +103,77 @@ This is ignored by ccls.") (label . 0)))) (when (listp c-default-style) - (setf (alist-get 'other c-default-style) "doom")) - - (after! ffap - (add-to-list 'ffap-alist '(c-mode . ffap-c-mode)))) - - -(use-package! modern-cpp-font-lock - :unless (modulep! +tree-sitter) - :hook (c++-mode . modern-c++-font-lock-mode)) + (setf (alist-get 'other c-default-style) "doom"))) ;; ;; Major modes -(after! cmake-mode - (set-docsets! 'cmake-mode "CMake") +(use-package! cmake-mode + :defer t + :init + (when (and (modulep! +tree-sitter) + (boundp 'cmake-ts-mode)) ; 29+ only + (set-tree-sitter! 'cmake-mode 'cmake-ts-mode + '((cmake :url "https://github.com/uyha/tree-sitter-cmake")))) + :config + (set-docsets! '(cmake-mode cmake-ts-mode) "CMake") (set-popup-rule! "^\\*CMake Help\\*" :size 0.4 :ttl t) - (set-lookup-handlers! 'cmake-mode - :documentation '+cc-cmake-lookup-documentation-fn)) + (set-lookup-handlers! '(cmake-mode cmake-ts-mode) + :documentation '+cc-cmake-lookup-documentation-fn) + (when (require 'company-cmake nil t) + (set-company-backend! '(cmake-mode cmake-ts-mode) 'company-cmake)) + (when (modulep! +lsp) + (add-hook 'cmake-mode-local-vars-hook #'lsp! 'append) + (add-hook 'cmake-ts-mode-local-vars-hook #'lsp! 'append))) -(use-package! company-cmake ; for `cmake-mode' - :when (modulep! :completion company) - :after cmake-mode - :config (set-company-backend! 'cmake-mode 'company-cmake)) +(use-package! glsl-mode + :defer t + :init + (when (modulep! +tree-sitter) + (set-tree-sitter! 'glsl-mode 'glsl-ts-mode + '((glsl :url "https://github.com/tree-sitter-grammars/tree-sitter-glsl")))) + :config + (when (require 'company-glsl nil t) + (set-company-backend! 'glsl-mode 'company-glsl)) + (when (modulep! +lsp) + (add-hook 'glsl-mode-local-vars-hook #'lsp! 'append) + (add-hook 'glsl-ts-mode-local-vars-hook #'lsp! 'append))) + + +(use-package! cuda-mode + :defer t + :config + (when (modulep! +lsp) + (add-hook 'cuda-mode-local-vars-hook #'lsp! 'append)) + ) + + +(use-package! cuda-ts-mode + :when (modulep! +tree-sitter) + :defer t + :init + (set-tree-sitter! 'cuda-mode 'cuda-ts-mode + '((cuda :url "https://github.com/tree-sitter-grammars/tree-sitter-cuda"))) + :config + (when (modulep! +lsp) + (add-hook 'cuda-ts-mode-local-vars-hook #'lsp! 'append))) (use-package! demangle-mode :hook llvm-mode) -(use-package! company-glsl ; for `glsl-mode' - :when (modulep! :completion company) - :after glsl-mode - :config (set-company-backend! 'glsl-mode 'company-glsl)) - - ;; ;;; LSP (when (modulep! +lsp) (add-hook! '(c-mode-local-vars-hook + c-ts-mode-local-vars-hook c++-mode-local-vars-hook - objc-mode-local-vars-hook - cmake-mode-local-vars-hook - cuda-mode-local-vars-hook) + c++-ts-mode-local-vars-hook + objc-mode-local-vars-hook) :append #'lsp!) (if (modulep! :tools lsp -eglot) diff --git a/modules/lang/cc/packages.el b/modules/lang/cc/packages.el index cb969ca48..d54dfca01 100644 --- a/modules/lang/cc/packages.el +++ b/modules/lang/cc/packages.el @@ -4,13 +4,15 @@ (package! cmake-mode :recipe (:host github :repo "emacsmirror/cmake-mode" :files (:defaults "*")) :pin "b08b5d9045308362a623a4f576896d55ffecfd52") -(package! cuda-mode :pin "c3dae31b3d1abedf4d0b98840127e2cac73d6ad8") (package! demangle-mode :pin "04f545adab066708d6151f13da65aaf519f8ac4e") (package! disaster :pin "8b445913221feb0c196e943106643040118bcd77") (package! opencl-mode :pin "204d5d9e0f5cb2cbe810f2933230eb08fe2c7695") -(unless (modulep! +tree-sitter) - (package! modern-cpp-font-lock :pin "43c6b68ff58fccdf9deef11674a172e4eaa8455c")) +(when (package! cuda-mode :pin "c3dae31b3d1abedf4d0b98840127e2cac73d6ad8") + (when (modulep! +tree-sitter) + (package! cuda-ts-mode + :recipe (:host github :repo "Ergus/cuda-ts-mode") + :pin "807f15150deb3a3060bc36a0e135a27876d7e239"))) (when (package! glsl-mode :pin "86e6bb6cf28d1053366039683a4498401bab9c47") (when (modulep! :completion company) diff --git a/modules/lang/clojure/README.org b/modules/lang/clojure/README.org index d9d98d2e8..98d230eb4 100644 --- a/modules/lang/clojure/README.org +++ b/modules/lang/clojure/README.org @@ -27,7 +27,11 @@ This module adds support for the Clojure(Script) language. ** Packages - [[doom-package:cider]] - [[doom-package:clj-refactor]] +- [[doom-package:clojure-mode]] +- [[doom-package:clojure-ts-mode]] if [[doom-module:+tree-sitter]] - [[doom-package:flycheck-clj-kondo]] if [[doom-module::checkers syntax]] +- [[doom-package:jet]] +- [[doom-package:neil]] ** Hacks - Error messages emitted from CIDER are piped into the REPL buffer when it is diff --git a/modules/lang/clojure/config.el b/modules/lang/clojure/config.el index bdd79167e..5014e9d36 100644 --- a/modules/lang/clojure/config.el +++ b/modules/lang/clojure/config.el @@ -32,18 +32,30 @@ clojurec-mode clojurescript-mode clojurex-mode)) - (add-to-list 'lsp-language-id-configuration (cons m "clojure"))))) + (add-to-list 'lsp-language-id-configuration (cons m "clojure")))))) - (when (modulep! +tree-sitter) - (add-hook! '(clojure-mode-local-vars-hook - clojurec-mode-local-vars-hook - clojurescript-mode-local-vars-hook) - :append - #'tree-sitter!) - ;; TODO: PR this upstream - (after! tree-sitter-langs - (add-to-list 'tree-sitter-major-mode-language-alist '(clojurec-mode . clojure)) - (add-to-list 'tree-sitter-major-mode-language-alist '(clojurescript-mode . clojure))))) + +(use-package! clojure-ts-mode + :when (modulep! +tree-sitter) + :defer t + :init + (setq clojure-ts-auto-remap nil) ; we do it ourselves + (set-tree-sitter! 'clojure-mode 'clojure-ts-mode + '((clojure :url "https://github.com/sogaiu/tree-sitter-clojure"))) + (set-tree-sitter! 'clojurec-mode 'clojure-ts-clojurec-mode 'clojure) + (set-tree-sitter! 'clojuredart-mode 'clojure-ts-clojuredart-mode 'clojure) + (set-tree-sitter! 'clojurescript-mode 'clojure-ts-clojurescript-mode 'javascript) + (set-tree-sitter! 'jank-mode 'clojure-ts-jank-mode 'cpp) + (set-tree-sitter! 'joker-mode 'clojure-ts-joker-mode 'clojure) + :config + ;; HACK: Rely on `major-mode-remap-defaults' instead (upstream also doesn't + ;; check if the grammars are ready before adding these entries, which will + ;; bork clojure buffers. + (cl-callf2 rassq-delete-all 'clojure-ts-clojurescript-mode auto-mode-alist) + (cl-callf2 rassq-delete-all 'clojure-ts-clojurec-mode auto-mode-alist) + (cl-callf2 rassq-delete-all 'clojure-ts-clojuredart-mode auto-mode-alist) + (cl-callf2 rassq-delete-all 'clojure-ts-jank-mode auto-mode-alist) + (cl-callf2 rassq-delete-all 'clojure-ts-joker-mode auto-mode-alist)) ;; `cider-mode' is used instead of the typical `cider' package due to the main @@ -52,11 +64,18 @@ (use-package! cider-mode ;; NOTE if `org-directory' doesn't exist, `cider-jack' in won't work :hook (clojure-mode-local-vars . cider-mode) + :hook (clojure-ts-mode-local-vars . cider-mode) :init (after! clojure-mode - (set-repl-handler! '(clojure-mode clojurec-mode) #'+clojure/open-repl :persist t) - (set-repl-handler! 'clojurescript-mode #'+clojure/open-cljs-repl :persist t) - (set-eval-handler! '(clojure-mode clojurescript-mode clojurec-mode) #'cider-eval-region)) + (set-repl-handler! '(clojure-mode clojure-ts-mode + clojurec-mode clojure-ts-clojurec-mode) + #'+clojure/open-repl :persist t) + (set-repl-handler! '(clojurescript-mode clojure-ts-clojurescript-mode) + #'+clojure/open-cljs-repl :persist t) + (set-eval-handler! '(clojure-mode clojure-ts-mode + clojurescript-mode clojure-ts-clojurescript-mode + clojurec-mode clojure-ts-clojurec-mode) + #'cider-eval-region)) ;; HACK Fix radian-software/radian#446: CIDER tries to calculate the frame's ;; background too early; sometimes before the initial frame has been @@ -285,6 +304,7 @@ :when (or (modulep! -lsp) +clojure-load-clj-refactor-with-lsp) :hook (clojure-mode . clj-refactor-mode) + :hook (clojure-ts-mode . clj-refactor-mode) :config (set-lookup-handlers! 'clj-refactor-mode :references #'cljr-find-usages) diff --git a/modules/lang/clojure/doctor.el b/modules/lang/clojure/doctor.el index 22455011e..7238477ac 100644 --- a/modules/lang/clojure/doctor.el +++ b/modules/lang/clojure/doctor.el @@ -1,6 +1,10 @@ ;; -*- lexical-binding: t; no-byte-compile: t; -*- ;;; lang/clojure/doctor.el +(assert! (or (not (modulep! +tree-sitter)) + (modulep! :tools tree-sitter)) + "This module requires (:tools tree-sitter)") + (when (and (modulep! :checkers syntax) (modulep! -lsp)) (unless (executable-find "clj-kondo") diff --git a/modules/lang/clojure/packages.el b/modules/lang/clojure/packages.el index 4291a46ca..a18287185 100644 --- a/modules/lang/clojure/packages.el +++ b/modules/lang/clojure/packages.el @@ -15,6 +15,8 @@ ;;; Core packages (package! clojure-mode :pin "b766094aea28bdc7b44ce1960d96434fe7d1d9cf") +(when (modulep! +tree-sitter) + (package! clojure-ts-mode :pin "da56a6938f525c8ead1fb3d79eced4d892df1661")) (package! clj-refactor :pin "dc1bbc8cdaa723bdbb6669ea7d280625c370755d") (package! cider :pin "12f10a6f4b3052a9b437f92cf97d551a5964f4cb") (when (modulep! :checkers syntax -flymake) diff --git a/modules/lang/csharp/README.org b/modules/lang/csharp/README.org index fcde71183..6fdcd1498 100644 --- a/modules/lang/csharp/README.org +++ b/modules/lang/csharp/README.org @@ -18,7 +18,7 @@ LSP). (supports =omnisharp-roslyn=). - +tree-sitter :: Leverages tree-sitter for better syntax highlighting and structural text - editing. Requires [[doom-module::tools tree-sitter]]. + editing. Requires Emacs 29.1+ and [[doom-module::tools tree-sitter]]. - +unity :: Enable special support for the [[https://unity.com/][Unity game engine]] (particularly, support for HLSL shaders). diff --git a/modules/lang/csharp/config.el b/modules/lang/csharp/config.el index fbab79d0c..1b0dccd3f 100644 --- a/modules/lang/csharp/config.el +++ b/modules/lang/csharp/config.el @@ -1,15 +1,22 @@ ;;; lang/csharp/config.el -*- lexical-binding: t; -*- (use-package! csharp-mode + :hook (csharp-mode . rainbow-delimiters-mode) :defer t + :init + (when (modulep! +tree-sitter) + (set-tree-sitter! 'csharp-mode 'csharp-ts-mode + '((c-sharp :url "https://github.com/tree-sitter/tree-sitter-c-sharp" + :rev "v0.23.1" + :commit "362a8a41b265056592a0c3771664a21d23a71392")))) :config (set-formatter! 'csharpier '("csharpier" "format" "--write-stdout") - :modes '(csharp-mode)) - (set-electric! 'csharp-mode :chars '(?\n ?\})) - (set-rotate-patterns! 'csharp-mode + :modes '(csharp-mode csharp-ts-mode)) + (set-electric! '(csharp-mode csharp-ts-mode) :chars '(?\n ?\})) + (set-rotate-patterns! '(csharp-mode csharp-ts-mode) :symbols '(("public" "protected" "private") ("class" "struct"))) - (set-ligatures! 'csharp-mode + (set-ligatures! '(csharp-mode csharp-ts-mode) ;; Functional :lambda "() =>" ;; Types @@ -30,12 +37,13 @@ :return "return" :yield "yield") - (sp-local-pair 'csharp-mode "<" ">" + (sp-local-pair '(csharp-mode csharp-ts-mode) "<" ">" :when '(+csharp-sp-point-in-type-p) :post-handlers '(("| " "SPC"))) (when (modulep! +lsp) - (add-hook 'csharp-mode-local-vars-hook #'lsp! 'append)) + (add-hook 'csharp-mode-local-vars-hook #'lsp! 'append) + (add-hook 'csharp-ts-mode-local-vars-hook #'lsp! 'append)) (defadvice! +csharp-disable-clear-string-fences-a (fn &rest args) "This turns off `c-clear-string-fences' for `csharp-mode'. When @@ -46,24 +54,13 @@ or terminating simple string." (apply fn args)))) -(use-package! csharp-tree-sitter - :when (modulep! +tree-sitter) - :defer t - :init - (add-hook 'csharp-mode-local-vars-hook #'tree-sitter! 'append) - (when (fboundp #'csharp-tree-sitter-mode) - (add-to-list 'auto-mode-alist '("\\.cs\\'" . csharp-tree-sitter-mode)) - (when (modulep! +lsp) - (add-hook 'csharp-tree-sitter-mode-local-vars-hook #'lsp! 'append)))) - - ;; Unity shaders (use-package! shader-mode :when (modulep! +unity) :mode "\\.shader\\'" :config (def-project-mode! +csharp-unity-mode - :modes '(csharp-mode shader-mode) + :modes '(csharp-mode csharp-ts-mode shader-mode) :files (and "Assets" "Library/MonoManager.asset" "Library/ScriptMapper"))) diff --git a/modules/lang/dart/README.org b/modules/lang/dart/README.org index 5c875e7ab..3fe7ed533 100644 --- a/modules/lang/dart/README.org +++ b/modules/lang/dart/README.org @@ -23,9 +23,13 @@ This module wraps ~dart-mode~, with [[https://microsoft.github.io/language-serve - +lsp :: Enable LSP support for ~dart-mode~. Requires [[doom-module::tools lsp]] and a langserver (supports flutter). +- +tree-sitter :: + Leverages tree-sitter for better syntax highlighting and structural text + editing. Requires [[doom-module::tools tree-sitter]]. ** Packages - [[doom-package:dart-mode]] +- [[doom-package:dart-ts-mode]] if [[doom-module:+tree-sitter]] - [[doom-package:flutter.el]] - [[doom-package:hover.el]] diff --git a/modules/lang/dart/config.el b/modules/lang/dart/config.el index adffd9fb0..3975f113c 100644 --- a/modules/lang/dart/config.el +++ b/modules/lang/dart/config.el @@ -1,11 +1,7 @@ ;;; lang/dart/config.el -*- lexical-binding: t; -*- -(use-package! dart-mode - :defer t - :config - (when (modulep! +lsp) - (add-hook 'dart-mode-local-vars-hook #'lsp! 'append)) - (set-ligatures! '(dart-mode) +(defun +dart-common-config (mode) + (set-ligatures! mode ;; Functional :def "Function" :lambda "() =>" @@ -23,7 +19,25 @@ :for "for" :return "return" ;; Other - :yield "yield")) + :yield "yield") + + (when (modulep! +lsp) + (add-hook (intern (format "%s-local-vars-hook" mode)) #'lsp! 'append))) + +(use-package! dart-mode + :hook (dart-mode . rainbow-delimiters-mode) + :config + (+dart-common-config 'dart-mode)) + + +(use-package! dart-ts-mode + :when (modulep! +tree-sitter) + :defer t + :init + (set-tree-sitter! 'dart-mode 'dart-ts-mode + '((dart :url "https://github.com/ast-grep/tree-sitter-dart"))) + :config + (+dart-common-config 'dart-ts-mode)) (use-package! flutter diff --git a/modules/lang/dart/doctor.el b/modules/lang/dart/doctor.el index 74b43a676..3f813bffc 100644 --- a/modules/lang/dart/doctor.el +++ b/modules/lang/dart/doctor.el @@ -4,5 +4,9 @@ (modulep! :tools lsp)) "This module requires (:tools lsp)") +(assert! (or (not (modulep! +tree-sitter)) + (modulep! :tools tree-sitter)) + "This module requires (:tools tree-sitter)") + (unless (executable-find "dart") (warn! "Dart isn't on PATH.")) diff --git a/modules/lang/dart/packages.el b/modules/lang/dart/packages.el index 27f47df62..16641568e 100644 --- a/modules/lang/dart/packages.el +++ b/modules/lang/dart/packages.el @@ -3,6 +3,12 @@ (package! dart-mode :pin "f82ff052309125b93d19bdd3f619266f908f43ce") +(when (modulep! +tree-sitter) + (package! dart-ts-mode + :recipe (:host github + :repo "50ways2sayhard/dart-ts-mode") + :pin "ab87873f25f7e0cc8d22daa2501aae141dbe98ad")) + (when (and (modulep! +lsp) (modulep! :tools lsp -eglot)) (package! lsp-dart :pin "34e2a1191f723792d5f366b314cd6b07de4f1566")) diff --git a/modules/lang/elixir/README.org b/modules/lang/elixir/README.org index c1189cccf..9615660ee 100644 --- a/modules/lang/elixir/README.org +++ b/modules/lang/elixir/README.org @@ -11,11 +11,11 @@ This module provides support for [[https://elixir-lang.org/][Elixir programming ** Module flags - +lsp :: - Enable LSP support for ~elixir-mode~. Requires [[doom-module::tools lsp]] and a langserver - (supports [[https://github.com/elixir-lsp/elixir-ls/][elixir-ls]]). + Enable LSP support for ~elixir-mode~. Requires [[doom-module::tools lsp]] and a + langserver (supports [[https://github.com/elixir-lsp/elixir-ls/][elixir-ls]]). - +tree-sitter :: Leverages tree-sitter for better syntax highlighting and structural text - editing. Requires [[doom-module::tools tree-sitter]]. + editing. Requires Emacs 30.1+ and [[doom-module::tools tree-sitter]]. ** Packages - [[doom-package:elixir-mode]] diff --git a/modules/lang/elixir/config.el b/modules/lang/elixir/config.el index 770dc1544..fbf31d4c2 100644 --- a/modules/lang/elixir/config.el +++ b/modules/lang/elixir/config.el @@ -8,14 +8,8 @@ ;; ;;; Packages -(use-package! elixir-mode - :defer t - :init - ;; Disable default smartparens config. There are too many pairs; we only want - ;; a subset of them (defined below). - (provide 'smartparens-elixir) - :config - (set-ligatures! 'elixir-mode +(defun +elixir-common-config (mode) + (set-ligatures! mode ;; Functional :def "def" :lambda "fn" @@ -29,7 +23,7 @@ :return "return" :yield "use") ;; ...and only complete the basics - (sp-with-modes 'elixir-mode + (sp-with-modes mode (sp-local-pair "do" "end" :when '(("RET" "")) :unless '(sp-in-comment-p sp-in-string-p) @@ -37,16 +31,41 @@ (sp-local-pair "do " " end" :unless '(sp-in-comment-p sp-in-string-p)) (sp-local-pair "fn " " end" :unless '(sp-in-comment-p sp-in-string-p))) - (when (modulep! +lsp +tree-sitter) - (add-hook 'elixir-ts-mode-local-vars-hook #'lsp! 'append)) + (when (modulep! +lsp) + (add-hook (intern (format "%s-local-vars-hook" mode)) #'lsp! 'append))) + + +(use-package! elixir-mode + :defer t + :init + ;; Disable default smartparens config. There are too many pairs; we only want + ;; a subset of them (defined below). + (provide 'smartparens-elixir) (when (modulep! +lsp) - (add-hook 'elixir-mode-local-vars-hook #'lsp! 'append) (after! lsp-mode (add-to-list 'lsp-file-watch-ignored-directories "[/\\\\]_build\\'"))) + :config + (+elixir-common-config 'elixir-mode)) - (when (modulep! +tree-sitter) - (add-hook 'elixir-mode-local-vars-hook #'tree-sitter! 'append))) + +(use-package! elixir-ts-mode ; 30.1+ only + :when (modulep! +tree-sitter) + :defer t + :init + (set-tree-sitter! 'elixir-mode 'elixir-ts-mode + '((elixir :url "https://github.com/elixir-lang/tree-sitter-elixir" + :commit "02a6f7fd4be28dd94ee4dd2ca19cb777053ea74e") + (heex :url "https://github.com/phoenixframework/tree-sitter-heex" + :commit "f6b83f305a755cd49cf5f6a66b2b789be93dc7b9"))) + :config + (+elixir-common-config 'elixir-ts-mode)) + + +(use-package! heex-ts-mode + :when (modulep! +tree-sitter) + :when (fboundp 'heex-ts-mode) ; 30.1+ only + :mode "\\.[hl]?eex\\'") (use-package! flycheck-credo diff --git a/modules/lang/elixir/doctor.el b/modules/lang/elixir/doctor.el index 2c0306692..a6c454108 100644 --- a/modules/lang/elixir/doctor.el +++ b/modules/lang/elixir/doctor.el @@ -4,3 +4,7 @@ (assert! (or (not (modulep! +tree-sitter)) (modulep! :tools tree-sitter)) "This module requires (:tools tree-sitter)") + +(assert! (or (not (modulep! +tree-sitter)) + (fboundp 'elixir-ts-mode)) + "Can't find `elixir-ts-mode'; Emacs 30.1+ is required") diff --git a/modules/lang/elm/README.org b/modules/lang/elm/README.org index 8445c7c20..d2c2d06c6 100644 --- a/modules/lang/elm/README.org +++ b/modules/lang/elm/README.org @@ -13,9 +13,6 @@ This module adds [[https://elm-lang.org/][Elm]] support to Doom Emacs. - +lsp :: Enable LSP support for ~elm-mode~. Requires [[doom-module::tools lsp]] and a langserver (supports [[https://github.com/elm-tooling/elm-language-server][elm-language-server]]). -- +tree-sitter :: - Leverages tree-sitter for better syntax highlighting and structural text - editing. Requires [[doom-module::tools tree-sitter]]. ** Packages - [[doom-package:elm-mode]] diff --git a/modules/lang/elm/config.el b/modules/lang/elm/config.el index c8d371a21..44948cb77 100644 --- a/modules/lang/elm/config.el +++ b/modules/lang/elm/config.el @@ -5,9 +5,6 @@ (add-hook 'elm-mode-local-vars-hook #'lsp! 'append) (set-company-backend! 'elm-mode 'company-elm)) - (when (modulep! +tree-sitter) - (add-hook 'elm-mode-local-vars-hook #'tree-sitter! 'append)) - (set-repl-handler! 'elm-mode #'run-elm-interactive) (set-ligatures! 'elm-mode :null "null" diff --git a/modules/lang/elm/doctor.el b/modules/lang/elm/doctor.el index 37e3272b3..5e3379f00 100644 --- a/modules/lang/elm/doctor.el +++ b/modules/lang/elm/doctor.el @@ -1,5 +1,2 @@ ;;; lang/elm/doctor.el -*- lexical-binding: t; -*- -(assert! (or (not (modulep! +tree-sitter)) - (modulep! :tools tree-sitter)) - "This module requires (:tools tree-sitter)") diff --git a/modules/lang/erlang/config.el b/modules/lang/erlang/config.el index 32854a627..23914e243 100644 --- a/modules/lang/erlang/config.el +++ b/modules/lang/erlang/config.el @@ -5,9 +5,16 @@ :mode ("/rebar\\.config\\(?:\\.script\\)?\\'" . erlang-mode) :mode ("/\\(?:app\\|sys\\)\\.config\\'" . erlang-mode) :config - (set-formatter! 'erlfmt '("rebar3" "fmt" "-") :modes '(erlang-mode)) + (set-formatter! 'erlfmt '("rebar3" "fmt" "-") + :modes '(erlang-mode erlang-ts-mode)) (when (modulep! +lsp) - (add-hook 'erlang-mode-local-vars-hook #'lsp! 'append)) + (add-hook 'erlang-mode-local-vars-hook #'lsp! 'append))) - (when (modulep! +tree-sitter) - (add-hook 'erlang-mode-local-vars-hook #'tree-sitter! 'append))) + +(use-package! erlang-ts + :when (modulep! +tree-sitter) + :when (fboundp 'erlang-ts-mode) + :defer t + :init + (set-tree-sitter! 'erlang-mode 'erlang-ts-mode + '((erlang "https://github.com/WhatsApp/tree-sitter-erlang")))) diff --git a/modules/lang/erlang/doctor.el b/modules/lang/erlang/doctor.el index eca4a6039..006832da2 100644 --- a/modules/lang/erlang/doctor.el +++ b/modules/lang/erlang/doctor.el @@ -5,6 +5,10 @@ (modulep! :tools lsp)) "This module requires (:tools lsp)") +(assert! (or (not (modulep! +tree-sitter)) + (modulep! :tools tree-sitter)) + "This module requires (:tools tree-sitter)") + (when (modulep! :editor format) (unless (and (executable-find "rebar3") (zerop (car (doom-call-process "rebar3" "fmt" "-v")))) (warn! "Couldn't find erlfmt. Formatting will be disabled."))) diff --git a/modules/lang/erlang/packages.el b/modules/lang/erlang/packages.el index 88de226ae..6777483ef 100644 --- a/modules/lang/erlang/packages.el +++ b/modules/lang/erlang/packages.el @@ -2,3 +2,6 @@ ;;; lang/erlang/packages.el (package! erlang :pin "b9d3ec017da091168918a2901a1cef4cb062fd2a") + +(when (modulep! +tree-sitter) + (package! erlang-ts :pin "eb579dd55fbb2cf721290939e7b3a50be19c0305")) diff --git a/modules/lang/ess/README.org b/modules/lang/ess/README.org index a09374034..c03439e36 100644 --- a/modules/lang/ess/README.org +++ b/modules/lang/ess/README.org @@ -13,9 +13,6 @@ SAS, Julia and Stata. ** Module flags - +stan :: Enable support for ~stan-mode~, including code completion and syntax checking. -- +tree-sitter :: - Leverages tree-sitter for better syntax highlighting and structural text - editing. Currently only supports ~ess-r-mode~. Requires [[doom-module::tools tree-sitter]]. ** Packages - [[doom-package:ess]] diff --git a/modules/lang/ess/config.el b/modules/lang/ess/config.el index d7d97e69a..d58c5bee7 100644 --- a/modules/lang/ess/config.el +++ b/modules/lang/ess/config.el @@ -24,9 +24,6 @@ (when (modulep! +lsp) (add-hook 'ess-r-mode-local-vars-hook #'lsp! 'append)) - (when (modulep! +tree-sitter) - (add-hook 'ess-r-mode-local-vars-hook #'tree-sitter! 'append)) - (set-repl-handler! 'ess-r-mode #'run-ess-r) (set-repl-handler! 'ess-julia-mode #'run-ess-julia) (set-lookup-handlers! '(ess-r-mode ess-julia-mode) diff --git a/modules/lang/go/config.el b/modules/lang/go/config.el index e26bf19ec..e6dde2ef4 100644 --- a/modules/lang/go/config.el +++ b/modules/lang/go/config.el @@ -3,19 +3,16 @@ ;; ;;; Packages -(after! go-mode - (set-docsets! 'go-mode "Go") - (set-repl-handler! 'go-mode #'gorepl-run) - (set-lookup-handlers! 'go-mode +(defun +go-common-config (mode) + (set-docsets! mode "Go") + (set-repl-handler! mode #'gorepl-run) + (set-lookup-handlers! mode :documentation #'godoc-at-point) (when (modulep! +lsp) - (add-hook 'go-mode-local-vars-hook #'lsp! 'append)) + (add-hook (intern (format "%s-local-vars-hook" mode)) #'lsp! 'append)) - (when (modulep! +tree-sitter) - (add-hook 'go-mode-local-vars-hook #'tree-sitter! 'append)) - - (map! :map go-mode-map + (map! :map ,(intern (format "%s-map" mode)) :localleader "a" #'go-tag-add "d" #'go-tag-remove @@ -47,10 +44,34 @@ "a" #'+go/bench-all)))) +(after! go-mode + (+go-common-config 'go-mode)) + + +(use-package! go-ts-mode ; 29.1+ only + :when (modulep! +tree-sitter) + :mode ("/go\\.mod\\'" . go-mod-ts-mode-maybe) + :init + (set-tree-sitter! 'go-mode 'go-ts-mode + '((go :url "https://github.com/tree-sitter/tree-sitter-go" + :commit "12fe553fdaaa7449f764bc876fd777704d4fb752"))) + (set-tree-sitter! nil 'go-mod-ts-mode + '((gomod :url "https://github.com/camdencheek/tree-sitter-go-mod" + :commit "3b01edce2b9ea6766ca19328d1850e456fde3103"))) + (when (fboundp 'go-work-ts-mode) ; 30.1+ only + (add-to-list 'auto-mode-alist '("/go\\.work\\'" . go-work-ts-mode-maybe)) + (set-tree-sitter! nil 'go-work-ts-mode + '((gowork :url "https://github.com/omertuc/tree-sitter-go-work" + :commit "949a8a470559543857a62102c84700d291fc984c")))) + :config + (+go-common-config 'go-ts-mode)) + + (use-package! gorepl-mode :commands gorepl-run-load-current-file) (use-package! flycheck-golangci-lint :when (modulep! :checkers syntax -flymake) - :hook (go-mode . flycheck-golangci-lint-setup)) + :hook (go-mode . flycheck-golangci-lint-setup) + :hook (go-ts-mode . flycheck-golangci-lint-setup)) diff --git a/modules/lang/go/doctor.el b/modules/lang/go/doctor.el index 9ab40bb49..ac0887afe 100644 --- a/modules/lang/go/doctor.el +++ b/modules/lang/go/doctor.el @@ -9,6 +9,10 @@ (modulep! :tools tree-sitter)) "This module requires (:tools tree-sitter)") +(assert! (or (not (modulep! +tree-sitter)) + (fboundp 'go-ts-mode)) + "Can't find `go-ts-mode'; Emacs 31.1+ is required") + (unless (executable-find "gore") (warn! "Couldn't find gore. REPL will not work")) diff --git a/modules/lang/graphql/README.org b/modules/lang/graphql/README.org index e09e32f00..9e0821542 100644 --- a/modules/lang/graphql/README.org +++ b/modules/lang/graphql/README.org @@ -26,10 +26,14 @@ It includes: - +lsp :: Enable LSP support for ~graphql-mode~. Requires [[doom-module::tools lsp]] and a langserver ([[https://github.com/graphql/graphiql/tree/main/packages/graphql-language-service-cli#readme][graphql-language-service-cli]]). +- +tree-sitter :: + Leverages tree-sitter for better syntax highlighting and structural text + editing. Requires [[doom-module::tools tree-sitter]]. ** Packages - [[doom-package:company-graphql]] unless [[doom-module:+lsp]] - [[doom-package:graphql-mode]] +- [[doom-package:graphql-ts-mode]] if [[doom-module:+tree-sitter]] - [[doom-package:graphql-doc]] ** Hacks diff --git a/modules/lang/graphql/config.el b/modules/lang/graphql/config.el index 3dbc6802a..3687b0aaf 100644 --- a/modules/lang/graphql/config.el +++ b/modules/lang/graphql/config.el @@ -1,21 +1,18 @@ ;;; lang/graphql/config.el -*- lexical-binding: t; -*- -(after! graphql-mode - (defface nerd-icons-rhodamine - '((t (:foreground "#E10098"))) - "Face for GraphQL icon." - :group 'nerd-icons-faces) +;; +;;; Packages + +(defun +graphql-common-config (mode) (if (modulep! +lsp) - (add-hook 'graphql-mode-local-vars-hook #'lsp! 'append) - (set-company-backend! 'graphql-mode 'company-graphql)) + (add-hook (intern (format "%s-local-vars-hook" mode)) #'lsp! 'append) + (set-company-backend! mode 'company-graphql)) - (set-docsets! 'graphql-mode :add "GraphQL Specification") - - (set-electric! 'graphql-mode + (set-docsets! mode :add "GraphQL Specification") + (set-electric! mode :chars '(?\} ?\)) :words '("or" "and")) - - (set-ligatures! 'graphql-mode + (set-ligatures! mode :null "null" :true "true" :false "false" :int "Int" :str "String" @@ -25,5 +22,26 @@ :not "not" :and "and" :or "or")) + +(after! graphql-mode + (defface nerd-icons-rhodamine + '((t (:foreground "#E10098"))) + "Face for GraphQL icon." + :group 'nerd-icons-faces) + (add-hook 'graphql-mode-hook #'rainbow-delimiters-mode) + (+graphql-common-config 'graphql-mode)) + + +(use-package! graphql-ts-mode + :when (modulep! +tree-sitter) + :when (fboundp 'treesit-available-p) + :defer t + :init + (set-tree-sitter! 'graphql-mode 'graphql-ts-mode + '((graphql :url "https://github.com/bkegley/tree-sitter-graphql"))) + :config + (+graphql-common-config 'graphql-ts-mode)) + + (use-package! graphql-doc :after graphql-mode) diff --git a/modules/lang/graphql/doctor.el b/modules/lang/graphql/doctor.el new file mode 100644 index 000000000..94be43a97 --- /dev/null +++ b/modules/lang/graphql/doctor.el @@ -0,0 +1,5 @@ +;;; lang/graphql/doctor.el -*- lexical-binding: t; -*- + +(assert! (or (not (modulep! +tree-sitter)) + (modulep! :tools tree-sitter)) + "This module requires (:tools tree-sitter)") diff --git a/modules/lang/graphql/packages.el b/modules/lang/graphql/packages.el index 6f0b7c096..7b11285e2 100644 --- a/modules/lang/graphql/packages.el +++ b/modules/lang/graphql/packages.el @@ -7,3 +7,5 @@ (package! company-graphql :recipe (:host github :repo "thaenalpha/company-graphql") :pin "aed9f5109e877944a895d08fc08bad103f03096b")) +(when (modulep! +tree-sitter) + (package! graphql-ts-mode :pin "e933f235408ea195762700fd07c2d828e8f09aac")) diff --git a/modules/lang/graphviz/config.el b/modules/lang/graphviz/config.el index 7e390b09e..daae33ac1 100644 --- a/modules/lang/graphviz/config.el +++ b/modules/lang/graphviz/config.el @@ -8,10 +8,6 @@ :config (set-company-backend! 'graphviz-dot-mode 'company-graphviz-dot-backend) (set-formatter! 'graphviz-dot #'+graphviz-formatter :modes '(graphviz-dot-mode)) - (set-tree-sitter-lang! 'graphviz-dot-mode 'dot) - - (when (modulep! +tree-sitter) - (add-hook 'graphiz-dot-mode-hook #'tree-sitter!)) (after! dtrt-indent (add-to-list 'dtrt-indent-hook-mapping-list '(graphviz-mode graphviz-dot-indent-width))) diff --git a/modules/lang/haskell/README.org b/modules/lang/haskell/README.org index 7fce1d721..553228a06 100644 --- a/modules/lang/haskell/README.org +++ b/modules/lang/haskell/README.org @@ -21,6 +21,7 @@ This module adds Haskell support to Doom Emacs. ** Packages - [[doom-package:haskell-mode]] +- [[doom-package:haskell-ts-mode]] if [[doom-module:+tree-sitter]] - [[doom-package:lsp-haskell]] if [[doom-module:+lsp]] ** Hacks diff --git a/modules/lang/haskell/config.el b/modules/lang/haskell/config.el index 9c78fbced..3707ac6a9 100644 --- a/modules/lang/haskell/config.el +++ b/modules/lang/haskell/config.el @@ -28,9 +28,6 @@ #'haskell-collapse-mode ; support folding haskell code blocks #'interactive-haskell-mode) - (when (modulep! +tree-sitter) - (add-hook 'haskell-mode-local-vars-hook #'tree-sitter! 'append)) - (add-to-list 'completion-ignored-extensions ".hi") (map! :map haskell-mode-map @@ -47,6 +44,18 @@ "H" #'haskell-hide-toggle-all)) +(use-package! haskell-ts-mode + :when (modulep! +tree-sitter) + :when (fboundp 'haskell-ts-mode) + :defer t + :init + (set-tree-sitter! 'haskell-mode 'haskell-ts-mode + '((haskell :url "https://github.com/tree-sitter/tree-sitter-haskell"))) + :config + (set-repl-handler! 'haskell-ts-mode #'run-haskell :persist t) + (set-eglot-client! 'haskell-ts-mode '("haskell-language-server-wrapper" "--lsp"))) + + (use-package! lsp-haskell :when (modulep! +lsp) :defer t diff --git a/modules/lang/haskell/doctor.el b/modules/lang/haskell/doctor.el index 8874330f5..7ffc55058 100644 --- a/modules/lang/haskell/doctor.el +++ b/modules/lang/haskell/doctor.el @@ -5,6 +5,10 @@ (modulep! :tools lsp)) "This module requires (:tools lsp)") +(assert! (or (not (modulep! +tree-sitter)) + (modulep! :tools tree-sitter)) + "This module requires (:tools tree-sitter)") + (unless (executable-find "cabal") (warn! "Couldn't find cabal. haskell-mode may have issues.")) diff --git a/modules/lang/haskell/packages.el b/modules/lang/haskell/packages.el index 8ba6491bd..0feac9687 100644 --- a/modules/lang/haskell/packages.el +++ b/modules/lang/haskell/packages.el @@ -2,6 +2,8 @@ ;;; lang/haskell/packages.el (package! haskell-mode :pin "e9c356739310332afe59b10ffa2e6c3e76f124e3") +(when (modulep! +tree-sitter) + (package! haskell-ts-mode :pin "b47211699944997bfb03fd88b1157dd71727bad7")) (when (and (modulep! +lsp) (modulep! :tools lsp -eglot)) diff --git a/modules/lang/janet/README.org b/modules/lang/janet/README.org index 44cfe98f5..65e09c2ea 100644 --- a/modules/lang/janet/README.org +++ b/modules/lang/janet/README.org @@ -12,7 +12,9 @@ This module adds rudimentary support for the [[https://janet-lang.org/][Janet pr [[doom-contrib-maintainer:][Become a maintainer?]] ** Module flags -/This module has no flags./ +- +tree-sitter :: + Leverages tree-sitter for better syntax highlighting and structural text + editing. Requires [[doom-module::tools tree-sitter]]. ** Packages - [[doom-package:janet-mode]] diff --git a/modules/lang/janet/config.el b/modules/lang/janet/config.el index cf26fbd66..f1564a68e 100644 --- a/modules/lang/janet/config.el +++ b/modules/lang/janet/config.el @@ -24,16 +24,10 @@ (put sym 'janet-indent-function 'defun))) -;; (use-package! janet-ts-mode -;; :when (modulep! +tree-sitter) -;; :defer t -;; :init -;; (set-tree-sitter! 'janet-mode 'janet-ts-mode -;; `(janet-simple :url "https://github.com/sogaiu/tree-sitter-janet-simple" -;; :cc ,(if (featurep :system 'windows) "gcc.exe"))) -;; :config -;; ;; HACK: These autoloads are inserted twice by this package, so remove them so -;; ;; this module can be the single source of truth. -;; (cl-callf2 delete '("\\.janet\\'" . janet-ts-mode) auto-mode-alist) -;; (cl-callf2 delete '("\\.jdn\\'" . janet-ts-mode) auto-mode-alist) -;; (cl-callf2 delete '("janet" . janet-ts-mode) interpreter-mode-alist)) +(use-package! janet-ts-mode + :when (modulep! +tree-sitter) + :defer t + :init + (set-tree-sitter! 'janet-mode 'janet-ts-mode + `((janet-simple :url "https://github.com/sogaiu/tree-sitter-janet-simple" + :cc ,(if (featurep :system 'windows) "gcc.exe"))))) diff --git a/modules/lang/janet/packages.el b/modules/lang/janet/packages.el index ba107e355..88409a9d9 100644 --- a/modules/lang/janet/packages.el +++ b/modules/lang/janet/packages.el @@ -5,7 +5,7 @@ :recipe (:files ("*.el")) :pin "9e3254a0249d720d5fa5603f1f8c3ed0612695af") -;; (when (modulep! +tree-sitter) -;; (package! janet-ts-mode -;; :recipe (:host github :repo "sogaiu/janet-ts-mode") -;; :pin "ac684edf57e4d4e085cf99d5ad2ee084b46b8123")) +(when (modulep! +tree-sitter) + (package! janet-ts-mode + :recipe (:host github :repo "sogaiu/janet-ts-mode") + :pin "ac684edf57e4d4e085cf99d5ad2ee084b46b8123")) diff --git a/modules/lang/java/config.el b/modules/lang/java/config.el index 77f300b22..ae0698ef0 100644 --- a/modules/lang/java/config.el +++ b/modules/lang/java/config.el @@ -28,13 +28,21 @@ If the depth is 2, the first two directories are removed: net.lissner.game.") (modulep! :tools lsp -eglot)) (load! "+lsp")) -(when (modulep! +tree-sitter) - (add-hook 'java-mode-local-vars-hook #'tree-sitter! 'append)) - ;; ;;; Common packages +(use-package! java-ts-mode ; 29.1+ only + :when (modulep! +tree-sitter) + :defer t + :init + (set-tree-sitter! 'java-mode 'java-ts-mode + '((java :url "https://github.com/tree-sitter/tree-sitter-java" + :commit "94703d5a6bed02b98e438d7cad1136c01a60ba2c") + (doxygen :url "https://github.com/tree-sitter-grammars/tree-sitter-doxygen" + :commit "1e28054cb5be80d5febac082706225e42eff14e6")))) + + (use-package! android-mode :commands android-mode :init diff --git a/modules/lang/java/doctor.el b/modules/lang/java/doctor.el index 9e0a9a1aa..102ec263e 100644 --- a/modules/lang/java/doctor.el +++ b/modules/lang/java/doctor.el @@ -9,6 +9,10 @@ (modulep! :tools tree-sitter)) "This module requires (:tools tree-sitter)") +(assert! (or (not (modulep! +tree-sitter)) + (fboundp 'java-ts-mode)) + "Can't find `java-ts-mode'; Emacs 29.1+ is required") + (unless (executable-find "javac") (warn! "Couldn't find the javac executable, are you sure the JDK is installed?")) diff --git a/modules/lang/javascript/README.org b/modules/lang/javascript/README.org index 419d37c2f..c51c78b9a 100644 --- a/modules/lang/javascript/README.org +++ b/modules/lang/javascript/README.org @@ -6,13 +6,14 @@ * Description :unfold: This module adds [[https://www.javascript.com/][JavaScript]] and [[https://www.typescriptlang.org/][TypeScript]] support to Doom Emacs. -- Code completion ([[doom-package:tide]]) -- REPL support ([[doom-package:nodejs-repl]]) -- Refactoring commands ([[doom-package:js2-refactor]]) -- Syntax checking ([[doom-package:flycheck]]) -- Browser code injection with [[doom-package:skewer-mode]] -- Coffeescript & JSX support -- Jump-to-definitions and references support ([[doom-package:xref]]) +- JSX/TSX support (requires [[doom-module:+tree-sitter]] and Emacs 29.1+) +- LSP Integration + - Code completion (with [[doom-module::completion corfu]] (recommended) or + [[doom-module::completion company]]) + - Syntax checking (with [[doom-module::checkers syntax]]) + - Jump-to-definitions and references support +- Code formatting (with [[doom-module::editor format]] and [[https://prettier.io/docs/en/install.html][prettier]]) +- REPL support (with [[doom-package:nodejs-repl]] and/or [[doom-module::tools eval]]) ** Maintainers - [[doom-user:][@elken]] @@ -23,22 +24,17 @@ This module adds [[https://www.javascript.com/][JavaScript]] and [[https://www.t ** Module flags - +lsp :: - Enable LSP support for ~js2-mode~, ~rjsx-mode~, JS in ~web-mode~, and - ~typescript-mode~. Requires [[doom-module::tools lsp]] and a langserver (supports ts-ls and - deno-ls). + Enable LSP support for ~js-mode~, ~js-ts-mode~, ~typesript-mode~, and + ~typescript-ts-mode. Requires [[doom-module::tools lsp]] and a langserver + (supports ts-ls and deno-ls). - +tree-sitter :: Leverages tree-sitter for better syntax highlighting and structural text - editing. Requires [[doom-module::tools tree-sitter]]. + editing. Requires [[doom-module::tools tree-sitter]]. Requires Emacs 29.1+. + Required for JSX/TSX support. ** Packages -- [[doom-package:js2-refactor]] - [[doom-package:nodejs-repl]] -- [[doom-package:npm-mode]] -- [[doom-package:rjsx-mode]] -- [[doom-package:skewer-mode]] (DEPRECATED) -- [[doom-package:tide]] -- [[doom-package:typescript-mode]] -- [[doom-package:xref-js2]] if [[doom-module::tools lookup]] +- [[doom-package:typescript-mode]] unless [[doom-module:+tree-sitter]] ** TODO Hacks #+begin_quote @@ -59,97 +55,13 @@ This module requires [[https://nodejs.org/en/][NodeJS]] and one of [[https://www - openSUSE: ~$ zypper install nodejs npm~ ** Formatter - Formatting is handled using the [[doom-module::editor format]] module via [[https://prettier.io/docs/en/install.html][prettier]]. * TODO Usage #+begin_quote - 󱌣 /This module's usage documentation is incomplete./ [[doom-contrib-module:][Complete it?]] + 󱌣 This module has no usage documentation yet. [[doom-contrib-module:][Write some?]] #+end_quote -~rjsx-mode~ is used for all javascript buffers. - -** Commands -*** rjsx-mode -| command | key / ex command | description | -|----------------------------------+------------------+------------------------------------------------------------| -| ~+javascript/open-repl~ | ~:repl~ | Open the NodeJS REPL (or send the current selection to it) | -| ~+javascript/skewer-this-buffer~ | [[kbd:][ S]] | Attaches a browser to the current buffer | - -*** Tide -| command | key / ex command | description | -|-------------------------+---------------------+------------------------| -| ~tide-restart-server~ | [[kbd:][ R]] | Restart tide server | -| ~tide-reformat~ | [[kbd:][ f]] | Reformat region | -| ~tide-rename-symbol~ | [[kbd:][ r r s]] | Rename symbol at point | -| ~tide-organize-imports~ | [[kbd:][ r o i]] | Organize imports | - -*** Refactoring (js2-refactor-mode) -| command | key / ex command | description | -|---------------------------------------------------+---------------------+--------------------------------------------------------------------------------------------------------------------| -| ~js2r-expand-node-at-point~ | [[kbd:][ r e e]] | Expand bracketed list according to node type at point | -| ~js2r-contract-node-at-point~ | [[kbd:][ r c c]] | Contract bracketed list according to node type at point | -| ~js2r-extract-function~ | [[kbd:][ r e f]] | Extracts the marked expressions out into a new named function. | -| ~js2r-extract-method~ | [[kbd:][ r e m]] | Extracts the marked expressions out into a new named method in an object literal. | -| ~js2r-toggle-function-expression-and-declaration~ | [[kbd:][ r t f]] | Toggle between function name() {} and var name = function (); | -| ~js2r-toggle-arrow-function-and-expression~ | [[kbd:][ r t a]] | Toggle between function expression to arrow function. | -| ~js2r-toggle-function-async~ | [[kbd:][ r t s]] | Toggle between an async and a regular function. | -| ~js2r-introduce-parameter~ | [[kbd:][ r i p]] | Changes the marked expression to a parameter in a local function. | -| ~js2r-localize-parameter~ | [[kbd:][ r l p]] | Changes a parameter to a local var in a local function. | -| ~js2r-wrap-buffer-in-iife~ | [[kbd:][ r w i]] | Wraps the entire buffer in an immediately invoked function expression | -| ~js2r-inject-global-in-iife~ | [[kbd:][ r i g]] | Creates a shortcut for a marked global by injecting it in the wrapping immediately invoked function expression | -| ~js2r-add-to-globals-annotation~ | [[kbd:][ r a g]] | Creates a /*global */ annotation if it is missing, and adds the var at point to it. | -| ~js2r-extract-var~ | [[kbd:][ r e v]] | Takes a marked expression and replaces it with a var. | -| ~js2r-extract-let~ | [[kbd:][ r e l]] | Similar to extract-var but uses a let-statement. | -| ~js2r-extract-const~ | [[kbd:][ r e c]] | Similar to extract-var but uses a const-statement. | -| ~js2r-inline-var~ | [[kbd:][ r i v]] | Replaces all instances of a variable with its initial value. | -| ~js2r-rename-var~ | [[kbd:][ r r v]] | Renames the variable on point and all occurrences in its lexical scope. | -| ~js2r-var-to-this~ | [[kbd:][ r v t]] | Changes local var a to be this.a instead. | -| ~js2r-arguments-to-object~ | [[kbd:][ r a o]] | Replaces arguments to a function call with an object literal of named arguments. | -| ~js2r-ternary-to-if~ | [[kbd:][ r 3 i]] | Converts ternary operator to if-statement. | -| ~js2r-split-var-declaration~ | [[kbd:][ r s v]] | Splits a var with multiple vars declared, into several var statements. | -| ~js2r-split-string~ | [[kbd:][ r s s]] | Splits a string. | -| ~js2r-string-to-template~ | [[kbd:][ r s t]] | Converts a string into a template string. | -| ~js2r-unwrap~ | [[kbd:][ r u w]] | Replaces the parent statement with the selected region. | -| ~js2r-log-this~ | [[kbd:][ r l t]] | Adds a console.log() statement for what is at point (or region). With a prefix argument, use JSON pretty-printing. | -| ~js2r-debug-this~ | [[kbd:][ r d t]] | Adds a debug() statement for what is at point (or region). | -| ~js2r-forward-slurp~ | [[kbd:][ r s l]] | Moves the next statement into current function, if-statement, for-loop or while-loop. | -| ~js2r-forward-barf~ | [[kbd:][ r b a]] | Moves the last child out of current function, if-statement, for-loop or while-loop. | -| ~js2r-kill~ | [[kbd:][ r k]] | Kills to the end of the line, but does not cross semantic boundaries. | - -*** skewer-mode -**** general -| command | key / ex command | description | -|-------------------------------+-------------------+---------------------------------------| -| ~skewer-eval-last-expression~ | [[kbd:][ s E]] | Evaluate last expression | -| ~skewer-eval-defun~ | [[kbd:][ s e]] | Evaluate function definition at point | -| ~skewer-load-buffer~ | [[kbd:][ s f]] | Load buffer into REPL | - -**** css -| command | key / ex command | description | -|---------------------------------------+-------------------+-------------------------------| -| ~skewer-css-eval-current-declaration~ | [[kbd:][ s e]] | Evaluate declaration at point | -| ~skewer-css-eval-current-rule~ | [[kbd:][ s r]] | Evaluate rule at point | -| ~skewer-css-eval-buffer~ | [[kbd:][ s b]] | Evaluate buffer | -| ~skewer-css-clear-all~ | [[kbd:][ s c]] | Clear all rules | - -**** html -| command | key / ex command | description | -|------------------------+-------------------+-----------------------| -| ~skewer-html-eval-tag~ | [[kbd:][ s e]] | Evaluate tag at point | - -*** npm-mode -| command | key / ex command | description | -|---------------------------------+-------------------+------------------------------------------------------------------| -| ~npm-mode-npm-init~ | [[kbd:][ n n]] | Initialize npm project | -| ~npm-mode-npm-install~ | [[kbd:][ n i]] | Install npm package | -| ~npm-mode-npm-install-save~ | [[kbd:][ n s]] | Install npm package and save to package.json | -| ~npm-mode-npm-install-save-dev~ | [[kbd:][ n d]] | Install npm package and save to package.json as a dev dependency | -| ~npm-mode-npm-uninstall~ | [[kbd:][ n u]] | Uninstall npm package | -| ~npm-mode-npm-list~ | [[kbd:][ n l]] | List npm packages | -| ~npm-mode-npm-run~ | [[kbd:][ n r]] | Run npm task | -| ~npm-mode-visit-project-file~ | [[kbd:][ n v]] | Find file in npm project | - * TODO Configuration #+begin_quote 󱌣 This module has no configuration documentation yet. [[doom-contrib-module:][Write some?]] diff --git a/modules/lang/javascript/config.el b/modules/lang/javascript/config.el index 7aa2ecf42..835bb0c10 100644 --- a/modules/lang/javascript/config.el +++ b/modules/lang/javascript/config.el @@ -8,303 +8,108 @@ ;; ;;; Major modes -(dolist (feature '(rjsx-mode - typescript-mode - web-mode - (nodejs-repl-mode . nodejs-repl))) - (let ((pkg (or (cdr-safe feature) feature)) - (mode (or (car-safe feature) feature))) - (with-eval-after-load pkg - (set-docsets! mode "JavaScript" - "AngularJS" "Backbone" "BackboneJS" "Bootstrap" "D3JS" "EmberJS" "Express" - "ExtJS" "JQuery" "JQuery_Mobile" "JQuery_UI" "KnockoutJS" "Lo-Dash" - "MarionetteJS" "MomentJS" "NodeJS" "PrototypeJS" "React" "RequireJS" - "SailsJS" "UnderscoreJS" "VueJS" "ZeptoJS") - (set-ligatures! mode - ;; Functional - :def "function" - :lambda "() =>" - :composition "compose" - ;; Types - :null "null" - :true "true" :false "false" - ;; Flow - :not "!" - :and "&&" :or "||" - :for "for" - :return "return" - ;; Other - :yield "import")))) +(defun +javascript-common-config (mode) + (unless (eq mode 'nodejs-repl-mode) + (set-repl-handler! mode #'+javascript/open-repl) + (set-electric! mode :chars '(?\} ?\) ?. ?:)) + (set-ligatures! mode + ;; Functional + :def "function" + :lambda "() =>" + :composition "compose" + ;; Types + :null "null" + :true "true" :false "false" + ;; Flow + :not "!" + :and "&&" :or "||" + :for "for" + :return "return" + ;; Other + :yield "import") + + (when (modulep! +lsp) + (add-hook (intern (format "%s-local-vars-hook" mode)) #'lsp! 'append))) + + (pcase mode + ((or 'js-mode 'js-ts-mode 'nodejs-repl-mode) + (set-docsets! mode "JavaScript" + "AngularJS" "Backbone" "BackboneJS" "Bootstrap" "D3JS" "EmberJS" "Express" + "ExtJS" "JQuery" "JQuery_Mobile" "JQuery_UI" "KnockoutJS" "Lo-Dash" + "MarionetteJS" "MomentJS" "NodeJS" "PrototypeJS" "React" "RequireJS" + "SailsJS" "UnderscoreJS" "VueJS" "ZeptoJS")) + ((or 'typescript-mode 'typescript-ts-mode) + (set-docsets! mode :add "TypeScript" "AngularTS") + (set-electric! mode :chars '(?\} ?\)) :words '("||" "&&"))))) -(use-package! rjsx-mode +(use-package! js-mode :mode "\\.[mc]?js\\'" :mode "\\.es6\\'" :mode "\\.pac\\'" - :interpreter "node" - :init - ;; Parse node stack traces in the compilation buffer - (after! compilation - (add-to-list 'compilation-error-regexp-alist 'node) - (add-to-list 'compilation-error-regexp-alist-alist - '(node "^[[:blank:]]*at \\(.*(\\|\\)\\(.+?\\):\\([[:digit:]]+\\):\\([[:digit:]]+\\)" - 2 3 4))) :config - (set-repl-handler! 'rjsx-mode #'+javascript/open-repl) - (set-electric! 'rjsx-mode :chars '(?\} ?\) ?. ?:)) + (setq js-chain-indent t) + (+javascript-common-config 'js-mode)) - (setq js-chain-indent t - ;; These have become standard in the JS community - js2-basic-offset 2 - ;; Don't mishighlight shebang lines - js2-skip-preprocessor-directives t - ;; let flycheck handle this - js2-mode-show-parse-errors nil - js2-mode-show-strict-warnings nil - ;; Flycheck provides these features, so disable them: conflicting with - ;; the eslint settings. - js2-strict-missing-semi-warning nil - ;; maximum fontification - js2-highlight-level 3 - js2-idle-timer-delay 0.15) - (setq-hook! 'rjsx-mode-hook - ;; Indent switch-case another step - js-switch-indent-offset js2-basic-offset) - - (use-package! xref-js2 - :when (modulep! :tools lookup) - :init - (setq xref-js2-search-program 'rg) - (set-lookup-handlers! 'rjsx-mode - :xref-backend #'xref-js2-xref-backend)) - - ;; HACK `rjsx-electric-gt' relies on js2's parser to tell it when the cursor - ;; is in a self-closing tag, so that it can insert a matching ending tag - ;; at point. The parser doesn't run immediately however, so a fast typist - ;; can outrun it, causing tags to stay unclosed, so force it to parse: - (defadvice! +javascript-reparse-a (n) - ;; if n != 1, rjsx-electric-gt calls rjsx-maybe-reparse itself - :before #'rjsx-electric-gt - (if (= n 1) (rjsx-maybe-reparse)))) +(use-package! js-ts-mode ; 29.1+ only + :when (modulep! +tree-sitter) + :defer t + :init + (set-tree-sitter! 'js-mode 'js-ts-mode + '((javascript :url "https://github.com/tree-sitter/tree-sitter-javascript" + :rev "v0.23.0" + :commit "108b2d4d17a04356a340aea809e4dd5b801eb40d") + (jsdoc :url "https://github.com/tree-sitter/tree-sitter-jsdoc" + :rev "v0.23.0" + :commit "b253abf68a73217b7a52c0ec254f4b6a7bb86665"))) + (+javascript-common-config 'js-ts-mode)) (use-package! typescript-mode - :defer t - :init - (when (modulep! :lang web) - (autoload 'typescript-tsx-mode "typescript-mode" nil t)) - - ;; REVIEW We associate TSX files with `typescript-tsx-mode' derived from - ;; `web-mode' because `typescript-mode' does not officially support - ;; JSX/TSX. See emacs-typescript/typescript.el#4 - (add-to-list 'auto-mode-alist - (cons "\\.tsx\\'" - (if (modulep! :lang web) - #'typescript-tsx-mode - #'typescript-mode))) - - (when (modulep! :checkers syntax -flymake) - (after! flycheck - (flycheck-add-mode 'javascript-eslint 'web-mode) - (flycheck-add-mode 'javascript-eslint 'typescript-mode) - (flycheck-add-mode 'javascript-eslint 'typescript-tsx-mode) - (flycheck-add-mode 'typescript-tslint 'typescript-tsx-mode) - (unless (modulep! +lsp) - (after! tide - (flycheck-add-next-checker 'typescript-tide '(warning . javascript-eslint) 'append) - (flycheck-add-mode 'typescript-tide 'typescript-tsx-mode))) - (add-hook! 'typescript-tsx-mode-hook - (defun +javascript-disable-tide-checkers-h () - (pushnew! flycheck-disabled-checkers - 'javascript-jshint - 'tsx-tide - 'jsx-tide))))) + :unless (modulep! +tree-sitter) + :mode "\\.ts\\'" :config - (when (fboundp 'web-mode) - (define-derived-mode typescript-tsx-mode web-mode "TypeScript-TSX") - (when (modulep! +lsp) - (after! lsp-mode - (add-to-list 'lsp--formatting-indent-alist '(typescript-tsx-mode . typescript-indent-level)))) - (when (modulep! +tree-sitter) - (after! evil-textobj-tree-sitter - (pushnew! evil-textobj-tree-sitter-major-mode-language-alist '(typescript-tsx-mode . "tsx"))) - (after! tree-sitter - (pushnew! tree-sitter-major-mode-language-alist '(typescript-tsx-mode . tsx))) - ;; HACK: the tsx grammer doesn't work with the hightlighting provided by - ;; font-lock-keywords. See emacs-tree-sitter/tree-sitter-langs#23 - (setq-hook! 'typescript-tsx-mode-hook - tree-sitter-hl-use-font-lock-keywords nil))) + (+javascript-common-config 'typescript-mode)) - (set-docsets! '(typescript-mode typescript-tsx-mode) - :add "TypeScript" "AngularTS") - (set-electric! '(typescript-mode typescript-tsx-mode) - :chars '(?\} ?\)) - :words '("||" "&&")) - ;; HACK Fixes comment continuation on newline - (autoload 'js2-line-break "js2-mode" nil t) - (setq-hook! 'typescript-mode-hook - comment-line-break-function #'js2-line-break - ;; Most projects use either eslint, prettier, .editorconfig, or tsf in order - ;; to specify indent level and formatting. In the event that no - ;; project-level config is specified (very rarely these days), the community - ;; default is 2, not 4. However, respect what is in tsfmt.json if it is - ;; present in the project - typescript-indent-level - (or (and (bound-and-true-p tide-mode) - (plist-get (tide-tsfmt-options) :indentSize)) - typescript-indent-level) +(use-package! typescript-ts-mode ; 29.1+ only + :when (modulep! +tree-sitter) + :mode "\\.ts\\'" + :init + (set-tree-sitter! 'typescript-mode 'typescript-ts-mode + '((typescript :url "https://github.com/tree-sitter/tree-sitter-typescript" + :commit "8e13e1db35b941fc57f2bd2dd4628180448c17d5" + :source-dir "typescript/src"))) + :config + (+javascript-common-config 'typescript-ts-mode)) - ;; Fix #5556: expand .x to className="x" instead of class="x", if - ;; `emmet-mode' is used. - emmet-expand-jsx-className? t)) + +(use-package! tsx-ts-mode + :when (modulep! +tree-sitter) + :when (fboundp 'tsx-ts-mode) ; 29.1+ only + :mode "\\.[tj]sx\\'" + :defer t + :config + (+javascript-common-config 'tsx-ts-mode)) ;; -;;; Tools +;;; Extensions -(when (modulep! +tree-sitter) - (add-hook! '(js2-mode-local-vars-hook - typescript-mode-local-vars-hook - typescript-tsx-mode-local-vars-hook - rjsx-mode-local-vars-hook) - :append #'tree-sitter!)) - -(add-hook! '(typescript-mode-local-vars-hook - typescript-tsx-mode-local-vars-hook - web-mode-local-vars-hook - rjsx-mode-local-vars-hook) - (defun +javascript-init-lsp-or-tide-maybe-h () - "Start `lsp' or `tide' in the current buffer. - -LSP will be used if the +lsp flag is enabled for :lang javascript AND if the -current buffer represents a file in a project. - -If LSP fails to start (e.g. no available server or project), then we fall back -to tide." - (let ((buffer-file-name (buffer-file-name (buffer-base-buffer)))) - (when (derived-mode-p 'js-mode 'typescript-mode 'typescript-tsx-mode) - (if (null buffer-file-name) - ;; necessary because `tide-setup' and `lsp' will error if not a - ;; file-visiting buffer - (add-hook 'after-save-hook #'+javascript-init-lsp-or-tide-maybe-h - nil 'local) - (or (if (modulep! +lsp) (lsp!)) - ;; fall back to tide - (if (executable-find "node") - (and (require 'tide nil t) - (progn (tide-setup) tide-mode)) - (ignore - (doom-log "Couldn't start tide because 'node' is missing")))) - (remove-hook 'after-save-hook #'+javascript-init-lsp-or-tide-maybe-h - 'local)))))) +;; Parse node stack traces in the compilation buffer +(after! compilation + (add-to-list 'compilation-error-regexp-alist 'node) + (add-to-list 'compilation-error-regexp-alist-alist + '(node "^[[:blank:]]*at \\(.*(\\|\\)\\(.+?\\):\\([[:digit:]]+\\):\\([[:digit:]]+\\)" + 2 3 4))) -(use-package! tide - :hook (tide-mode . tide-hl-identifier-mode) - :config - (set-company-backend! 'tide-mode 'company-tide) - ;; navigation - (set-lookup-handlers! 'tide-mode :async t - :xref-backend #'xref-tide-xref-backend - :documentation #'tide-documentation-at-point) - (set-popup-rule! "^\\*tide-documentation" :quit t) - - (setq tide-completion-detailed t - tide-always-show-documentation t - ;; Fix #1792: by default, tide ignores payloads larger than 100kb. This - ;; is too small for larger projects that produce long completion lists, - ;; so we up it to 512kb. - tide-server-max-response-length 524288 - ;; We'll handle it - tide-completion-setup-company-backend nil) - - ;; Resolve to `doom-project-root' if `tide-project-root' fails - (advice-add #'tide-project-root :override #'+javascript-tide-project-root-a) - - ;; Cleanup tsserver when no tide buffers are left - (add-hook! 'tide-mode-hook - (add-hook 'kill-buffer-hook #'+javascript-cleanup-tide-processes-h - nil 'local)) - - ;; Eldoc is activated too soon and disables itself, thinking there is no eldoc - ;; support in the current buffer, so we must re-enable it later once eldoc - ;; support exists. It is set *after* tide-mode is enabled, so enabling it on - ;; `tide-mode-hook' is too early, so... - (advice-add #'tide-setup :after #'eldoc-mode) - - (map! :localleader - :map tide-mode-map - "R" #'tide-restart-server - "f" #'tide-format - "rrs" #'tide-rename-symbol - "roi" #'tide-organize-imports)) - - -(use-package! js2-refactor - :hook ((js2-mode rjsx-mode) . js2-refactor-mode) +(use-package! nodejs-repl + :defer t :init - (map! :after js2-mode - :map js2-mode-map - :localleader - (:prefix ("r" . "refactor") - (:prefix ("a" . "add/arguments")) - (:prefix ("b" . "barf")) - (:prefix ("c" . "contract")) - (:prefix ("d" . "debug")) - (:prefix ("e" . "expand/extract")) - (:prefix ("i" . "inject/inline/introduce")) - (:prefix ("l" . "localize/log")) - (:prefix ("o" . "organize")) - (:prefix ("r" . "rename")) - (:prefix ("s" . "slurp/split/string")) - (:prefix ("t" . "toggle")) - (:prefix ("u" . "unwrap")) - (:prefix ("v" . "var")) - (:prefix ("w" . "wrap")) - (:prefix ("3" . "ternary")))) :config - (when (modulep! :editor evil +everywhere) - (add-hook 'js2-refactor-mode-hook #'evil-normalize-keymaps) - (let ((js2-refactor-mode-map (evil-get-auxiliary-keymap js2-refactor-mode-map 'normal t t))) - (js2r-add-keybindings-with-prefix (format "%s r" doom-localleader-key))))) - - -;;;###package skewer-mode -(map! :localleader - (:after js2-mode - :map js2-mode-map - "S" #'+javascript/skewer-this-buffer - :prefix ("s" . "skewer")) - :prefix "s" - (:after skewer-mode - :map skewer-mode-map - "E" #'skewer-eval-last-expression - "e" #'skewer-eval-defun - "f" #'skewer-load-buffer) - - (:after skewer-css - :map skewer-css-mode-map - "e" #'skewer-css-eval-current-declaration - "r" #'skewer-css-eval-current-rule - "b" #'skewer-css-eval-buffer - "c" #'skewer-css-clear-all) - - (:after skewer-html - :map skewer-html-mode-map - "e" #'skewer-html-eval-tag)) - - -(use-package! npm-mode - :hook ((js-mode typescript-mode) . npm-mode) - :config - (map! :localleader - (:map npm-mode-keymap - "n" npm-mode-command-keymap) - (:after js2-mode - :map js2-mode-map - :prefix ("n" . "npm")))) + (+javascript-common-config 'nodejs-repl-mode)) ;; diff --git a/modules/lang/javascript/doctor.el b/modules/lang/javascript/doctor.el index be3415c2d..3c774e795 100644 --- a/modules/lang/javascript/doctor.el +++ b/modules/lang/javascript/doctor.el @@ -8,3 +8,7 @@ (assert! (or (not (modulep! +tree-sitter)) (modulep! :tools tree-sitter)) "This module requires (:tools tree-sitter)") + +(unless (modulep! +tree-sitter) + (warn! "Typescript support is degraded without +tree-sitter (and Emacs 29+)") + (warn! "No JSX/TSX support without +tree-sitter (and Emacs 29+)")) diff --git a/modules/lang/javascript/packages.el b/modules/lang/javascript/packages.el index 02c79e850..5a61a437a 100644 --- a/modules/lang/javascript/packages.el +++ b/modules/lang/javascript/packages.el @@ -2,18 +2,10 @@ ;;; lang/javascript/packages.el ;; Major modes -(package! rjsx-mode :pin "b697fe4d92cc84fa99a7bcb476f815935ea0d919") -(package! typescript-mode :pin "481df3ad2cdf569d8e6697679669ff6206fbd2f9") +(unless (or (modulep! +tree-sitter) + (fboundp 'treesit-available-p) + (treesit-available-p)) + (package! typescript-mode :pin "481df3ad2cdf569d8e6697679669ff6206fbd2f9")) -;; Tools -(package! js2-refactor :pin "e1177c728ae52a5e67157fb18ee1409d8e95386a") -(package! npm-mode :pin "3ee7c0bad5b7a041d4739ef3aaa06a3dc764e5eb") - -;; Eval +;; Extensions (package! nodejs-repl :pin "130d49b073a50b7aad472ae8cd05848a9840e480") -(package! skewer-mode :pin "e5bed351939c92a1f788f78398583c2f83f1bb3c") - -;; Programming environment -(package! tide :pin "6a35fe355f1442da34b976bf2decf008d6e4f991") -(when (modulep! :tools lookup) - (package! xref-js2 :pin "e215af9eedac69b40942fff9d5514704f9f4d43e")) diff --git a/modules/lang/json/README.org b/modules/lang/json/README.org index 996335237..5bcecde7b 100644 --- a/modules/lang/json/README.org +++ b/modules/lang/json/README.org @@ -15,7 +15,7 @@ This module adds [[https://www.json.org/json-en.html][JSON]] support to Doom Ema (supports [[https://github.com/vscode-langservers/vscode-json-languageserver][vscode-json-languageserver]]). - +tree-sitter :: Leverages tree-sitter for better syntax highlighting and structural text - editing. Requires [[doom-module::tools tree-sitter]]. + editing. Requires Emacs 29.1+ and [[doom-module::tools tree-sitter]]. ** Packages - [[doom-package:counsel-jq]] if [[doom-module::completion ivy]] diff --git a/modules/lang/json/config.el b/modules/lang/json/config.el index cd789b2a0..c4b56b82d 100644 --- a/modules/lang/json/config.el +++ b/modules/lang/json/config.el @@ -2,16 +2,12 @@ (use-package! json-mode :mode "\\.js\\(?:on\\|[hl]int\\(?:rc\\)?\\)\\'" - :init - (when (modulep! +lsp) - (add-hook 'json-mode-local-vars-hook #'lsp! 'append)) - (when (modulep! +tree-sitter) - (add-hook! '(json-mode-local-vars-hook - jsonc-mode-local-vars-hook) - :append #'tree-sitter!)) :config (set-electric! 'json-mode :chars '(?\n ?: ?{ ?})) + (when (modulep! +lsp) + (add-hook 'json-mode-local-vars-hook #'lsp! 'append)) + (map! :after json-mode :map json-mode-map :localleader @@ -24,6 +20,17 @@ "f" #'json-mode-beautify)) +(use-package! json-ts-mode ; 29.1+ only + :when (modulep! +tree-sitter) + :defer t + :init + (set-tree-sitter! 'json-mode 'json-ts-mode + '((json :url "https://github.com/tree-sitter/tree-sitter-json" + :commit "4d770d31f732d50d3ec373865822fbe659e47c75"))) + :config + (when (modulep! +lsp) + (add-hook 'json-ts-mode-local-vars-hook #'lsp! 'append))) + (use-package! counsel-jq :when (modulep! :completion ivy) diff --git a/modules/lang/julia/README.org b/modules/lang/julia/README.org index 97f8094b6..c3fcb25ea 100644 --- a/modules/lang/julia/README.org +++ b/modules/lang/julia/README.org @@ -15,8 +15,8 @@ This module adds support for [[https://julialang.org/][the Julia language]] to D ** Module flags - +lsp :: - Enable LSP support for ~julia-mode~. Requires [[doom-module::tools lsp]] and a langserver - (supports LanguageServer.jl). + Enable LSP support for ~julia-mode~. Requires [[doom-module::tools lsp]] and a + langserver (supports LanguageServer.jl). - +tree-sitter :: Leverages tree-sitter for better syntax highlighting and structural text editing. Requires [[doom-module::tools tree-sitter]]. diff --git a/modules/lang/julia/config.el b/modules/lang/julia/config.el index 462b42b10..99850f6f1 100644 --- a/modules/lang/julia/config.el +++ b/modules/lang/julia/config.el @@ -4,14 +4,11 @@ :interpreter "julia" :config (unless (modulep! +snail) - (set-repl-handler! 'julia-mode #'+julia/open-repl)) + (set-repl-handler! '(julia-mode julia-ts-mode) #'+julia/open-repl)) (when (modulep! +lsp) (add-hook 'julia-mode-local-vars-hook #'lsp! 'append)) - (when (modulep! +tree-sitter) - (add-hook 'julia-mode-local-vars-hook #'tree-sitter! 'append)) - ;; Borrow matlab.el's fontification of math operators. From ;; (dolist (mode '(julia-mode ess-julia-mode)) @@ -47,9 +44,21 @@ 1 font-lock-type-face))))) +(use-package! julia-ts-mode + :when (modulep! +tree-sitter) + :defer t + :init + (set-tree-sitter! 'julia-mode 'julia-ts-mode + '((julia :url "https://github.com/tree-sitter/tree-sitter-julia"))) + :config + (when (modulep! +lsp) + (add-hook 'julia-ts-mode-local-vars-hook #'lsp! 'append))) + + (use-package! julia-repl :preface (defvar +julia-repl-start-hook nil) :hook (julia-mode . julia-repl-mode) + :hook (julia-ts-mode . julia-repl-mode) :hook (+julia-repl-start . +julia-override-repl-escape-char-h) :hook (+julia-repl-start . julia-repl-use-emacsclient) :config @@ -95,7 +104,8 @@ :after eglot :init ;; Prevent timeout while installing LanguageServer.jl - (setq-hook! 'julia-mode-hook eglot-connect-timeout (max eglot-connect-timeout 60)) + (setq-hook! '(julia-mode-hook julia-ts-mode-hook) + eglot-connect-timeout (max eglot-connect-timeout 60)) :config (eglot-jl-init)) @@ -103,6 +113,7 @@ :when (modulep! +snail) :when (modulep! :term vterm) :hook (julia-mode . julia-snail-mode) + :hook (julia-ts-mode . julia-snail-mode) :config (set-popup-rule! "^\\*julia.*\\*$" :ttl nil :select nil :quit nil) diff --git a/modules/lang/julia/packages.el b/modules/lang/julia/packages.el index 6d45f02e5..c35b03300 100644 --- a/modules/lang/julia/packages.el +++ b/modules/lang/julia/packages.el @@ -4,6 +4,9 @@ (package! julia-mode :pin "5c940c4ba357d8361534f11169f3d40b2d7833fc") (package! julia-repl :pin "317d56021889a336b4be241604ba71e46dc80581") +(when (modulep! +tree-sitter) + (package! julia-ts-mode :pin "d693c6b35d3aed986b2700a3b5f910de12d6c53c")) + (when (modulep! +lsp) (if (modulep! :tools lsp +eglot) (package! eglot-jl :pin "7c968cc61fb64016ebe6dc8ff83fd05923db4374") diff --git a/modules/lang/kotlin/README.org b/modules/lang/kotlin/README.org index af35162ab..878071c01 100644 --- a/modules/lang/kotlin/README.org +++ b/modules/lang/kotlin/README.org @@ -13,10 +13,14 @@ This module adds [[https://kotlinlang.org/][Kotlin]] support to Doom Emacs. - +lsp :: Enable LSP support for ~kotlin-mode~. Requires [[doom-module::tools lsp]] and a langserver (supports [[https://github.com/emacs-lsp/lsp-mode][kotlin-language-server]]). +- +tree-sitter :: + Leverages tree-sitter for better syntax highlighting and structural text + editing. Requires Emacs 29.1+ and [[doom-module::tools tree-sitter]]. ** Packages - [[doom-package:flycheck-kotlin]] if [[doom-module::checkers syntax]] - [[doom-package:kotlin-mode]] +- [[doom-package:kotlin-ts-mode]] ** Hacks /No hacks documented for this module./ diff --git a/modules/lang/kotlin/config.el b/modules/lang/kotlin/config.el index db22b89ac..06a6a34bb 100644 --- a/modules/lang/kotlin/config.el +++ b/modules/lang/kotlin/config.el @@ -1,11 +1,12 @@ ;;; lang/kotlin/config.el -*- lexical-binding: t; -*- (after! kotlin-mode - (when (modulep! +lsp) - (add-hook 'kotlin-mode-local-vars-hook #'lsp! 'append)) (set-docsets! 'kotlin-mode "Kotlin") (set-repl-handler! 'kotlin-mode #'kotlin-repl) + (when (modulep! +lsp) + (add-hook 'kotlin-mode-local-vars-hook #'lsp! 'append)) + (map! :map kotlin-mode-map :localleader :prefix ("b" . "build") @@ -17,3 +18,15 @@ (use-package! flycheck-kotlin :when (modulep! :checkers syntax -flymake) :hook (kotlin-mode . flycheck-kotlin-setup)) + + +(use-package! kotlin-ts-mode + :when (modulep! +tree-sitter) + :when (fboundp 'treesit-available-p) + :defer t + :init + (set-tree-sitter! 'kotlin-mode 'kotlin-ts-mode + '((kotlin :url "https://github.com/fwcd/tree-sitter-kotlin"))) + :config + (when (modulep! +lsp) + (add-hook 'kotlin-ts-mode-local-vars-hook #'lsp! 'append))) diff --git a/modules/lang/kotlin/packages.el b/modules/lang/kotlin/packages.el index 8d1c42bc0..849823a42 100644 --- a/modules/lang/kotlin/packages.el +++ b/modules/lang/kotlin/packages.el @@ -3,5 +3,9 @@ (package! kotlin-mode :pin "fddd747e5b4736e8b27a147960f369b86179ddff") +(when (and (modulep! +tree-sitter) + (fboundp 'treesit-available-p)) + (package! kotlin-ts-mode :pin "a25d56cecac9160ba7c140f982ec16ca7b2fe97f")) + (when (modulep! :checkers syntax -flymake) (package! flycheck-kotlin :pin "a2a6abb9a7f85c6fb15ce327459ec3c8ff780188")) diff --git a/modules/lang/lua/README.org b/modules/lang/lua/README.org index a07e0ecec..ffdfbb6af 100644 --- a/modules/lang/lua/README.org +++ b/modules/lang/lua/README.org @@ -24,8 +24,8 @@ This module adds Lua support to Doom Emacs. (supports EmmyLua, lua-language-server, and lua-lsp). - +tree-sitter :: Leverages tree-sitter for better syntax highlighting and structural text - editing. Requires [[doom-module::tools tree-sitter]]. Has support for both Lua and - Fennel. + editing. Requires Emacs 30.1+ and [[doom-module::tools tree-sitter]]. Only + supports Lua at the moment. - +moonscript :: Enable support for the Moonscript language. diff --git a/modules/lang/lua/autoload/lua.el b/modules/lang/lua/autoload/lua.el index fb10215e8..e5e19b2c1 100644 --- a/modules/lang/lua/autoload/lua.el +++ b/modules/lang/lua/autoload/lua.el @@ -1,5 +1,26 @@ ;;; lang/lua/autoload/lua.el -*- lexical-binding: t; -*- +;;;###autoload +(defvar +lua-lsp-dir (concat doom-data-dir "lsp/lua-language-server/") + "Absolute path to the directory of sumneko's lua-language-server. + +This directory MUST contain the 'main.lua' file and be the in-source build of +lua-language-server.") + +;;;###autoload +(defun +lua-generate-lsp-server-command () + ;; The absolute path to lua-language-server binary is necessary because the + ;; bundled dependencies aren't found otherwise. The only reason this is a + ;; function is to dynamically change when/if `+lua-lsp-dir' does + (list (or (executable-find "lua-language-server") + (doom-path +lua-lsp-dir + (cond ((featurep :system 'macos) "bin/macOS") + ((featurep :system 'linux) "bin/Linux") + ((featurep :system 'windows) "bin/Windows")) + "lua-language-server")) + "-E" "-e" "LANG=en" + (doom-path +lua-lsp-dir "main.lua"))) + (defun +lua-love-build-command () (when-let (root (+lua-love-project-root)) (format "%s %s" diff --git a/modules/lang/lua/config.el b/modules/lang/lua/config.el index 34b0d2c39..0314fafeb 100644 --- a/modules/lang/lua/config.el +++ b/modules/lang/lua/config.el @@ -7,44 +7,34 @@ ;; ;;; Major modes +(defun +lua-common-config (mode) + (set-lookup-handlers! mode :documentation 'lua-search-documentation) + (set-electric! mode :words '("else" "end")) + (set-repl-handler! mode #'+lua/open-repl) + (set-company-backend! mode '(company-lua company-yasnippet)) + (when (modulep! +lsp) + (add-hook (intern (format "%s-local-vars-hook" mode)) #'lsp! 'append) + (when (modulep! :tools lsp +eglot) + (set-eglot-client! mode (+lua-generate-lsp-server-command))))) + + (use-package! lua-mode + :interpreter "\\ p]]), to provide live github-style previews of your markdown (or org) files. +- +tree-sitter :: + Leverages tree-sitter for better syntax highlighting and structural text + editing. Requires [[doom-module::tools tree-sitter]]. Note that tree-sitter + support on Emacs 31 is superior to 30 and under. ** Packages - [[doom-package:edit-indirect]] - [[doom-package:evil-markdown]] if [[doom-module::editor evil +everywhere]] - [[doom-package:grip-mode]] if [[doom-module:+grip]] +- [[doom-package:markdown-ts-mode]] if [[doom-module:+tree-sitter]] - [[doom-package:markdown-mode]] - [[doom-package:markdown-toc]] diff --git a/modules/lang/markdown/config.el b/modules/lang/markdown/config.el index 4070c481e..cdd82325d 100644 --- a/modules/lang/markdown/config.el +++ b/modules/lang/markdown/config.el @@ -130,6 +130,13 @@ capture, the end position, and the output buffer.") :desc "GFM checkbox" "x" #'markdown-toggle-gfm-checkbox))) +(use-package! markdown-ts-mode ; 31+ only + :when (modulep! +tree-sitter) + :defer t + :init + (set-tree-sitter! 'markdown-mode 'markdown-ts-mode '(markdown markdown-inline))) + + (use-package! evil-markdown :when (modulep! :editor evil +everywhere) :hook (markdown-mode . evil-markdown-mode) diff --git a/modules/lang/markdown/doctor.el b/modules/lang/markdown/doctor.el index e70cb8d82..b09f53535 100644 --- a/modules/lang/markdown/doctor.el +++ b/modules/lang/markdown/doctor.el @@ -1,6 +1,10 @@ ;; -*- lexical-binding: t; no-byte-compile: t; -*- ;;; lang/markdown/doctor.el +(assert! (or (not (modulep! +tree-sitter)) + (modulep! :tools tree-sitter)) + "This module requires (:tools tree-sitter)") + (when (require 'markdown-mode nil t) (cond ((eq markdown-command #'+markdown-compile) (unless (cl-loop for (exe . cmd) in (list (cons "marked" '+markdown-compile-marked) diff --git a/modules/lang/markdown/packages.el b/modules/lang/markdown/packages.el index ad0c67fff..27ddaae0c 100644 --- a/modules/lang/markdown/packages.el +++ b/modules/lang/markdown/packages.el @@ -8,6 +8,11 @@ ;; present when you call `markdown-edit-code-block'. (package! edit-indirect :pin "82a28d8a85277cfe453af464603ea330eae41c05") +(when (modulep! +tree-sitter) + (package! markdown-ts-mode + :built-in 'prefer ; Emacs 31+ has a superior markdown-ts-mode + :pin "2f1ee8b94cdf53cebc31ae08ecfbba846193d5e1")) + (when (modulep! +grip) (package! grip-mode :pin "11fecd5b38c78597ff53a39fb3a090e7c80350fa")) diff --git a/modules/lang/nix/README.org b/modules/lang/nix/README.org index 1752a3b84..e4931cee7 100644 --- a/modules/lang/nix/README.org +++ b/modules/lang/nix/README.org @@ -19,20 +19,18 @@ Includes: [[doom-contrib-maintainer:][Become a maintainer?]] ** Module flags +- +lsp :: + Enable an LSP hook for ~nix-mode~. Requires [[doom-module::tools lsp]] and a + language server (one of either ~nil~ or ~rnix-lsp~). - +tree-sitter :: Leverages tree-sitter for better syntax highlighting and structural text - editing. Requires [[doom-module::tools tree-sitter]]. -- +lsp :: - Enable an LSP hook for ~nix-mode~. Requires [[doom-module::tools lsp]] and a language - server (one of either ~nil~ or ~rnix-lsp~). - - You can still start a nix lsp manually without this flag, this just adds - a hook to always start the lsp when loading ~nix-mode~. + editing. Requires Emacs 29.1+ and [[doom-module::tools tree-sitter]]. ** Packages - [[doom-package:company-nixos-options]] if [[doom-module::completion company]] - [[doom-package:helm-nixos-options]] if [[doom-module::completion helm]] - [[doom-package:nix-mode]] +- [[doom-package:nix-ts-mode]] if [[doom-module:+tree-sitter]] - [[doom-package:nix-update]] ** Hacks diff --git a/modules/lang/nix/config.el b/modules/lang/nix/config.el index 10bfb1731..035e5f418 100644 --- a/modules/lang/nix/config.el +++ b/modules/lang/nix/config.el @@ -7,33 +7,25 @@ ;; ;;; Plugins -(use-package! nix-mode - :interpreter ("\\(?:cached-\\)?nix-shell" . +nix-shell-init-mode) - :mode "\\.nix\\'" - :init - (add-to-list 'auto-mode-alist - (cons "/flake\\.lock\\'" - (if (modulep! :lang json) - 'json-mode - 'js-mode))) - :config - (set-repl-handler! 'nix-mode #'+nix/open-repl) - (set-company-backend! 'nix-mode 'company-nixos-options) - (set-lookup-handlers! 'nix-mode +(add-to-list 'auto-mode-alist + (cons "/flake\\.lock\\'" + (if (modulep! :lang json) + 'json-mode + 'js-mode))) + + +(defun +nix-common-config (mode) + (set-repl-handler! mode #'+nix/open-repl) + (set-company-backend! mode 'company-nixos-options) + (set-lookup-handlers! mode :documentation '(+nix/lookup-option :async t)) (set-popup-rule! "^\\*nixos-options-doc\\*$" :ttl 0 :quit t) - ;; Fix #3927: disable idle completion because `company-nixos-options' is - ;; dreadfully slow. It can still be invoked manually.. - (setq-hook! 'nix-mode-hook company-idle-delay nil) - (when (modulep! +lsp) - (add-hook 'nix-mode-local-vars-hook #'lsp! 'append)) - (when (modulep! +tree-sitter) - (add-hook 'nix-mode-local-vars-hook #'tree-sitter! 'append)) + (add-hook (intern (format "%s-local-vars-hook" mode)) #'lsp! 'append)) (map! :localleader - :map nix-mode-map + :map ,(intern (format "%s-map" mode)) "f" #'nix-update-fetch "p" #'nix-format-buffer "r" #'nix-repl-show @@ -43,6 +35,32 @@ "o" #'+nix/lookup-option)) +(use-package! nix-mode + :interpreter ("\\(?:cached-\\)?nix-shell" . +nix-shell-init-mode) + :mode "\\.nix\\'" + :config + (+nix-common-config 'nix-mode)) + + +(use-package! nix-ts-mode + :when (modulep! +tree-sitter) + :when (fboundp 'treesit-available-p) + :defer t + :init + (set-tree-sitter! 'nix-mode 'nix-ts-mode + '((nix :url "https://github.com/nix-community/tree-sitter-nix"))) + :config + (+nix-common-config 'nix-ts-mode)) + + +(use-package! company-nixos-options + :defer t + :init + ;; Fix #3927: disable idle completion because `company-nixos-options' is + ;; dreadfully slow. It can still be invoked manually.. + (setq-hook! '(nix-mode-hook nix-ts-mode-hook) company-idle-delay nil)) + + (use-package! nix-update :commands nix-update-fetch) diff --git a/modules/lang/nix/doctor.el b/modules/lang/nix/doctor.el index 366d273e7..1a8c0f0e3 100644 --- a/modules/lang/nix/doctor.el +++ b/modules/lang/nix/doctor.el @@ -1,13 +1,13 @@ ;; -*- lexical-binding: t; no-byte-compile: t; -*- ;;; lang/nix/doctor.el +(assert! (or (modulep! -tree-sitter) + (modulep! :tools tree-sitter)) + "This module requires (:tools tree-sitter)") + (unless (executable-find "nix") (warn! "Couldn't find the nix package manager. nix-mode won't work.")) (when (require 'nix-mode nil t) (unless (executable-find nix-nixfmt-bin) (warn! (concat "Couldn't find " nix-nixfmt-bin ". nix-format-buffer won't work.")))) - -(assert! (or (modulep! -tree-sitter) - (modulep! :tools tree-sitter)) - "This module requires (:tools tree-sitter)") diff --git a/modules/lang/nix/packages.el b/modules/lang/nix/packages.el index 6ce4debbc..f76d55da8 100644 --- a/modules/lang/nix/packages.el +++ b/modules/lang/nix/packages.el @@ -4,6 +4,10 @@ (package! nix-mode :pin "719feb7868fb567ecfe5578f6119892c771ac5e5") (package! nix-update :pin "77022ccd918d665acbb519b243e7e3dc5eae1c47") +(when (and (modulep! +tree-sitter) + (fboundp 'treesit-available-p)) + (package! nix-ts-mode :pin "62ce3a2dc39529c5db3516427e84b2c96b8efcfd")) + (when (modulep! :completion company) (package! company-nixos-options :pin "053a2d5110ce05b7f99bcc2ac4804b70cbe87916")) diff --git a/modules/lang/ocaml/README.org b/modules/lang/ocaml/README.org index c062f1aec..d6b824b35 100644 --- a/modules/lang/ocaml/README.org +++ b/modules/lang/ocaml/README.org @@ -23,9 +23,6 @@ This module adds [[https://ocaml.org/][OCaml]] support to Doom Emacs, powered by - +lsp :: Enable LSP support for ~tuareg-mode~. Requires [[doom-module::tools lsp]] and a langserver (supports [[https://github.com/freebroccolo/ocaml-language-server][ocaml-language-server]]). -- +tree-sitter :: - Leverages tree-sitter for better syntax highlighting and structural text - editing. Requires [[doom-module::tools tree-sitter]]. ** Packages - [[doom-package:dune]] diff --git a/modules/lang/ocaml/config.el b/modules/lang/ocaml/config.el index 4ca5805d5..a270252f0 100644 --- a/modules/lang/ocaml/config.el +++ b/modules/lang/ocaml/config.el @@ -130,10 +130,6 @@ (opam-switch-set-switch (tuareg-opam-current-compiler))) -(when (modulep! +tree-sitter) - (add-hook 'tuareg-mode-local-vars-hook #'tree-sitter!)) - - (use-package! dune :defer t :config diff --git a/modules/lang/ocaml/doctor.el b/modules/lang/ocaml/doctor.el index 07facc1d3..4879155b9 100644 --- a/modules/lang/ocaml/doctor.el +++ b/modules/lang/ocaml/doctor.el @@ -5,10 +5,6 @@ (modulep! :tools lsp)) "This module requires (:tools lsp)") -(assert! (or (not (modulep! +tree-sitter)) - (modulep! :tools tree-sitter)) - "This module requires (:tools tree-sitter)") - (unless (executable-find "ocamlmerlin") (warn! "Couldn't find ocamlmerlin. Lookup, completion and syntax checking won't work")) diff --git a/modules/lang/php/README.org b/modules/lang/php/README.org index 321ce8177..24f7c1f31 100644 --- a/modules/lang/php/README.org +++ b/modules/lang/php/README.org @@ -36,7 +36,7 @@ This module adds support for PHP 5.3+ (including PHP8) to Doom Emacs. langserver (supports [[https://emacs-lsp.github.io/lsp-mode/page/lsp-phpactor/][phpactor]], [[https://emacs-lsp.github.io/lsp-mode/page/lsp-intelephense/][intelephense]], [[https://emacs-lsp.github.io/lsp-mode/page/lsp-serenata/][serenata]], [[https://emacs-lsp.github.io/lsp-mode/page/lsp-php/][php-language-server]]). - +tree-sitter :: Leverages tree-sitter for better syntax highlighting and structural text - editing. Requires [[doom-module::tools tree-sitter]]. + editing. Requires [[doom-module::tools tree-sitter]] and Emacs 30.1+. ** Packages - [[doom-package:async]] diff --git a/modules/lang/php/config.el b/modules/lang/php/config.el index 849200d81..85382b068 100644 --- a/modules/lang/php/config.el +++ b/modules/lang/php/config.el @@ -17,17 +17,11 @@ ;; ;;; Packages -(use-package! php-mode - :mode "\\.inc\\'" - :config - ;; Disable HTML compatibility in php-mode. `web-mode' has superior support for - ;; php+html. Use the .phtml extension instead. - (setq php-mode-template-compatibility nil) - - (set-docsets! 'php-mode "PHP" "PHPUnit" "Laravel" "CakePHP" "CodeIgniter" "Doctrine_ORM") - (set-repl-handler! 'php-mode #'+php/open-repl) - (set-lookup-handlers! 'php-mode :documentation #'php-search-documentation) - (set-ligatures! 'php-mode +(defun +php-common-config (mode) + (set-docsets! mode "PHP" "PHPUnit" "Laravel" "CakePHP" "CodeIgniter" "Doctrine_ORM") + (set-repl-handler! mode #'+php/open-repl) + (set-lookup-handlers! mode :documentation #'php-search-documentation) + (set-ligatures! mode ;; Functional :lambda "function()" :lambda "fn" :def "function" @@ -45,31 +39,61 @@ :return "return" :yield "use") - (when (modulep! +lsp) - (when (executable-find "php-language-server.php") - (setq lsp-clients-php-server-command "php-language-server.php")) - (add-hook 'php-mode-local-vars-hook #'lsp! 'append)) + (let ((mode-vars-hook (intern (format "%s-local-vars-hook" mode))) + (mode-map (intern (format "%s-map" mode)))) + (sp-with-modes (ensure-list mode) + (sp-local-pair "" :post-handlers '(("| " "SPC" "=") ("||\n[i]" "RET") ("[d2]" "p"))) + (sp-local-pair "" :post-handlers '(("| " "SPC") ("||\n[i]" "RET")))) - (when (modulep! +tree-sitter) - (add-hook 'php-mode-local-vars-hook #'tree-sitter! 'append)) + (if (modulep! -lsp) + ;; `+php-company-backend' uses `php-extras-company' or + ;; `company-dabbrev-code', in that order. + (when +php--company-backends + (set-company-backend! mode + (cons :separate +php--company-backends) + 'company-dabbrev-code)) + (when (executable-find "php-language-server.php") + (setq lsp-clients-php-server-command "php-language-server.php")) + (add-hook mode-vars-hook #'lsp! 'append)) - ;; Use the smallest `sp-max-pair-length' for optimum `smartparens' performance - (setq-hook! 'php-mode-hook sp-max-pair-length 5) + (map! :localleader + :map ,mode-map + :prefix ("t" . "test") + "r" #'phpunit-current-project + "a" #'phpunit-current-class + "s" #'phpunit-current-test))) - (sp-with-modes '(php-mode) - (sp-local-pair "" :post-handlers '(("| " "SPC" "=") ("||\n[i]" "RET") ("[d2]" "p"))) - (sp-local-pair "" :post-handlers '(("| " "SPC") ("||\n[i]" "RET")))) - (map! :localleader - :map php-mode-map - :prefix ("t" . "test") - "r" #'phpunit-current-project - "a" #'phpunit-current-class - "s" #'phpunit-current-test)) +(use-package! php-mode + :hook (php-mode . rainbow-delimiters-mode) + :config + (+php-common-config 'php-mode) + + ;; Disable HTML compatibility in php-mode. `web-mode' has superior support for + ;; php+html. Use the .phtml extension instead. + (setq php-mode-template-compatibility nil)) + + +(use-package! php-ts-mode + :when (modulep! +tree-sitter) + :defer t + :init + (set-tree-sitter! 'php-mode 'php-ts-mode + '((php :url "https://github.com/tree-sitter/tree-sitter-php" + :rev "v0.23.11" + :commit "f7cf7348737d8cff1b13407a0bfedce02ee7b046" + :source-dir "php/src") + (phpdoc :url "https://github.com/claytonrcarter/tree-sitter-phpdoc" + :commit "03bb10330704b0b371b044e937d5cc7cd40b4999") + html css ; requires :lang (web +tree-sitter) + javascript jsdoc)) ; requires :lang (javascript +tree-sitter) + :config + (+php-common-config 'php-ts-mode)) (use-package! php-refactor-mode :hook php-mode + :hook php-ts-mode :config (map! :localleader :map php-refactor-mode-map @@ -88,10 +112,9 @@ (use-package! composer :defer t :init - (map! :after php-mode - :localleader - :map php-mode-map - :prefix ("c" . "composer") + (setq composer-directory-to-managed-file (file-name-concat doom-etc-dir "composer/")) + (defvar +php-common-mode-map (make-sparse-keymap)) + (map! :map +php-common-mode-map "c" #'composer "i" #'composer-install "r" #'composer-require @@ -100,23 +123,29 @@ "s" #'composer-run-script "v" #'composer-run-vendor-bin-command "o" #'composer-find-json-file - "l" #'composer-view-lock-file)) + "l" #'composer-view-lock-file) + (map! :after php-mode + :map php-mode-map + :desc "composer" "c" +php-common-mode-map) + (map! :after php-ts-mode + :map php-ts-mode-map + :desc "composer" "c" +php-common-mode-map)) ;; ;; Projects (def-project-mode! +php-laravel-mode - :modes '(php-mode yaml-mode web-mode nxml-mode js2-mode scss-mode) + :modes '(php-mode php-ts-mode yaml-mode web-mode nxml-mode js2-mode scss-mode) :files (and "artisan" "server.php")) (def-project-mode! +php-composer-mode - :modes '(web-mode php-mode) + :modes '(web-mode php-mode php-ts-mode) :files ("composer.json")) (def-project-mode! +phpunit-docker-compose-mode :when +php-run-tests-in-docker - :modes '(php-mode docker-compose-mode) + :modes '(php-mode php-ts-mode docker-compose-mode) :files (and "phpunit.xml" (or +php-default-docker-compose "docker-compose.yml")) :on-enter (setq phpunit-args `("exec" ,+php-default-docker-container "php" "vendor/bin/phpunit") diff --git a/modules/lang/php/doctor.el b/modules/lang/php/doctor.el index 6094a4c75..e72e73fcc 100644 --- a/modules/lang/php/doctor.el +++ b/modules/lang/php/doctor.el @@ -5,9 +5,15 @@ (modulep! :tools lsp)) "This module requires (:tools lsp)") -(assert! (or (not (modulep! +tree-sitter)) - (modulep! :tools tree-sitter)) - "This module requires (:tools tree-sitter)") +(when (modulep! +tree-sitter) + (assert! (modulep! :tools tree-sitter) + "This module requires (:tools tree-sitter)") + (assert! (fboundp 'php-ts-mode) + "Can't find `php-ts-mode'; Emacs 30.1+ is required") + (unless (modulep! :lang javascript +tree-sitter) + (error! "(:lang (javascript +tree-sitter)) required, but not enabled")) + (unless (modulep! :lang web +tree-sitter) + (error! "(:lang (web +tree-sitter)) required, but not enabled"))) (unless (executable-find "php") (warn! "Couldn't find php in your PATH")) diff --git a/modules/lang/python/autoload/pyenv.el b/modules/lang/python/autoload/pyenv.el index a129cd5b4..9fd159832 100644 --- a/modules/lang/python/autoload/pyenv.el +++ b/modules/lang/python/autoload/pyenv.el @@ -7,7 +7,7 @@ ;;;###autoload (defun +python-pyenv-mode-set-auto-h () "Set pyenv-mode version from buffer-local variable." - (when (eq major-mode 'python-mode) + (when (memq major-mode '(python-mode python-ts-mode)) (when (not (local-variable-p '+pyenv--version)) (make-local-variable '+pyenv--version) (setq +pyenv--version (+python-pyenv-read-version-from-file))) diff --git a/modules/lang/python/config.el b/modules/lang/python/config.el index 1cbb9f529..527c0cfb4 100644 --- a/modules/lang/python/config.el +++ b/modules/lang/python/config.el @@ -14,28 +14,39 @@ ;;; Packages (use-package! python - :mode ("[./]flake8\\'" . conf-mode) - :mode ("/Pipfile\\'" . conf-mode) + :mode ("/\\(?:Pipfile\\|\\.?flake8\\)\\'" . conf-mode) :init (setq python-environment-directory doom-cache-dir python-indent-guess-indent-offset-verbose nil) + (when (modulep! +tree-sitter) + (set-tree-sitter! 'python-mode 'python-ts-mode + '((python :url "https://github.com/tree-sitter/tree-sitter-python" + :commit "bffb65a8cfe4e46290331dfef0dbf0ef3679de11")))) + + :config + ;; HACK: `python-base-mode' (and `python-ts-mode') don't exist on pre-29 + ;; versions of Emacs, Rather than litter this module with conditionals, I + ;; shim the keymap in. + (unless (boundp 'python-base-mode-map) + (defvaralias 'python-base-mode-map 'python-mode-map)) + (when (modulep! +lsp) (add-hook 'python-mode-local-vars-hook #'lsp! 'append) + (add-hook 'python-ts-mode-local-vars-hook #'lsp! 'append) ;; Use "mspyls" in eglot if in PATH (when (executable-find "Microsoft.Python.LanguageServer") - (set-eglot-client! 'python-mode '("Microsoft.Python.LanguageServer")))) + (set-eglot-client! '(python-mode python-ts-mode) '("Microsoft.Python.LanguageServer")))) - (when (modulep! +tree-sitter) - (add-hook 'python-mode-local-vars-hook #'tree-sitter! 'append)) - :config - (set-repl-handler! 'python-mode #'+python/open-repl + (set-repl-handler! '(python-mode python-ts-mode) #'+python/open-repl :persist t :send-region #'python-shell-send-region :send-buffer #'python-shell-send-buffer) - (set-docsets! '(python-mode inferior-python-mode) "Python 3" "NumPy" "SciPy" "Pandas") - (set-ligatures! 'python-mode + (set-docsets! '(python-mode python-ts-mode inferior-python-mode) + "Python 3" "NumPy" "SciPy" "Pandas") + + (set-ligatures! '(python-mode python-ts-mode) ;; Functional :def "def" :lambda "lambda" @@ -62,7 +73,7 @@ (executable-find "python3")) (setq python-shell-interpreter "python3")) - (add-hook! 'python-mode-hook + (add-hook! '(python-mode-hook python-ts-mode-hook) (defun +python-use-correct-flycheck-executables-h () "Use the correct Python executables for Flycheck." (let ((executable python-shell-interpreter)) @@ -86,14 +97,16 @@ (advice-add #'pythonic-activate :after-while #'+modeline-update-env-in-all-windows-h) (advice-add #'pythonic-deactivate :after #'+modeline-clear-env-in-all-windows-h)) - (setq-hook! 'python-mode-hook tab-width python-indent-offset)) + ;; HACK: `python-mode' doesn't update `tab-width' to reflect + ;; `python-indent-offset', causing issues anywhere `tab-width' is respected. + (setq-hook! '(python-mode-hook python-ts-mode-hook) tab-width python-indent-offset)) (use-package! pyimport :defer t :init (map! :after python - :map python-mode-map + :map python-base-mode-map :localleader :prefix ("i" . "imports") :desc "Insert missing imports" "i" #'pyimport-insert-missing @@ -105,12 +118,13 @@ :defer t :init (map! :after python - :map python-mode-map + :map python-base-mode-map :localleader (:prefix ("i" . "imports") :desc "Sort imports" "s" #'py-isort-buffer :desc "Sort region" "r" #'py-isort-region))) + (use-package! nose :commands nose-mode :preface (defvar nose-mode-map (make-sparse-keymap)) @@ -138,7 +152,7 @@ :init (map! :after python :localleader - :map python-mode-map + :map python-base-mode-map :prefix ("t" . "test") "a" #'python-pytest "f" #'python-pytest-file-dwim @@ -157,7 +171,7 @@ :hook (python-mode . pipenv-mode) :init (setq pipenv-with-projectile nil) :config - (set-eval-handler! 'python-mode + (set-eval-handler! '(python-mode python-ts-mode) '((:command . (lambda () python-shell-interpreter)) (:exec (lambda () (if-let* ((bin (executable-find "pipenv" t)) @@ -165,7 +179,7 @@ (format "PIPENV_MAX_DEPTH=9999 %s run %%c %%o %%s %%a" bin) "%c %o %s %a"))) (:description . "Run Python script"))) - (map! :map python-mode-map + (map! :map python-base-mode-map :localleader :prefix ("e" . "pipenv") :desc "activate" "a" #'pipenv-activate @@ -185,7 +199,8 @@ (add-hook 'pyvenv-post-activate-hooks #'+modeline-update-env-in-all-windows-h) (add-hook 'pyvenv-pre-deactivate-hooks #'+modeline-clear-env-in-all-windows-h)) :config - (add-hook 'python-mode-local-vars-hook #'pyvenv-track-virtualenv) + (add-hook! '(python-mode-local-vars-hook python-ts-mode-local-vars-hook) + #'pyvenv-track-virtualenv) (add-to-list 'global-mode-string '(pyvenv-virtual-env-name (" venv:" pyvenv-virtual-env-name " ")) 'append)) @@ -199,7 +214,8 @@ (when (executable-find "pyenv") (pyenv-mode +1) (add-to-list 'exec-path (expand-file-name "shims" (or (getenv "PYENV_ROOT") "~/.pyenv")))) - (add-hook 'python-mode-local-vars-hook #'+python-pyenv-mode-set-auto-h) + (add-hook! '(python-mode-local-vars-hook python-ts-mode-local-vars-hook) + #'+python-pyenv-mode-set-auto-h) (add-hook 'doom-switch-buffer-hook #'+python-pyenv-mode-set-auto-h)) diff --git a/modules/lang/python/doctor.el b/modules/lang/python/doctor.el index 65928df91..47af20fcd 100644 --- a/modules/lang/python/doctor.el +++ b/modules/lang/python/doctor.el @@ -8,6 +8,10 @@ (modulep! :tools tree-sitter)) "This module requires (:tools tree-sitter)") +(assert! (or (not (modulep! +tree-sitter)) + (fboundp 'python-ts-mode)) + "Can't find `python-ts-mode'; Emacs 29.1+ is required") + (if (not (or (executable-find "python") (executable-find "python3"))) (error! "Couldn't find python in your PATH") diff --git a/modules/lang/qt/README.org b/modules/lang/qt/README.org index 2470b3b5d..a549e0292 100644 --- a/modules/lang/qt/README.org +++ b/modules/lang/qt/README.org @@ -13,10 +13,16 @@ This module provides language functionality for [[https://qt.io][Qt]] specific f *This module needs a maintainer.* [[doom-contrib-maintainer:][Become a maintainer?]] ** Module flags -/This module has no flags./ +- +lsp :: + Enable LSP support for ~qml-mode~/~qml-ts-mode~. Requires [[doom-module::tools lsp]] + and a langserver (supports [[https://doc.qt.io/qt-6/qtqml-tooling-qmlls.html][qmlls]]). +- +tree-sitter :: + Leverages tree-sitter for better syntax highlighting and structural text + editing. Requires [[doom-module::tools tree-sitter]]. ** Packages - [[doom-package:qml-mode]] +- [[doom-package:qml-ts-mode]] if [[doom-module:+tree-sitter]] - [[doom-package:qt-pro-mode]] ** Hacks diff --git a/modules/lang/qt/autoload.el b/modules/lang/qt/autoload.el deleted file mode 100644 index ba5db146c..000000000 --- a/modules/lang/qt/autoload.el +++ /dev/null @@ -1,4 +0,0 @@ -;;; lang/qt/autoload.el -*- lexical-binding: t; -*- - -;;;###autoload -(add-to-list 'auto-mode-alist '("\\.pr[io]\\'" . qt-pro-mode)) diff --git a/modules/lang/qt/config.el b/modules/lang/qt/config.el new file mode 100644 index 000000000..afcd94357 --- /dev/null +++ b/modules/lang/qt/config.el @@ -0,0 +1,27 @@ +;;; lang/qt/config.el -*- lexical-binding: t; -*- + +(defun +qt-common-config (mode) + (when (modulep! +lsp) + (set-eglot-client! mode '("qmlls")) + (add-hook (intern (format "%s-local-vars-hook" mode)) #'lsp! 'append))) + + +(use-package! qml-mode + :defer t + :config + (+qt-common-config 'qml-mode)) + + +(use-package! qml-ts-mode + :when (modulep! +tree-sitter) + :when (fboundp 'treesit-available-p) + :defer t + :init + (set-tree-sitter! 'qml-mode 'qml-ts-mode + '((qmljs :url "https://github.com/yuja/tree-sitter-qmljs"))) + :config + (+qt-common-config 'qml-ts-mode)) + + +(use-package! qt-pro-mode + :mode "\\.pr[io]\\'") diff --git a/modules/lang/qt/doctor.el b/modules/lang/qt/doctor.el new file mode 100644 index 000000000..1fb1dd978 --- /dev/null +++ b/modules/lang/qt/doctor.el @@ -0,0 +1,9 @@ +;;; lang/qt/doctor.el -*- lexical-binding: t; -*- + +(assert! (or (not (modulep! +lsp)) + (modulep! :tools lsp)) + "This module requires (:tools lsp)") + +(assert! (or (not (modulep! +tree-sitter)) + (modulep! :tools tree-sitter)) + "This module requires (:tools tree-sitter)") diff --git a/modules/lang/qt/packages.el b/modules/lang/qt/packages.el index 22f01ef77..b60c95f0a 100644 --- a/modules/lang/qt/packages.el +++ b/modules/lang/qt/packages.el @@ -3,3 +3,9 @@ (package! qml-mode :pin "6c5f33ba88ae010bf201a80ee8095e20a724558c") (package! qt-pro-mode :pin "7a2da323de834294b413cbbb3c92f42f54913643") + +(when (modulep! +tree-sitter) + (package! qml-ts-mode + :recipe (:host github + :repo "xhcoding/qml-ts-mode") + :pin "b80c6663521b4d0083e416e6712ebc02d37b7aec")) diff --git a/modules/lang/ruby/config.el b/modules/lang/ruby/config.el index 4f0a7c501..4975c2cd4 100644 --- a/modules/lang/ruby/config.el +++ b/modules/lang/ruby/config.el @@ -22,9 +22,6 @@ (when (modulep! +lsp) (add-hook 'ruby-mode-local-vars-hook #'lsp! 'append)) - (when (modulep! +tree-sitter) - (add-hook 'ruby-mode-local-vars-hook #'tree-sitter! 'append)) - (after! inf-ruby (add-hook 'inf-ruby-mode-hook #'doom-mark-buffer-as-real-h) ;; switch to inf-ruby from compile if we detect a breakpoint has been hit @@ -39,6 +36,20 @@ "{" #'ruby-toggle-block)) +(use-package! ruby-ts-mode ; 29.1+ only + :when (modulep! +tree-sitter) + :defer t + :init + (set-tree-sitter! 'ruby-mode 'ruby-ts-mode + '((ruby :url "https://github.com/tree-sitter/tree-sitter-ruby" + :commit "71bd32fb7607035768799732addba884a37a6210"))) + :config + (set-electric! 'ruby-ts-mode :words '("else" "end" "elsif")) + (set-repl-handler! 'ruby-ts-mode #'inf-ruby) + (when (modulep! +lsp) + (add-hook 'ruby-ts-mode-local-vars-hook #'lsp! 'append))) + + (use-package! yard-mode :hook ruby-mode) diff --git a/modules/lang/ruby/doctor.el b/modules/lang/ruby/doctor.el index dfc0ecd66..1ab28a7ac 100644 --- a/modules/lang/ruby/doctor.el +++ b/modules/lang/ruby/doctor.el @@ -8,6 +8,10 @@ (modulep! :tools tree-sitter)) "This module requires (:tools tree-sitter)") +(assert! (or (not (modulep! +tree-sitter)) + (fboundp 'ruby-ts-mode)) + "Can't find `ruby-ts-mode'; Emacs 29.1+ is required") + (unless (executable-find "ruby") (warn! "Ruby isn't installed.")) diff --git a/modules/lang/rust/README.org b/modules/lang/rust/README.org index 93179ad59..c7806b8e9 100644 --- a/modules/lang/rust/README.org +++ b/modules/lang/rust/README.org @@ -26,6 +26,7 @@ e.g. ~cargo~. editing. Requires [[doom-module::tools tree-sitter]]. ** Packages +- [[doom-package:rust-mode]] - [[doom-package:rustic]] ** Hacks diff --git a/modules/lang/rust/config.el b/modules/lang/rust/config.el index 307c509c8..36f1774b6 100644 --- a/modules/lang/rust/config.el +++ b/modules/lang/rust/config.el @@ -8,15 +8,50 @@ ;; ;;; 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\\'" . rustic-mode) + :defer t :preface - ;; 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 the `:mode' directives above to re-insert them - ;; with the correct order. - (setq auto-mode-alist (assoc-delete-all "\\.rs\\'" auto-mode-alist)) + ;; Ensure rust-mode derives from rust-ts-mode, b/c rustic-mode derives from + ;; rust-mode. This way, rustic-mode is the only major mode we have to worry + ;; about. + (setq rust-mode-treesitter-derive (modulep! +tree-sitter)) + + :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 ; 29.1+ only + :when (modulep! +tree-sitter) + :defer t + :init + (set-tree-sitter! 'rust-mode 'rust-ts-mode + `((rust :url "https://github.com/tree-sitter/tree-sitter-rust" + :commit ,(if (and (treesit-available-p) + (< (treesit-library-abi-version) 15)) + "1f63b33efee17e833e0ea29266dd3d713e27e321" + "18b0515fca567f5a10aee9978c6d2640e878671a")))) + + (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 ;; our respective modules standardize how they're initialized. @@ -27,20 +62,20 @@ (remove-hook 'rustic-mode-hook #'flycheck-mode) (remove-hook 'rustic-mode-hook #'flymake-mode-off) (remove-hook 'flycheck-mode-hook #'rustic-flycheck-setup)) + :init ;; 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 - ;; load it all, we must do it early: + ;; load it all, it must be done earlier: (after! org-src (defalias 'org-babel-execute:rust #'org-babel-execute:rustic) (add-to-list 'org-src-lang-modes '("rust" . rustic))) + :config (set-docsets! 'rustic-mode "Rust") (set-popup-rule! "^\\*rustic-compilation" :vslot -1) (set-popup-rule! "^\\*cargo-run" :vslot -1) - (setq rustic-indent-method-chain t) - ;; Leave automatic reformatting to the :editor format module. (setq rustic-babel-format-src-block nil rustic-format-trigger nil) @@ -59,7 +94,7 @@ ;; response of Rust Analyzer, which is not stable enough for `lsp-mode' ;; maintainers (see emacs-lsp/lsp-mode#1740). (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 (when (derived-mode-p 'rust-mode 'rust-ts-mode) (setq lsp--hover-saved-bounds nil))) @@ -83,9 +118,6 @@ (s-join " ")))) (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 ;; package.el. Doom manages its own dependencies through straight so disable ;; this behavior to avoid package-not-initialized errors. @@ -96,17 +128,17 @@ (map! :map rustic-mode-map :localleader (:prefix ("b" . "build") - :desc "cargo audit" "a" #'+rust/cargo-audit - :desc "cargo build" "b" #'rustic-cargo-build - :desc "cargo bench" "B" #'rustic-cargo-bench - :desc "cargo check" "c" #'rustic-cargo-check - :desc "cargo clippy" "C" #'rustic-cargo-clippy - :desc "cargo doc" "d" #'rustic-cargo-build-doc - :desc "cargo doc --open" "D" #'rustic-cargo-doc - :desc "cargo fmt" "f" #'rustic-cargo-fmt - :desc "cargo new" "n" #'rustic-cargo-new - :desc "cargo outdated" "o" #'rustic-cargo-outdated - :desc "cargo run" "r" #'rustic-cargo-run) + :desc "cargo audit" "a" #'+rust/cargo-audit + :desc "cargo build" "b" #'rustic-cargo-build + :desc "cargo bench" "B" #'rustic-cargo-bench + :desc "cargo check" "c" #'rustic-cargo-check + :desc "cargo clippy" "C" #'rustic-cargo-clippy + :desc "cargo doc" "d" #'rustic-cargo-build-doc + :desc "cargo doc --open" "D" #'rustic-cargo-doc + :desc "cargo fmt" "f" #'rustic-cargo-fmt + :desc "cargo new" "n" #'rustic-cargo-new + :desc "cargo outdated" "o" #'rustic-cargo-outdated + :desc "cargo run" "r" #'rustic-cargo-run) (:prefix ("t" . "cargo test") - :desc "all" "a" #'rustic-cargo-test - :desc "current test" "t" #'rustic-cargo-current-test))) + :desc "all" "a" #'rustic-cargo-test + :desc "current test" "t" #'rustic-cargo-current-test))) diff --git a/modules/lang/rust/doctor.el b/modules/lang/rust/doctor.el index a7e3ee467..e813e09d9 100644 --- a/modules/lang/rust/doctor.el +++ b/modules/lang/rust/doctor.el @@ -9,6 +9,10 @@ (modulep! :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") (warn! "Couldn't find rustc binary")) diff --git a/modules/lang/scala/README.org b/modules/lang/scala/README.org index e6107a387..d22a6ab77 100644 --- a/modules/lang/scala/README.org +++ b/modules/lang/scala/README.org @@ -30,11 +30,12 @@ Through the power of [[https://scalameta.org/metals/docs/editors/overview.html][ (supports metals). - +tree-sitter :: Leverages tree-sitter for better syntax highlighting and structural text - editing. Requires [[doom-module::tools tree-sitter]]. + editing. Requires Emacs 29.1+ and [[doom-module::tools tree-sitter]]. ** Packages - [[doom-package:sbt-mode]] - [[doom-package:scala-mode]] +- [[doom-package:scala-ts-mode]] if [[doom-module:+tree-sitter]] - [[doom-package:lsp-metals]] if [[doom-module:+lsp]] ** Hacks diff --git a/modules/lang/scala/config.el b/modules/lang/scala/config.el index d42e879db..6197fe243 100644 --- a/modules/lang/scala/config.el +++ b/modules/lang/scala/config.el @@ -7,24 +7,12 @@ ;; ;;; Packages -(after! scala-mode - (setq scala-indent:align-parameters t - ;; indent block comments to first asterix, not second - scala-indent:use-javadoc-style t) - - (setq-hook! 'scala-mode-hook - comment-line-break-function #'+scala-comment-indent-new-line-fn) - - (when (modulep! +lsp) - (setq-hook! 'scala-mode-hook lsp-enable-indentation nil) - (add-hook 'scala-mode-local-vars-hook #'lsp! 'append)) - - (when (modulep! +tree-sitter) - (add-hook 'scala-mode-local-vars-hook #'tree-sitter! 'append)) - - (set-formatter! 'scalafmt '("scalafmt" "--stdin") :modes '(scala-mode)) - - (set-ligatures! 'scala-mode +(defun +scala-common-config (mode) + (set-formatter! 'scalafmt '("scalafmt" "--stdin") + :modes (list mode)) + (set-repl-handler! mode #'+scala/open-repl + :persist t) + (set-ligatures! mode ;; Functional :def "def" :composition "compose" @@ -49,9 +37,34 @@ ;; Other :union "union" :intersect "intersect" - :diff "diff")) + :diff "diff") + + (when (modulep! +lsp) + (add-hook (intern (format "%s-local-vars-hook" mode)) #'lsp! 'append))) -(use-package! sbt-mode - :after scala-mode - :config (set-repl-handler! 'scala-mode #'+scala/open-repl :persist t)) +(after! scala-mode + (setq scala-indent:align-parameters t + ;; indent block comments to first asterix, not second + scala-indent:use-javadoc-style t) + + (setq-hook! 'scala-mode-hook + comment-line-break-function #'+scala-comment-indent-new-line-fn + lsp-enable-indentation nil) + + (+scala-common-config 'scala-mode)) + + +(use-package! scala-ts-mode + :when (modulep! +tree-sitter) + :when (fboundp 'treesit-available-p) + :defer t + :init + (set-tree-sitter! 'scala-mode 'scala-ts-mode + '((scala :url "https://github.com/tree-sitter/tree-sitter-scala"))) + + :config + (when (modulep! +lsp) + (setq-hook! 'scala-ts-mode-hook lsp-enable-indentation nil)) + + (+scala-common-config 'scala-ts-mode)) diff --git a/modules/lang/scala/packages.el b/modules/lang/scala/packages.el index 6289243ff..ea3e43fa5 100644 --- a/modules/lang/scala/packages.el +++ b/modules/lang/scala/packages.el @@ -4,6 +4,10 @@ (package! sbt-mode :pin "cc68728a6ef0600aad369157b3a2d0ce56afba9b") (package! scala-mode :pin "661337d8aa0a0cb418184c83757661603de3b2e3") +(when (and (modulep! +tree-sitter) + (fboundp 'treesit-available-p)) + (package! scala-ts-mode :pin "c7671e10419261ef70b1820d3b970ad39f6fcfe2")) + (when (and (modulep! +lsp) (modulep! :tools lsp -eglot)) (package! lsp-metals :pin "e1d9d04f3bab7e6e74916054b36ab1a87e831367")) diff --git a/modules/lang/sh/README.org b/modules/lang/sh/README.org index 130aed01c..fcaa225be 100644 --- a/modules/lang/sh/README.org +++ b/modules/lang/sh/README.org @@ -23,10 +23,7 @@ Fish script) to Doom Emacs. (supports bash-language-server). - +powershell :: Add syntax highlighting for Powershell script files (=.ps1= and =.psm1=). -- +tree-sitter :: - Leverages tree-sitter for better syntax highlighting and structural text - editing. Requires [[doom-module::tools tree-sitter]]. - + ** Packages - [[doom-package:company-shell]] if [[doom-module::completion company]] - [[doom-package:fish-mode]] if [[doom-module:+fish]] diff --git a/modules/lang/sh/config.el b/modules/lang/sh/config.el index 3b773a911..d65b7b9ea 100755 --- a/modules/lang/sh/config.el +++ b/modules/lang/sh/config.el @@ -37,9 +37,6 @@ (when (modulep! +lsp) (add-hook 'sh-mode-local-vars-hook #'lsp! 'append)) - (when (modulep! +tree-sitter) - (add-hook 'sh-mode-local-vars-hook #'tree-sitter! 'append)) - (setq sh-indent-after-continuation 'always) ;; [pedantry intensifies] diff --git a/modules/lang/sh/doctor.el b/modules/lang/sh/doctor.el index a5a6ce2a5..60446af00 100644 --- a/modules/lang/sh/doctor.el +++ b/modules/lang/sh/doctor.el @@ -7,7 +7,3 @@ (when (modulep! :editor format) (unless (executable-find "shfmt") (warn! "Couldn't find shfmt. Code formatting will not work."))) - -(assert! (or (modulep! -tree-sitter) - (modulep! :tools tree-sitter)) - "This module requires (:tools tree-sitter)") diff --git a/modules/lang/sml/README.org b/modules/lang/sml/README.org index 745651e02..1b2b3be7e 100644 --- a/modules/lang/sml/README.org +++ b/modules/lang/sml/README.org @@ -4,17 +4,23 @@ #+since: 21.12.0 * Description :unfold: -THis module adds [[https://smlfamily.github.io/][SML (Standard ML) programming language]] support to Doom Emacs. +This module adds [[https://smlfamily.github.io/][SML (Standard ML) programming language]] support to Doom Emacs. ** Maintainers *This module needs a maintainer.* [[doom-contrib-maintainer:][Become a maintainer?]] ** Module flags -/This module has no flags./ +- +lsp :: + Enable LSP support for ~sml-mode~/~sml-ts-mode~. Requires [[doom-module::tools lsp]] + and a langserver (supports [[https://github.com/azdavis/millet][millet-ls]]). +- +tree-sitter :: + Leverages tree-sitter for better syntax highlighting and structural text + editing. Requires [[doom-module::tools tree-sitter]]. ** Packages - [[doom-package:company-mlton]] if [[doom-module::completion company]] - [[doom-package:sml-mode]] +- [[doom-package:sml-ts-mode]] if [[doom-module:+tree-sitter]] ** Hacks /No hacks documented for this module./ diff --git a/modules/lang/sml/config.el b/modules/lang/sml/config.el index 9755cd33e..81493bfcc 100644 --- a/modules/lang/sml/config.el +++ b/modules/lang/sml/config.el @@ -3,11 +3,14 @@ (use-package! sml-mode :mode "\\.s\\(?:ml\\|ig\\)\\'" :config - (set-repl-handler! 'sml-mode #'run-sml) - (set-formatter! 'smlformat '("smlformat") :modes '(sml-mode)) + (set-repl-handler! '(sml-mode sml-ts-mode) #'run-sml) + (set-formatter! 'smlformat '("smlformat") :modes '(sml-mode sml-ts-mode)) + + (when (modulep! +lsp) + (add-hook 'sml-mode-local-vars-hook #'lsp! 'append)) ;; don't auto-close apostrophes (type 'a = foo) and backticks (`Foo) - (sp-with-modes 'sml-mode + (sp-with-modes '(sml-mode sml-ts-mode) (sp-local-pair "'" nil :actions nil) (sp-local-pair "`" nil :actions nil)) @@ -23,6 +26,19 @@ :desc "Run region" "r" #'sml-prog-proc-send-region)) +;; TODO: Mirror sml-mode keybinds to ts-mode +(use-package! sml-ts-mode + :when (modulep! +tree-sitter) + :when (fboundp 'treesit-available-p) + :defer t + :init + (set-tree-sitter! 'sml-mode 'sml-ts-mode + '((sml :url "https://github.com/MatthewFluet/tree-sitter-sml"))) + :config + (when (modulep! +lsp) + (add-hook 'sml-ts-mode-local-vars-hook #'lsp! 'append))) + + (use-package! company-mlton :when (modulep! :completion company) :hook (sml-mode . company-mlton-init) diff --git a/modules/lang/sml/doctor.el b/modules/lang/sml/doctor.el index de483c420..eb21317a5 100644 --- a/modules/lang/sml/doctor.el +++ b/modules/lang/sml/doctor.el @@ -1,5 +1,9 @@ ;;; lang/sml/doctor.el -*- lexical-binding: t; -*- +(assert! (or (not (modulep! +tree-sitter)) + (modulep! :tools tree-sitter)) + "This module requires (:tools tree-sitter)") + (when (modulep! :editor format) (unless (executable-find "smlformat") (warn! "Couldn't find smlformat. Formatting will be disabled."))) diff --git a/modules/lang/sml/packages.el b/modules/lang/sml/packages.el index 08879072e..3322c9f8a 100644 --- a/modules/lang/sml/packages.el +++ b/modules/lang/sml/packages.el @@ -6,3 +6,5 @@ (package! company-mlton :recipe (:host github :repo "MatthewFluet/company-mlton" :files ("*.el" "*.basis")) :pin "9b09d209b4767a2af24784fb5321390ed1d445bf")) +(when (modulep! +tree-sitter) + (package! sml-ts-mode :pin "d2dabcc9d8f91eeee7048641e4c80fabb3583194")) diff --git a/modules/lang/swift/README.org b/modules/lang/swift/README.org index 510653c2b..dabc650d4 100644 --- a/modules/lang/swift/README.org +++ b/modules/lang/swift/README.org @@ -19,6 +19,7 @@ This module adds support for the [[https://developer.apple.com/swift/][Swift pro ** Packages - [[doom-package:swift-mode]] +- [[doom-package:swift-ts-mode]] if [[doom-module:+tree-sitter]] - if [[doom-module:+lsp]] - [[doom-package:lsp-sourcekit]] - else diff --git a/modules/lang/swift/config.el b/modules/lang/swift/config.el index de11b40a2..8a16bdb0f 100644 --- a/modules/lang/swift/config.el +++ b/modules/lang/swift/config.el @@ -1,13 +1,18 @@ ;;; lang/swift/config.el -*- lexical-binding: t; -*- -(after! swift-mode +(use-package! swift-mode + :defer t + :init + (when (modulep! +tree-sitter) + (set-tree-sitter! 'swift-mode 'swift-ts-mode + '((swift :url "https://github.com/alex-pinkus/tree-sitter-swift")))) + + :config (set-repl-handler! 'swift-mode #'run-swift) (set-eglot-client! 'swift-mode '("sourcekit-lsp")) (when (modulep! +lsp) - (add-hook 'swift-mode-local-vars-hook #'lsp! 'append)) - (when (modulep! +tree-sitter) - (add-hook 'swift-mode-local-vars-hook #'tree-sitter! 'append))) + (add-hook 'swift-mode-local-vars-hook #'lsp! 'append))) (use-package! flycheck-swift diff --git a/modules/lang/swift/packages.el b/modules/lang/swift/packages.el index 2448d0ab0..56206450b 100644 --- a/modules/lang/swift/packages.el +++ b/modules/lang/swift/packages.el @@ -10,3 +10,6 @@ (package! company-sourcekit :pin "a1860ad4dd3a542acd2fa0dfac2a388cbdf4af0c")) (when (modulep! :checkers syntax -flymake) (package! flycheck-swift :pin "4c5ad401252400a78da395fd56a71e67ff8c2761"))) + +(when (modulep! +tree-sitter) + (package! swift-ts-mode :pin "43a0be79f9758fc444f5fafdff6023c4c7bf80f7")) diff --git a/modules/lang/web/+css.el b/modules/lang/web/+css.el index 2211abc50..bb96cd966 100644 --- a/modules/lang/web/+css.el +++ b/modules/lang/web/+css.el @@ -73,5 +73,12 @@ If set to `nil', disable all the above behaviors.") less-css-mode-local-vars-hook) :append #'lsp!)) -(when (modulep! +tree-sitter) - (add-hook 'css-mode-local-vars-hook #'tree-sitter! 'append)) + +(use-package! css-ts-mode ; 29.1+ only + :when (modulep! +tree-sitter) + :defer t + :init + (set-tree-sitter! 'css-mode 'css-ts-mode + '((css :url "https://github.com/tree-sitter/tree-sitter-css" + :rev "v0.23.0" + :commit "6a442a3cf461b0ce275339e5afa178693484c927")))) diff --git a/modules/lang/web/+html.el b/modules/lang/web/+html.el index e9abf0227..69f63a42a 100644 --- a/modules/lang/web/+html.el +++ b/modules/lang/web/+html.el @@ -167,7 +167,19 @@ nxml-mode-local-vars-hook) :append #'lsp!)) -(when (modulep! +tree-sitter) - (add-hook! '(html-mode-local-vars-hook - mhtml-mode-local-vars-hook) - :append #'tree-sitter!)) + +(use-package! html-ts-mode ; 30.1+ only + :when (modulep! +tree-sitter) + :defer t + :init + (set-tree-sitter! 'html-mode 'html-ts-mode + '((html :url "https://github.com/tree-sitter/tree-sitter-html" + :rev "v0.23.0" + :commit "6a442a3cf461b0ce275339e5afa178693484c927")))) + + +(use-package! mhtml-ts-mode ; 31+ only + :when (modulep! +tree-sitter) + :defer t + :init + (set-tree-sitter! 'mhtml-mode 'mhtml-ts-mode 'html)) diff --git a/modules/lang/yaml/README.org b/modules/lang/yaml/README.org index 7d9542f6c..3a50238b2 100644 --- a/modules/lang/yaml/README.org +++ b/modules/lang/yaml/README.org @@ -11,8 +11,8 @@ This module provides support for the [[https://yaml.org/][YAML file format]] to ** Module flags - +lsp :: - Enable LSP support for ~yaml-mode~. Requires [[doom-module::tools lsp]] and a langserver - (supports [[https://github.com/redhat-developer/yaml-language-server][yaml-language-server]]). + Enable LSP support for ~yaml-mode~. Requires [[doom-module::tools lsp]] and a + langserver (supports [[https://github.com/redhat-developer/yaml-language-server][yaml-language-server]]). - +tree-sitter :: Leverages tree-sitter for better syntax highlighting and structural text editing. Requires [[doom-module::tools tree-sitter]]. diff --git a/modules/lang/yaml/config.el b/modules/lang/yaml/config.el index 684568c44..f6e795a68 100644 --- a/modules/lang/yaml/config.el +++ b/modules/lang/yaml/config.el @@ -2,10 +2,19 @@ (use-package! yaml-mode :mode "Procfile\\'" - :init + :config (when (modulep! +lsp) (add-hook 'yaml-mode-local-vars-hook #'lsp! 'append)) - (when (modulep! +tree-sitter) - (add-hook 'yaml-mode-local-vars-hook #'tree-sitter! 'append)) - :config (setq-hook! 'yaml-mode-hook tab-width yaml-indent-offset)) + + +(use-package! yaml-ts-mode ; 29.1+ only + :when (modulep! +tree-sitter) + :defer t + :init + (set-tree-sitter! 'yaml-mode 'yaml-ts-mode + '((yaml :url "https://github.com/tree-sitter-grammars/tree-sitter-yaml" + :commit "b733d3f5f5005890f324333dd57e1f0badec5c87"))) + :config + (when (modulep! +lsp) + (add-hook 'yaml-ts-mode-local-vars-hook #'lsp! 'append))) diff --git a/modules/lang/yaml/doctor.el b/modules/lang/yaml/doctor.el new file mode 100644 index 000000000..73d4086c9 --- /dev/null +++ b/modules/lang/yaml/doctor.el @@ -0,0 +1,9 @@ +;;; lang/yaml/doctor.el -*- lexical-binding: t; -*- + +(assert! (or (not (modulep! +lsp)) + (modulep! :tools lsp)) + "This module requires (:tools lsp)") + +(assert! (or (not (modulep! +tree-sitter)) + (modulep! :tools tree-sitter)) + "This module requires (:tools tree-sitter)") diff --git a/modules/lang/zig/README.org b/modules/lang/zig/README.org index 4a0e7aa70..41dad18d1 100644 --- a/modules/lang/zig/README.org +++ b/modules/lang/zig/README.org @@ -22,10 +22,11 @@ This module adds [[https://ziglang.org/][Zig]] support, with optional (but recom this. - +tree-sitter :: Leverages tree-sitter for better syntax highlighting and structural text - editing. Requires [[doom-module::tools tree-sitter]]. + editing. Requires Emacs 29.1+ and [[doom-module::tools tree-sitter]]. ** Packages - [[doom-package:zig-mode]] +- [[doom-package:zig-ts-mode]] if [[doom-module:+tree-sitter]] ** Hacks /No hacks documented for this module./ diff --git a/modules/lang/zig/config.el b/modules/lang/zig/config.el index 41e35ee25..c68f864cd 100644 --- a/modules/lang/zig/config.el +++ b/modules/lang/zig/config.el @@ -8,30 +8,43 @@ ;; ;;; Packages -(use-package! zig-mode - :defer t - :config - (setq zig-format-on-save nil) ; rely on :editor format instead - +(defun +zig-common-config (mode) (when (modulep! +lsp) - (add-hook 'zig-mode-local-vars-hook #'lsp! 'append)) + (add-hook (intern (format "%s-local-vars-hook" mode)) #'lsp! 'append)) + (map! :localleader + :map ,(intern (format "%s-map" mode)) + "b" #'zig-compile + "f" #'zig-format-buffer + "r" #'zig-run + "t" #'zig-test-buffer)) - (when (modulep! +tree-sitter) - (add-hook 'zig-mode-local-vars-hook #'tree-sitter! 'append)) - (when (modulep! :checkers syntax -flymake) +(when (modulep! :checkers syntax -flymake) + (after! flycheck (eval '(flycheck-define-checker zig "A zig syntax checker using zig's `ast-check` command." :command ("zig" "ast-check" (eval (buffer-file-name))) :error-patterns ((error line-start (file-name) ":" line ":" column ": error: " (message) line-end)) - :modes zig-mode) + :modes (zig-mode zig-ts-mode)) t) - (add-to-list 'flycheck-checkers 'zig)) + (add-to-list 'flycheck-checkers 'zig))) - (map! :localleader - :map zig-mode-map - "b" #'zig-compile - "f" #'zig-format-buffer - "r" #'zig-run - "t" #'zig-test-buffer)) + +(use-package! zig-mode + :hook (zig-mode . rainbow-delimiters-mode) + :config + (setq zig-format-on-save nil) ; rely on :editor format instead + (+zig-common-config 'zig-mode)) + + +(use-package! zig-ts-mode + :when (modulep! +tree-sitter) + :when (fboundp 'zig-ts-mode) + :defer t + :init + (set-tree-sitter! 'zig-mode 'zig-ts-mode + '((zig :url "https://github.com/tree-sitter/zig-tree-sitter" + :rev "v0.25.0"))) + :config + (+zig-common-config 'zig-ts-mode)) diff --git a/modules/lang/zig/packages.el b/modules/lang/zig/packages.el index 0a86d0cf5..a37af95db 100644 --- a/modules/lang/zig/packages.el +++ b/modules/lang/zig/packages.el @@ -2,3 +2,7 @@ ;;; lang/zig/packages.el (package! zig-mode :pin "c46d024733b7c1d6af829bb610fc9629b060bc9e") + +(when (and (modulep! +tree-sitter) + (fboundp 'treesit-available-p)) + (package! zig-ts-mode :pin "3898b70d6f72da688e086323fa2922f1542d1318")) diff --git a/modules/tools/docker/README.org b/modules/tools/docker/README.org index bc42c463d..64936fb34 100644 --- a/modules/tools/docker/README.org +++ b/modules/tools/docker/README.org @@ -18,6 +18,9 @@ functions allow images to be built easily. ** Module flags - +lsp :: Enable integration for the Dockerfile Language Server. +- +tree-sitter :: + Leverages tree-sitter for better syntax highlighting and structural text + editing. Requires Emacs 29.1+ and [[doom-module::tools tree-sitter]]. ** Packages - [[doom-package:docker]] diff --git a/modules/tools/docker/config.el b/modules/tools/docker/config.el index d030acd85..b6f67b847 100644 --- a/modules/tools/docker/config.el +++ b/modules/tools/docker/config.el @@ -6,3 +6,12 @@ (when (modulep! +lsp) (add-hook 'dockerfile-mode-local-vars-hook #'lsp! 'append))) + + +(use-package! dockerfile-ts-mode + :when (modulep! +tree-sitter) + :defer t + :init + (set-tree-sitter! 'dockerfile-mode 'dockerfile-ts-mode + '((dockerfile :url "https://github.com/camdencheek/tree-sitter-dockerfile" + :commit "087daa20438a6cc01fa5e6fe6906d77c869d19fe")))) diff --git a/modules/tools/docker/doctor.el b/modules/tools/docker/doctor.el index d84713e7c..597781cd7 100644 --- a/modules/tools/docker/doctor.el +++ b/modules/tools/docker/doctor.el @@ -1,5 +1,13 @@ ;;; tools/docker/doctor.el -*- lexical-binding: t; -*- +(assert! (or (not (modulep! +tree-sitter)) + (modulep! :tools tree-sitter)) + "This module requires (:tools tree-sitter)") + +(assert! (or (not (modulep! +tree-sitter)) + (fboundp 'dockerfile-ts-mode)) + "Can't find `dockerfile-ts-mode'; Emacs 29.1+ is required") + (when (modulep! :editor format) (unless (executable-find "dockfmt") (warn! "Couldn't find dockfmt. Formatting will be disabled."))) diff --git a/modules/tools/tree-sitter/README.org b/modules/tools/tree-sitter/README.org index a13d58a9d..46a518353 100644 --- a/modules/tools/tree-sitter/README.org +++ b/modules/tools/tree-sitter/README.org @@ -27,12 +27,26 @@ It includes: /This module has no flags./ ** Packages -- [[doom-package:evil-textobj-tree-sitter]] if [[doom-module::editor evil +everywhere]] -- [[doom-package:tree-sitter]] -- [[doom-package:tree-sitter-langs]] +/This module doesn't install any packages./ ** Hacks -/No hacks documented for this module./ +- ~treesit-auto-install-grammar~, ~treesit-ensure-installed~, ~treesit-enabled-modes~, + and ~treesit-major-mode-remap-alist~ have been backported from Emacs 30/31. +- ~treesit~ has been advised to install grammars to the current Doom profile's + data folder, rather than in ~$EMACSDIR/treesit/~ (to keep ~$EMACSDIR~ clean and so + each profile can have their own grammars; in case of version conflicts). +- Because *-ts-modes are inconsistent in how they handle missing language + grammars (some error out, some respect ~treesit-auto-install-grammar~ as of 30+, + some fall back to the non-ts-mode), ~major-mode-remap~ is advised to provide + consistent and graceful failure these cases (falling back to the non-ts-mode + in all cases, with a logged warning). +- Some *-ts-modes modify ~auto-mode-alist~ and/or ~interpreter-mode-alist~ with + hardcoded entries whenever they are activated, potentially overriding user (or + Doom module) configuration. They have been advised to suppress this behavior. +- Autoloaded ~*-ts-mode~/~*-ts-mode-maybe~ entries in ~auto-mode-alist~ and + ~interpreter-mode-alist~ are proactively removed so we can consistently rely on + ~major-mode-remap-{alist,defaults}~ instead (which is more predictable and + harder for users/modules to carelessly override) ** TODO Changelog # This section will be machine generated. Don't edit it by hand. diff --git a/modules/tools/tree-sitter/autoload.el b/modules/tools/tree-sitter/autoload.el deleted file mode 100644 index 42e11dd9b..000000000 --- a/modules/tools/tree-sitter/autoload.el +++ /dev/null @@ -1,41 +0,0 @@ -;;; tools/tree-sitter/autoload.el -*- lexical-binding: t; -*- - -;;;###autodef (fset 'tree-sitter! #'ignore) -(defun tree-sitter! () - "Dispatch to turn on tree sitter. - -Used as a hook function which turns on `tree-sitter-mode' -and selectively turn on `tree-sitter-hl-mode'. -according to `+tree-sitter-hl-enabled-modes'" - (turn-on-tree-sitter-mode) - ;; conditionally enable `tree-sitter-hl-mode' - (let ((mode (bound-and-true-p tree-sitter-hl-mode))) - (when-let (mode (if (pcase +tree-sitter-hl-enabled-modes - (`(not . ,modes) (not (memq major-mode modes))) - ((and `(,_ . ,_) modes) (memq major-mode modes)) - (bool bool)) - (unless mode +1) - (if mode -1))) - (tree-sitter-hl-mode mode)))) - -;;;###autodef (fset 'set-tree-sitter-lang! #'ignore) -(defun set-tree-sitter-lang! (mode lang) - "Associate LANG with major MODE." - (after! tree-sitter-langs - (add-to-list 'tree-sitter-major-mode-language-alist (cons mode lang)))) - -;; HACK: Remove and refactor when `use-package' eager macro expansion is solved or `use-package!' is removed -;;;###autoload -(defun +tree-sitter-get-textobj (group &optional query) - "A wrapper around `evil-textobj-tree-sitter-get-textobj' to -prevent eager expansion." - (eval `(evil-textobj-tree-sitter-get-textobj ,group ,query))) - -;;;###autoload -(defun +tree-sitter-goto-textobj (group &optional previous end query) - "Thin wrapper that returns the symbol of a named function, used in keybindings." - (let ((sym (intern (format "+goto%s%s-%s" (if previous "-previous" "") (if end "-end" "") group)))) - (fset sym (lambda () - (interactive) - (evil-textobj-tree-sitter-goto-textobj group previous end query))) - sym)) diff --git a/modules/tools/tree-sitter/autoload/compat-30.el b/modules/tools/tree-sitter/autoload/compat-30.el new file mode 100644 index 000000000..2d610aaed --- /dev/null +++ b/modules/tools/tree-sitter/autoload/compat-30.el @@ -0,0 +1,74 @@ +;;; tools/tree-sitter/autoload/compat-30.el -*- lexical-binding: t; -*- +;;;###if (and (fboundp 'treesit-available-p) (version< emacs-version "31.1")) +;; +;; Backported from 31.1 +;; +;;; Code: + +(autoload 'treesit-ready-p "treesit") + +;;;###autoload +(defcustom treesit-auto-install-grammar 'ask + "Whether to install tree-sitter language grammar libraries when needed. +This controls whether Emacs will install missing grammar libraries +when they are needed by some tree-sitter based mode. +If `ask', ask for confirmation before installing the required grammar library. +If `always', install the grammar library without asking. +If nil or `never' or anything else, don't install the grammar library +even while visiting a file in the mode that requires such grammar; this +might display a warning and/or fail to turn on the mode." + :type '(choice (const :tag "Never install grammar libraries" never) + (const :tag "Always automatically install grammar libraries" + always) + (const :tag "Ask whether to install missing grammar libraries" + ask)) + :version "31.1" + :group 'treesit) + +;;;###autoload +(defun treesit-ensure-installed (lang) + "Ensure that the grammar library for the language LANG is installed. +The option `treesit-auto-install-grammar' defines whether to install +the grammar library if it's unavailable." + (or (treesit-ready-p lang t) + (when (or (eq treesit-auto-install-grammar 'always) + (and (eq treesit-auto-install-grammar 'ask) + (y-or-n-p (format "\ +Tree-sitter grammar for `%s' is missing; install it?" + lang)))) + (treesit-install-language-grammar lang) + ;; Check that the grammar was installed successfully + (treesit-ready-p lang)))) + +;;; Introduced in later commits of 31.X +;;;###autoload +(unless (boundp 'treesit-major-mode-remap-alist) + (defvar treesit-major-mode-remap-alist nil)) + +;;;###autoload +(defcustom treesit-enabled-modes nil + "Specify what treesit modes to enable by default. +The value can be either a list of ts-modes to enable, +or t to enable all ts-modes." + :type `(choice + (const :tag "Disable all automatic associations" nil) + (const :tag "Enable all available ts-modes" t) + (set :tag "List of enabled ts-modes" + ,@(when (treesit-available-p) + (let ((items (mapcar (lambda (m) `(function-item ,m)) + (seq-uniq (mapcar #'cdr treesit-major-mode-remap-alist))))) + (if (= (car (func-arity 'sort)) 1) + (sort items) + (sort items #'value<)))))) + :initialize #'custom-initialize-default + :set (lambda (sym val) + (set-default sym val) + (when (treesit-available-p) + (dolist (m treesit-major-mode-remap-alist) + (setq major-mode-remap-alist + (if (or (eq val t) (memq (cdr m) val)) + (cons m major-mode-remap-alist) + (delete m major-mode-remap-alist)))))) + :version "31.1") + +;;; compat-30.el ends here diff --git a/modules/tools/tree-sitter/autoload/tree-sitter.el b/modules/tools/tree-sitter/autoload/tree-sitter.el new file mode 100644 index 000000000..f9953bbbd --- /dev/null +++ b/modules/tools/tree-sitter/autoload/tree-sitter.el @@ -0,0 +1,64 @@ +;;; tools/tree-sitter/autoload/tree-sitter.el -*- lexical-binding: t; -*- + +;;;###autodef (fset 'tree-sitter! #'ignore) +(defun tree-sitter! () + (message "Old tree-sitter.el support is deprecated!")) + +;;;###autodef (fset 'set-tree-sitter! #'ignore) +(defun set-tree-sitter! (mode ts-mode &optional recipes) + "Remap major MODE to TS-MODE. + +MODE and TS-MODE are major mode symbols. If RECIPES is provided, fall back to +MODE if RECIPES don't pass `treesit-ready-p' when activating TS-MODE. Use this +for ts modes that error out instead of failing gracefully. + +RECIPES is a symbol (a grammar language name), list thereof, or alist of plists +with the format (LANG &key URL REV SOURCE-DIR CC CPP COMMIT). If an alist of +plists, it will be transformed into entries for `treesit-language-source-alist' +(which describe what each of these keys mean). Note that COMMIT is ignored +pre-Emacs 31." + (declare (indent 2)) + (cl-check-type mode symbol) + (cl-check-type ts-mode symbol) + (setq recipes (mapcar #'ensure-list (ensure-list recipes))) + (dolist (m (ensure-list mode)) + (setf (alist-get m major-mode-remap-defaults) ts-mode) + (put ts-mode '+tree-sitter (cons m (mapcar #'car recipes)))) + (when (setq recipes (cl-remove-if-not #'cdr recipes)) + (with-eval-after-load 'treesit + (dolist (recipe recipes) + (cl-destructuring-bind (name &key url rev source-dir cc cpp commit) (ensure-list recipe) + (setf (alist-get name treesit-language-source-alist) + (append (list url rev source-dir cc cpp) + ;; COMPAT: 31.1 introduced a COMMIT recipe argument. On + ;; <=30.x, extra arguments will trigger an arity error + ;; when installing grammars. + (if (eq (cdr (func-arity 'treesit--install-language-grammar-1)) + 'many) + (list commit))))))))) + +;; ;; HACK: Remove and refactor when `use-package' eager macro expansion is solved or `use-package!' is removed +;; ;;;###autoload +;; (defun +tree-sitter-get-textobj (group &optional query) +;; "A wrapper around `evil-textobj-tree-sitter-get-textobj' to +;; prevent eager expansion." +;; (eval `(evil-textobj-tree-sitter-get-textobj ,group ,query))) + +;; ;;;###autoload +;; (defun +tree-sitter-goto-textobj (group &optional previous end query) +;; "Thin wrapper that returns the symbol of a named function, used in keybindings." +;; (let ((sym (intern (format "+goto%s%s-%s" (if previous "-previous" "") (if end "-end" "") group)))) +;; (fset sym (lambda () +;; (interactive) +;; (evil-textobj-tree-sitter-goto-textobj group previous end query))) +;; sym)) + +;;;###autoload +(defun +tree-sitter-ts-mode-inhibit-side-effects-a (fn &rest args) + "Suppress changes to `auto-mode-alist' and `interpreter-mode-alist'." + (let (auto-mode-alist interpreter-mode-alist) + (apply fn args))) + +;;; TODO: Backwards compatibility + +;;; tree-sitter.el ends here diff --git a/modules/tools/tree-sitter/config.el b/modules/tools/tree-sitter/config.el index def0ce5d2..d45aa88c9 100644 --- a/modules/tools/tree-sitter/config.el +++ b/modules/tools/tree-sitter/config.el @@ -1,77 +1,171 @@ ;;; tools/tree-sitter/config.el -*- lexical-binding: t; -*- -(defvar +tree-sitter-hl-enabled-modes '(not web-mode typescript-tsx-mode) - "A list of major modes which should be highlighted by tree-sitter. - -If this list begins with `not', then it negates the list. -If it is t, it is enabled in all modes. -If nil, it is disabled in all modes") - ;; ;;; Packages -(use-package! tree-sitter +(use-package! treesit + :when (fboundp 'treesit-available-p) + :when (treesit-available-p) :defer t + :preface + (setq treesit-enabled-modes t) + + ;; HACK: The *-ts-mode major modes are inconsistent about how they treat + ;; missing language grammars (some error out, some respect + ;; `treesit-auto-install-grammar', some fall back to `fundamental-mode'). + ;; I'd like to address this poor UX using `major-mode-remap-alist' entries + ;; created by `set-tree-sitter!' (which will fall back to the non-treesit + ;; modes), but most *-ts-mode's clobber `auto-mode-alist' and/or + ;; `interpreter-mode-alist' each time the major mode is activated, so those + ;; must be undone too so they don't overwrite user config. + ;; TODO: Handle this during the 'doom sync' process instead. + (save-match-data + (dolist (sym '(auto-mode-alist interpreter-mode-alist)) + (set + sym (cl-loop for (src . fn) in (symbol-value sym) + unless (and (functionp fn) + (string-match "-ts-mode\\(?:-maybe\\)?$" (symbol-name fn))) + collect (cons src fn))))) + + ;; HACK: These *-ts-modes change `auto-mode-alist' and/or + ;; `interpreter-mode-alist' every time they are activated, running the risk + ;; of overwriting user (or Doom) config. + ;; REVIEW: Should be addressed upstream. + (dolist (mode '(csharp-ts-mode + python-ts-mode)) + (advice-add mode :around #'+tree-sitter-ts-mode-inhibit-side-effects-a)) + + ;; HACK: Intercept all ts-mode major mode remappings so grammars can be + ;; dynamically checked and `treesit-auto-install-grammar' can be + ;; consistently respected (which isn't currently the case with the majority + ;; of ts-modes, even the built-in ones). + (defadvice! +tree-sitter--maybe-remap-major-mode-a (fn mode) + :around #'major-mode-remap + (let ((mode (funcall fn mode))) + (if-let* ((ts (get mode '+tree-sitter)) + (fallback-mode (car ts))) + (cond ((not (fboundp mode)) + (message "Couldn't find `%S', falling back to `%S'" mode fallback-mode) + fallback-mode) + ((and (or (eq treesit-enabled-modes t) + (memq fallback-mode treesit-enabled-modes)) + ;; Lazily load autoloaded `treesit-language-source-alist' + ;; entries. + (let ((fn (symbol-function mode)) + ;; Silence "can't find grammar" warning popups from + ;; `treesit-ready-p' calls in Emacs <=30.1. We'll + ;; log it to *Messages* instead. + (warning-suppress-types + (cons '(treesit) warning-suppress-types))) + (or (not (autoloadp fn)) + (autoload-do-load fn mode))) + ;; Only prompt once, and log other times. + (or (null (cdr ts)) + (cl-every (if (get mode '+tree-sitter-ensured) + (doom-rpartial #'treesit-ready-p 'message) + #'treesit-ensure-installed) + (cdr ts)))) + (put mode '+tree-sitter-ensured t) + mode) + (fallback-mode)) + mode))) + :config - (require 'tree-sitter-langs) - ;; This makes every node a link to a section of code - (setq tree-sitter-debug-jump-buttons t - ;; and this highlights the entire sub tree in your code - tree-sitter-debug-highlight-jump-region t)) + ;; HACK: Keep $EMACSDIR clean by installing grammars to the active profile. + (add-to-list 'treesit-extra-load-path (concat doom-profile-data-dir "tree-sitter")) + (defadvice! +tree-sitter--install-grammar-to-local-dir-a (fn &rest args) + "Write grammars to `doom-profile-data-dir'." + :around #'treesit-install-language-grammar + :around #'treesit--build-grammar + (let ((user-emacs-directory doom-profile-data-dir)) + (apply fn args))) + + ;; TODO: Move most of these out to modules + (dolist (map '((awk "https://github.com/Beaglefoot/tree-sitter-awk" nil nil nil nil) + (bibtex "https://github.com/latex-lsp/tree-sitter-bibtex" nil nil nil nil) + (blueprint "https://github.com/huanie/tree-sitter-blueprint" nil nil nil nil) + (commonlisp "https://github.com/tree-sitter-grammars/tree-sitter-commonlisp" nil nil nil nil) + (latex "https://github.com/latex-lsp/tree-sitter-latex" nil nil nil nil) + (make "https://github.com/tree-sitter-grammars/tree-sitter-make" nil nil nil nil) + (nu "https://github.com/nushell/tree-sitter-nu" nil nil nil nil) + (org "https://github.com/milisims/tree-sitter-org" nil nil nil nil) + (perl "https://github.com/ganezdragon/tree-sitter-perl" nil nil nil nil) + (proto "https://github.com/mitchellh/tree-sitter-proto" nil nil nil nil) + (r "https://github.com/r-lib/tree-sitter-r" nil nil nil nil) + (sql "https://github.com/DerekStride/tree-sitter-sql" "gh-pages" nil nil nil) + (surface "https://github.com/connorlay/tree-sitter-surface" nil nil nil nil) + (toml "https://github.com/tree-sitter/tree-sitter-toml" nil nil nil nil) + (typst "https://github.com/uben0/tree-sitter-typst" "master" "src" nil nil) + (verilog "https://github.com/gmlarumbe/tree-sitter-verilog" nil nil nil nil) + (vhdl "https://github.com/alemuller/tree-sitter-vhdl" nil nil nil nil) + (vue "https://github.com/tree-sitter-grammars/tree-sitter-vue" nil nil nil nil) + (wast "https://github.com/wasm-lsp/tree-sitter-wasm" nil "wast/src" nil nil) + (wat "https://github.com/wasm-lsp/tree-sitter-wasm" nil "wat/src" nil nil) + (wgsl "https://github.com/mehmetoguzderin/tree-sitter-wgsl" nil nil nil nil))) + (cl-pushnew map treesit-language-source-alist :test #'eq :key #'car))) -(use-package! evil-textobj-tree-sitter - :when (modulep! :editor evil +everywhere) - :defer t - :init (after! tree-sitter (require 'evil-textobj-tree-sitter)) - :config - (defvar +tree-sitter-inner-text-objects-map (make-sparse-keymap)) - (defvar +tree-sitter-outer-text-objects-map (make-sparse-keymap)) - (defvar +tree-sitter-goto-previous-map (make-sparse-keymap)) - (defvar +tree-sitter-goto-next-map (make-sparse-keymap)) +;; TODO: combobulate or evil-textobj-tree-sitter - (evil-define-key '(visual operator) 'tree-sitter-mode - "i" +tree-sitter-inner-text-objects-map - "a" +tree-sitter-outer-text-objects-map) - (evil-define-key 'normal 'tree-sitter-mode - "[g" +tree-sitter-goto-previous-map - "]g" +tree-sitter-goto-next-map) - (map! (:map +tree-sitter-inner-text-objects-map - "A" (+tree-sitter-get-textobj '("parameter.inner" "call.inner")) - "f" (+tree-sitter-get-textobj "function.inner") - "F" (+tree-sitter-get-textobj "call.inner") - "C" (+tree-sitter-get-textobj "class.inner") - "v" (+tree-sitter-get-textobj "conditional.inner") - "l" (+tree-sitter-get-textobj "loop.inner")) - (:map +tree-sitter-outer-text-objects-map - "A" (+tree-sitter-get-textobj '("parameter.outer" "call.outer")) - "f" (+tree-sitter-get-textobj "function.outer") - "F" (+tree-sitter-get-textobj "call.outer") - "C" (+tree-sitter-get-textobj "class.outer") - "c" (+tree-sitter-get-textobj "comment.outer") - "v" (+tree-sitter-get-textobj "conditional.outer") - "l" (+tree-sitter-get-textobj "loop.outer")) +;; (use-package! combobulate +;; :commands combobulate-query-builder +;; :hook (prog-mode . combobulate-mode)) - (:map +tree-sitter-goto-previous-map - "a" (+tree-sitter-goto-textobj "parameter.outer" t) - "f" (+tree-sitter-goto-textobj "function.outer" t) - "F" (+tree-sitter-goto-textobj "call.outer" t) - "C" (+tree-sitter-goto-textobj "class.outer" t) - "c" (+tree-sitter-goto-textobj "comment.outer" t) - "v" (+tree-sitter-goto-textobj "conditional.outer" t) - "l" (+tree-sitter-goto-textobj "loop.outer" t)) - (:map +tree-sitter-goto-next-map - "a" (+tree-sitter-goto-textobj "parameter.outer") - "f" (+tree-sitter-goto-textobj "function.outer") - "F" (+tree-sitter-goto-textobj "call.outer") - "C" (+tree-sitter-goto-textobj "class.outer") - "c" (+tree-sitter-goto-textobj "comment.outer") - "v" (+tree-sitter-goto-textobj "conditional.outer") - "l" (+tree-sitter-goto-textobj "loop.outer"))) - (after! which-key - (setq which-key-allow-multiple-replacements t) - (pushnew! - which-key-replacement-alist - '(("" . "\\`+?evil-textobj-tree-sitter-function--\\(.*\\)\\(?:.inner\\|.outer\\)") . (nil . "\\1"))))) +;; (use-package! evil-textobj-tree-sitter +;; :when (modulep! :editor evil +everywhere) +;; :defer t +;; :init (after! tree-sitter (require 'evil-textobj-tree-sitter)) +;; :after-call doom-first-input-hook +;; :config +;; (defvar +tree-sitter-inner-text-objects-map (make-sparse-keymap)) +;; (defvar +tree-sitter-outer-text-objects-map (make-sparse-keymap)) +;; (defvar +tree-sitter-goto-previous-map (make-sparse-keymap)) +;; (defvar +tree-sitter-goto-next-map (make-sparse-keymap)) + +;; (evil-define-key '(visual operator) 'tree-sitter-mode +;; "i" +tree-sitter-inner-text-objects-map +;; "a" +tree-sitter-outer-text-objects-map) +;; (evil-define-key 'normal 'tree-sitter-mode +;; "[g" +tree-sitter-goto-previous-map +;; "]g" +tree-sitter-goto-next-map) + +;; (map! (:map +tree-sitter-inner-text-objects-map +;; "A" (+tree-sitter-get-textobj '("parameter.inner" "call.inner")) +;; "f" (+tree-sitter-get-textobj "function.inner") +;; "F" (+tree-sitter-get-textobj "call.inner") +;; "C" (+tree-sitter-get-textobj "class.inner") +;; "v" (+tree-sitter-get-textobj "conditional.inner") +;; "l" (+tree-sitter-get-textobj "loop.inner")) +;; (:map +tree-sitter-outer-text-objects-map +;; "A" (+tree-sitter-get-textobj '("parameter.outer" "call.outer")) +;; "f" (+tree-sitter-get-textobj "function.outer") +;; "F" (+tree-sitter-get-textobj "call.outer") +;; "C" (+tree-sitter-get-textobj "class.outer") +;; "c" (+tree-sitter-get-textobj "comment.outer") +;; "v" (+tree-sitter-get-textobj "conditional.outer") +;; "l" (+tree-sitter-get-textobj "loop.outer")) + +;; (:map +tree-sitter-goto-previous-map +;; "a" (+tree-sitter-goto-textobj "parameter.outer" t) +;; "f" (+tree-sitter-goto-textobj "function.outer" t) +;; "F" (+tree-sitter-goto-textobj "call.outer" t) +;; "C" (+tree-sitter-goto-textobj "class.outer" t) +;; "c" (+tree-sitter-goto-textobj "comment.outer" t) +;; "v" (+tree-sitter-goto-textobj "conditional.outer" t) +;; "l" (+tree-sitter-goto-textobj "loop.outer" t)) +;; (:map +tree-sitter-goto-next-map +;; "a" (+tree-sitter-goto-textobj "parameter.outer") +;; "f" (+tree-sitter-goto-textobj "function.outer") +;; "F" (+tree-sitter-goto-textobj "call.outer") +;; "C" (+tree-sitter-goto-textobj "class.outer") +;; "c" (+tree-sitter-goto-textobj "comment.outer") +;; "v" (+tree-sitter-goto-textobj "conditional.outer") +;; "l" (+tree-sitter-goto-textobj "loop.outer"))) + +;; (after! which-key +;; (setq which-key-allow-multiple-replacements t) +;; (pushnew! +;; which-key-replacement-alist +;; '(("" . "\\`+?evil-textobj-tree-sitter-function--\\(.*\\)\\(?:.inner\\|.outer\\)") . (nil . "\\1"))))) diff --git a/modules/tools/tree-sitter/doctor.el b/modules/tools/tree-sitter/doctor.el index 68026fce7..4a32abf4f 100644 --- a/modules/tools/tree-sitter/doctor.el +++ b/modules/tools/tree-sitter/doctor.el @@ -1,4 +1,10 @@ -;;; tools/treesitter/doctor.el -*- lexical-binding: t; -*- +;;; tools/tree-sitter/doctor.el -*- lexical-binding: t; -*- (unless (fboundp 'module-load) - (warn! "Emacs was not built with dynamic modules support. Tree sitter needs this to function")) + (error! "Emacs not built with dynamic modules support")) + +(if (version< emacs-version "29.1") + (error! "Emacs 29.1 or newer is required for tree-sitter support") + (unless (and (fboundp 'treesit-available-p) + (treesit-available-p)) + (error! "Emacs not built with tree-sitter support!"))) diff --git a/modules/tools/tree-sitter/packages.el b/modules/tools/tree-sitter/packages.el index c062f7d4a..c5b7fa3c2 100644 --- a/modules/tools/tree-sitter/packages.el +++ b/modules/tools/tree-sitter/packages.el @@ -1,10 +1,18 @@ ;; -*- no-byte-compile: t; -*- ;;; tools/tree-sitter/packages.el -(package! tree-sitter :recipe (:branch "master") :pin "caeb32e8a7783a8a6c14ac7b2d84d415e8a582ff") -(package! tree-sitter-langs :pin "9b7e5084353b89d28a5ed33503731c86b4d6ec70") -(package! tree-sitter-indent :pin "4ef246db3e4ff99f672fe5e4b416c890f885c09e") - -(when (modulep! :editor evil +everywhere) - (package! evil-textobj-tree-sitter - :pin "4ca5dffbd3f81361c85203bde44328ad2128d33a")) +(package! treesit :built-in t) +(when (> emacs-major-version 28) + ;; (package! combobulate + ;; :recipe '(;; If pulled from emacsmirror, this would otherwise pull in test + ;; ;; repos that users don't need. + ;; :nonrecursive t + ;; ;; HACK: This package has terrible autoload ettiquette, eagerly + ;; ;; loading a number of expensive packages at startup, so + ;; ;; autoloads are handled manually in config.el + ;; :build (:not autoloads)) + ;; :pin "59b64d66d66eb84da6a2cedd152b1692378af674") + ;; (when (modulep! :editor evil +everywhere) + ;; (package! evil-textobj-tree-sitter + ;; :pin "bce236e5d2cc2fa4eae7d284ffd19ad18d46349a")) + ) diff --git a/modules/ui/indent-guides/config.el b/modules/ui/indent-guides/config.el index 898920d5f..b60191a9c 100644 --- a/modules/ui/indent-guides/config.el +++ b/modules/ui/indent-guides/config.el @@ -21,7 +21,8 @@ be enabled. If any function returns non-nil, the mode will not be activated." (unless (run-hook-with-args-until-success '+indent-guides-inhibit-functions) (indent-bars-mode +1))) :config - (setq indent-bars-prefer-character + (setq indent-bars-treesit-support (modulep! :tools tree-sitter) + indent-bars-prefer-character (or ;; Bitmaps are far slower on MacOS, inexplicably, but this needs more ;; testing to see if it's specific to ns or emacs-mac builds, or is @@ -42,9 +43,6 @@ be enabled. If any function returns non-nil, the mode will not be activated." ;; unnecessary overhead for little benefit. indent-bars-highlight-current-depth nil) - ;; TODO: Uncomment once we support treesit - ;; (setq indent-bars-treesit-support (modulep! :tools tree-sitter)) - ;; indent-bars adds this to `enable-theme-functions', which was introduced in ;; 29.1, which will be redundant with `doom-load-theme-hook'. (unless (boundp 'enable-theme-functions) @@ -105,21 +103,4 @@ be enabled. If any function returns non-nil, the mode will not be activated." (defadvice! +indent-guides--restore-after-lsp-ui-peek-a (&rest _) :after #'lsp-ui-peek--peek-hide (unless indent-bars-prefer-character - (indent-bars-setup)))) - - ;; HACK: Both indent-bars and tree-sitter-hl-mode use the jit-font-lock - ;; mechanism, and so they don't play well together. For those particular - ;; cases, we'll use `highlight-indent-guides', at least until the - ;; tree-sitter module adopts treesit. - (defvar-local +indent-guides-p nil) - (add-hook! 'tree-sitter-mode-hook :append - (defun +indent-guides--toggle-on-tree-sitter-h () - (if tree-sitter-mode - (when (bound-and-true-p indent-bars-mode) - (with-memoization (get 'indent-bars-mode 'disabled-in-tree-sitter) - (doom-log "Disabled `indent-bars-mode' because it's not supported in `tree-sitter-mode'") - t) - (indent-bars-mode -1) - (setq +indent-guides-p t)) - (when +indent-guides-p - (indent-bars-mode +1)))))) + (indent-bars-setup)))))