feat!(cc): add treesit support

BREAKING CHANGE: Besides treesit support, this removes a few
fontification enhancements (in favor of tree-sitter).
This commit is contained in:
Henrik Lissner
2025-05-15 12:46:58 +02:00
parent c403bb5e2f
commit 1670ce2767
4 changed files with 110 additions and 76 deletions

View File

@ -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 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 doesn't support specification of the fallback mode and whose heuristics are
simpler." simpler."
(let ((base (file-name-sans-extension (buffer-file-name (buffer-base-buffer))))) (funcall
(cond ((file-exists-p! (or (concat base ".cpp") (major-mode-remap
(concat base ".cc"))) (let ((base (file-name-sans-extension (buffer-file-name (buffer-base-buffer)))))
(c++-mode)) (cond ((file-exists-p! (or (concat base ".cpp")
((or (file-exists-p! (or (concat base ".m") (concat base ".cc")))
(concat base ".mm"))) 'c++-mode)
(+cc--re-search-for ((or (file-exists-p! (or (concat base ".m")
(concat "^[ \t\r]*\\(?:" (concat base ".mm")))
"@\\(?:class\\|interface\\|property\\|end\\)\\_>" (+cc--re-search-for
"\\|#import +<Foundation/Foundation.h>" (concat "^[ \t\r]*\\(?:"
"\\|[-+] ([a-zA-Z0-9_]+)" "@\\(?:class\\|interface\\|property\\|end\\)\\_>"
"\\|#import +<Foundation/Foundation.h>"
"\\|[-+] ([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)) 'c++-mode)
((+cc--re-search-for ((functionp +cc-default-header-file-mode)
(let ((id "[a-zA-Z0-9_]+") (ws "[ \t\r]+") (ws-maybe "[ \t\r]*")) +cc-default-header-file-mode)
(concat "^" ws-maybe "\\(?:" ('c-mode))))))
"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)))))
(defun +cc-resolve-include-paths () (defun +cc-resolve-include-paths ()
(cl-loop with path = (or buffer-file-name default-directory) (cl-loop with path = (or buffer-file-name default-directory)
@ -137,15 +139,6 @@ the children of class at point."
;; ;;
;; Hooks ;; 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) (defvar +cc--project-includes-alist nil)
;;;###autoload ;;;###autoload
(defun +cc-init-ffap-integration-h () (defun +cc-init-ffap-integration-h ()

View File

@ -25,17 +25,26 @@ This is ignored by ccls.")
;; set up before lsp is initialized. Also, we use local-vars hooks to ensure ;; 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. ;; 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-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') ;;; Improve fontification in C/C++ (also see `modern-cpp-font-lock')
:hook (c-mode-common . rainbow-delimiters-mode) :hook (c-mode-common . rainbow-delimiters-mode)
: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 :config
(set-docsets! 'c-mode "C") (set-docsets! '(c-mode c-ts-mode) "C")
(set-docsets! 'c++-mode "C++" "Boost") (set-docsets! '(c++-mode c++-ts-mode) "C++" "Boost")
(set-electric! '(c-mode c++-mode objc-mode java-mode) :chars '(?\n ?\} ?\{)) (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 (set-rotate-patterns! 'c++-mode
:symbols '(("public" "protected" "private") :symbols '(("public" "protected" "private")
("class" "struct"))) ("class" "struct")))
(set-ligatures! '(c-mode c++-mode) (set-ligatures! '(c-mode c-ts-mode c++-mode c++-ts-mode)
;; Functional ;; Functional
;; :def "void " ;; :def "void "
;; Types ;; Types
@ -54,10 +63,14 @@ This is ignored by ccls.")
(add-to-list 'find-sibling-rules '("/\\([^/]+\\)\\.c\\(c\\|pp\\)?\\'" "\\1.h\\(h\\|pp\\)?\\'")) (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\\)?\\'")) (add-to-list 'find-sibling-rules '("/\\([^/]+\\)\\.h\\(h\\|pp\\)?\\'" "\\1.c\\(c\\|pp\\)?\\'"))
(when (modulep! +tree-sitter) ;; Delete all the default remappings created by the cc-mode package. We define
(add-hook! '(c-mode-local-vars-hook ;; better ones with `set-tree-sitter!' further below, otherwise there should
c++-mode-local-vars-hook) ;; be no remapping if the user hasn't explicitly asked for tree-sitter
:append #'tree-sitter!)) ;; integration.
(dolist (mode '((c++-mode . c++-ts-mode)
(c-mode . c-ts-mode)
(c-or-c++-mode . c-or-c++-ts-mode)))
(cl-callf2 delete mode major-mode-remap-defaults))
;; HACK Suppress 'Args out of range' error in when multiple modifications are ;; 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 ;; performed at once in a `c++-mode' buffer, e.g. with `iedit' or
@ -101,52 +114,82 @@ This is ignored by ccls.")
(label . 0)))) (label . 0))))
(when (listp c-default-style) (when (listp c-default-style)
(setf (alist-get 'other c-default-style) "doom")) (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))
;; ;;
;; Major modes ;; Major modes
(after! cmake-mode (use-package! cmake-mode
(set-docsets! 'cmake-mode "CMake") :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-popup-rule! "^\\*CMake Help\\*" :size 0.4 :ttl t)
(set-lookup-handlers! 'cmake-mode (set-lookup-handlers! '(cmake-mode cmake-ts-mode)
:documentation '+cc-cmake-lookup-documentation-fn)) :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' (use-package! glsl-mode
:when (modulep! :completion company) :defer t
:after cmake-mode :init
:config (set-company-backend! 'cmake-mode 'company-cmake)) (when (modulep! +tree-sitter) ; 29+ only
(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))
;; HACK: Remove redundant entries so we can rely solely on
;; `major-mode-remap-defaults' et co.
(rassq-delete-all 'cuda-ts-mode auto-mode-alist)
(cl-callf2 delete '(cuda "https://github.com/tree-sitter-grammars/tree-sitter-cuda" nil nil nil nil)
treesit-language-source-alist))
(use-package! demangle-mode (use-package! demangle-mode
:hook llvm-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 ;;; LSP
(when (modulep! +lsp) (when (modulep! +lsp)
(add-hook! '(c-mode-local-vars-hook (add-hook! '(c-mode-local-vars-hook
c-ts-mode-local-vars-hook
c++-mode-local-vars-hook c++-mode-local-vars-hook
objc-mode-local-vars-hook c++-ts-mode-local-vars-hook
cmake-mode-local-vars-hook objc-mode-local-vars-hook)
cuda-mode-local-vars-hook)
:append #'lsp!) :append #'lsp!)
(if (modulep! :tools lsp -eglot) (if (modulep! :tools lsp -eglot)

View File

@ -4,13 +4,15 @@
(package! cmake-mode (package! cmake-mode
:recipe (:host github :repo "emacsmirror/cmake-mode" :files (:defaults "*")) :recipe (:host github :repo "emacsmirror/cmake-mode" :files (:defaults "*"))
:pin "b08b5d9045308362a623a4f576896d55ffecfd52") :pin "b08b5d9045308362a623a4f576896d55ffecfd52")
(package! cuda-mode :pin "c3dae31b3d1abedf4d0b98840127e2cac73d6ad8")
(package! demangle-mode :pin "04f545adab066708d6151f13da65aaf519f8ac4e") (package! demangle-mode :pin "04f545adab066708d6151f13da65aaf519f8ac4e")
(package! disaster :pin "8b445913221feb0c196e943106643040118bcd77") (package! disaster :pin "8b445913221feb0c196e943106643040118bcd77")
(package! opencl-mode :pin "204d5d9e0f5cb2cbe810f2933230eb08fe2c7695") (package! opencl-mode :pin "204d5d9e0f5cb2cbe810f2933230eb08fe2c7695")
(unless (modulep! +tree-sitter) (when (package! cuda-mode :pin "c3dae31b3d1abedf4d0b98840127e2cac73d6ad8")
(package! modern-cpp-font-lock :pin "43c6b68ff58fccdf9deef11674a172e4eaa8455c")) (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 (package! glsl-mode :pin "86e6bb6cf28d1053366039683a4498401bab9c47")
(when (modulep! :completion company) (when (modulep! :completion company)

View File

@ -20,17 +20,13 @@
(dolist (map '((awk "https://github.com/Beaglefoot/tree-sitter-awk" nil nil nil nil) (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) (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) (blueprint "https://github.com/huanie/tree-sitter-blueprint" nil nil nil nil)
(c "https://github.com/tree-sitter/tree-sitter-c" nil nil nil nil)
(c-sharp "https://github.com/tree-sitter/tree-sitter-c-sharp" nil nil nil nil) (c-sharp "https://github.com/tree-sitter/tree-sitter-c-sharp" nil nil nil nil)
(clojure "https://github.com/sogaiu/tree-sitter-clojure" nil nil nil nil) (clojure "https://github.com/sogaiu/tree-sitter-clojure" nil nil nil nil)
(cmake "https://github.com/uyha/tree-sitter-cmake" nil nil nil nil)
(commonlisp "https://github.com/tree-sitter-grammars/tree-sitter-commonlisp" nil nil nil nil) (commonlisp "https://github.com/tree-sitter-grammars/tree-sitter-commonlisp" nil nil nil nil)
(cpp "https://github.com/tree-sitter/tree-sitter-cpp" nil nil nil nil)
(css "https://github.com/tree-sitter/tree-sitter-css" nil nil nil nil) (css "https://github.com/tree-sitter/tree-sitter-css" nil nil nil nil)
(dart "https://github.com/ast-grep/tree-sitter-dart" nil nil nil nil) (dart "https://github.com/ast-grep/tree-sitter-dart" nil nil nil nil)
(dockerfile "https://github.com/camdencheek/tree-sitter-dockerfile" nil nil nil nil) (dockerfile "https://github.com/camdencheek/tree-sitter-dockerfile" nil nil nil nil)
(elixir "https://github.com/elixir-lang/tree-sitter-elixir" nil nil nil nil) (elixir "https://github.com/elixir-lang/tree-sitter-elixir" nil nil nil nil)
(glsl "https://github.com/tree-sitter-grammars/tree-sitter-glsl" nil nil nil nil)
(go "https://github.com/tree-sitter/tree-sitter-go" nil nil nil nil) (go "https://github.com/tree-sitter/tree-sitter-go" nil nil nil nil)
(gomod "https://github.com/camdencheek/tree-sitter-go-mod" nil nil nil nil) (gomod "https://github.com/camdencheek/tree-sitter-go-mod" nil nil nil nil)
(heex "https://github.com/phoenixframework/tree-sitter-heex" nil nil nil nil) (heex "https://github.com/phoenixframework/tree-sitter-heex" nil nil nil nil)