summaryrefslogblamecommitdiff
path: root/.config/emacs/modules/mm-treesit.el
blob: a41f52c7741d6d1a1f58aaa2a35bc10c2a2e6dfc (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17















                                                                            
                                                                      




                                                                          
                                                                        








                                                                                


                                                                     
               
                                                       
 







                                                            













































































                                                                                       
















                                                                             




























                                                                        
                    
;;; mm-treesit.el --- Tree-Sitter configuration  -*- lexical-binding: t; -*-

(unless (treesit-available-p)
  (error "Tree-Sitter is not available."))

^L
;;; Tree-Sitter Variables

(defvar mm-treesit-language-remap-alist
  '((cpp        . c++)
    (gomod      . go-mod)
    (javascript . js)
    (vim        . vimscript))
  "TODO")

(setopt treesit-font-lock-level 4)
(setopt treesit-language-source-alist
        '((awk        "https://github.com/Beaglefoot/tree-sitter-awk")
          (c          "https://github.com/tree-sitter/tree-sitter-c")
          (cpp        "https://github.com/tree-sitter/tree-sitter-cpp")
          (css        "https://github.com/tree-sitter/tree-sitter-css")
          (go         "https://github.com/tree-sitter/tree-sitter-go")
          (gomod      "https://github.com/camdencheek/tree-sitter-go-mod")
          (gsp        "git://git.thomasvoss.com/tree-sitter-gsp.git")
          (html       "https://github.com/tree-sitter/tree-sitter-html")
          (java       "https://github.com/tree-sitter/tree-sitter-java")
          (javascript "https://github.com/tree-sitter/tree-sitter-javascript")
          (python     "https://github.com/tree-sitter/tree-sitter-python")
          (typescript "https://github.com/tree-sitter/tree-sitter-typescript"
                      "master" "typescript/src")
          (vim        "https://github.com/tree-sitter-grammars/tree-sitter-vim")
          (vue        "https://github.com/ikatyang/tree-sitter-vue")))

^L
;;; Install Missing Parsers

(defun mm-treesit-install-all ()
  "Install all Tree-Sitter parsers.
This is like `mm-treesit-install-missing' but also reinstalls parsers
that are already installed."
  (interactive)
  (cl-loop for (lang) in treesit-language-source-alist
           do (treesit-install-language-grammar lang)))

(defun mm-treesit-install-missing ()
  "Install missing Tree-Sitter parsers.
The parsers are taken from `treesit-language-source-alist'."
  (interactive)
  (cl-loop for (lang) in treesit-language-source-alist
           unless (treesit-language-available-p lang)
           do (treesit-install-language-grammar lang)))

(mm-treesit-install-missing)

^L
;;; Install Additional TS Modes

(use-package gsp-ts-mode
  :vc (:url "https://git.thomasvoss.com/gsp-ts-mode"
       :branch "master"
       :rev :newest
       :vc-backend Git)
  :ensure t)

;; NOTE: This package doesn’t autoload its ‘auto-mode-alist’ entries
(use-package vimscript-ts-mode
  :ensure t
  :mode (rx (or (seq (? (or ?. ?_)) (? ?g) "vimrc")
                ".vim"
                ".exrc")
            eos))

;; NOTE: This package doesn’t autoload its ‘auto-mode-alist’ entries
(use-package vue-ts-mode
  :vc (:url "https://github.com/8uff3r/vue-ts-mode.git"
       :branch "main"
       :rev :newest
       :vc-backend Git)
  :ensure t
  :mode "\\.vue\\'")

^L
;;; Prefer Tree-Sitter Modes

;; NOTE: ‘go-ts-mode’ already adds itself to ‘auto-mode-alist’ but it
;; isn’t autoloaded as of 2024-09-29 so we need to do it ourselves
;; anyway.  Same goes for ‘typescript-ts-mode’.
(defvar mm-treesit-language-file-name-alist
  '((go         . "\\.go\\'")
    (go-mod     . "/go\\.mod\\'")
    (typescript . "\\.ts\\'"))
  "Alist mapping languages to their associated file-names.
This alist is a set of pairs of the form (LANG . REGEXP) where LANG is
the symbol corresponding to a major mode with the ‘-ts-mode’ suffix
removed.  REGEXP is a regular expression matching filenames for which
the associated language’s major-mode should be enabled.

This alist is used to configure `auto-mode-alist'.")

(dolist (spec treesit-language-source-alist)
  (let* ((lang (car spec))
         (lang (alist-get lang mm-treesit-language-remap-alist lang))
         (symbol-name (symbol-name lang))
         (name-mode    (intern (concat symbol-name    "-mode")))
         (name-ts-mode (intern (concat symbol-name "-ts-mode"))))
    ;; If ‘name-ts-mode’ is already in ‘auto-mode-alist’ then we don’t
    ;; need to do anything, however if that’s not the case then if
    ;; ‘name-ts-mode’ and ‘name-mode’ are both bound we do a simple
    ;; remap.  If the above is not true then we lookup the extensions in
    ;; ‘mm-treesit-language-file-name-alist’.
    (cond
     ((not (fboundp name-ts-mode))
      (warn "`%s' is missing." name-ts-mode))
     ((rassq name-ts-mode auto-mode-alist)
      nil)
     ((fboundp name-mode)
      (add-to-list 'major-mode-remap-alist (cons name-mode name-ts-mode)))
     (t          ; (and (fboundp name-ts-mode) (not (fboundp name-mode)))
      (if-let ((file-regexp
                (alist-get lang mm-treesit-language-file-name-alist)))
          (add-to-list 'auto-mode-alist (cons file-regexp name-ts-mode))
        (warn "Unable to determine the extension for `%s'." name-ts-mode))))))

^L
;;; Hack For C23

(advice-add #'c-ts-mode--keywords :filter-return
            (defun mm-c-ts-mode-add-constexpr (keywords)
              ;; NOTE: We can’t add ‘typeof’ until it’s added to the TS grammar
              ;; https://github.com/tree-sitter/tree-sitter-c/issues/236
              (append keywords '("constexpr"))))

^L
;;; Highlight Predefined Variables

(with-eval-after-load 'treesit
  (defvar mm-c-font-lock-rules
    (treesit-font-lock-rules
     :language 'c
     :feature 'constant
     :override t
     `(((identifier) @font-lock-constant-face
        (:match ,(rx bos (or "__func__" "__FUNCTION__") eos)
                @font-lock-constant-face))))))

(add-hook 'c-ts-mode-hook
          (defun mm-c-apply-font-lock-extras ()
            (setq treesit-font-lock-settings
                  (append treesit-font-lock-settings mm-c-font-lock-rules))))

^L
;;; Region Expansion

(defun mm-expreg-expand (n)
  "Expand to N syntactic units."
  (interactive "p")
  (dotimes (_ n)
    (expreg-expand)))

(defun mm-expreg-expand-dwim ()
  "Do-What-I-Mean `expreg-expand' to start with symbol or word.
If over a real symbol, mark that directly, else start with a word.  Fall
back to regular `expreg-expand'."
  (interactive)
  (if (region-active-p)
      (expreg-expand)
    (let ((symbol (bounds-of-thing-at-point 'symbol)))
      (cond
       ((equal (bounds-of-thing-at-point 'word) symbol)
        (mm-expreg-expand 1))
       (symbol
        (mm-expreg-expand 2))
       (:else
        (expreg-expand))))))

(use-package expreg
  :ensure t
  :commands (mm-expreg-expand mm-expreg-expand-dwim)
  :bind ("M-SPC" . mm-expreg-expand-dwim))

(provide 'mm-treesit)