mirror of
https://github.com/jimeh/.emacs.d.git
synced 2026-02-19 13:46:41 +00:00
chore(treesit): add and use treesit helpers for easier custom font-lock queries
This commit is contained in:
@@ -7,6 +7,8 @@
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'cl-lib)
|
||||
|
||||
(defmacro siren-prepend (list-var element)
|
||||
"Add ELEMENT to beginning of LIST-VAR, removing duplicates."
|
||||
`(setq ,list-var (cons ,element (remove ,element ,list-var))))
|
||||
@@ -55,6 +57,18 @@
|
||||
(cl-subseq cleaned-list (1+ pos)))
|
||||
(append cleaned-list (list ,element))))))
|
||||
|
||||
(defmacro siren-replace-value (list-var old-value new-value)
|
||||
"Replace all occurrences of OLD-VALUE with NEW-VALUE in LIST-VAR in-place."
|
||||
`(cl-loop for item on ,list-var
|
||||
if (equal (car item) ,old-value)
|
||||
do (setf (car item) ,new-value)))
|
||||
|
||||
(defmacro siren-replace-if (list-var predicate new-value)
|
||||
"Replace elements in LIST-VAR that match PREDICATE with NEW-VALUE in-place."
|
||||
`(cl-loop for item on ,list-var
|
||||
if (funcall ,predicate (car item))
|
||||
do (setf (car item) ,new-value)))
|
||||
|
||||
(defun siren-recursive-add-to-load-path (dir)
|
||||
"Add DIR and all its sub-directories to `load-path'."
|
||||
(add-to-list 'load-path dir)
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
(require 'siren-prog-mode)
|
||||
(require 'siren-projectile)
|
||||
(require 'siren-reformatter)
|
||||
(require 'siren-treesit)
|
||||
|
||||
(defgroup siren-go nil
|
||||
"Siren: go-mode configuration."
|
||||
@@ -109,36 +110,48 @@
|
||||
(defun siren-go-ts-mode-setup ()
|
||||
(setq-local tab-width siren-go-tab-width
|
||||
company-minimum-prefix-length 1
|
||||
ff-other-file-alist 'go-ts-other-file-alist
|
||||
treesit-font-lock-settings
|
||||
(append treesit-font-lock-settings
|
||||
(siren-go-ts-mode-font-lock-overrides)))
|
||||
ff-other-file-alist 'go-ts-other-file-alist)
|
||||
|
||||
(siren-treesit-append-font-lock-settings
|
||||
:default-language 'go
|
||||
|
||||
;; Highlight `true', `false', `nil' and `iota' as built-in constants,
|
||||
;; and const declarations as variable names.
|
||||
:feature 'constant
|
||||
:override t
|
||||
`([(false) (nil) (true)] @font-lock-builtin-face
|
||||
,@(when (go-ts-mode--iota-query-supported-p)
|
||||
'((iota) @font-lock-builtin-face))
|
||||
(const_declaration
|
||||
(const_spec name: (identifier) @font-lock-variable-name-face)))
|
||||
|
||||
;; Customize struct properties to be highlighted as a constant, as
|
||||
;; opposed the same as variables.
|
||||
:feature 'property
|
||||
:override t
|
||||
'((selector_expression
|
||||
field: (field_identifier) @font-lock-constant-face)
|
||||
(keyed_element (_ (identifier) @font-lock-constant-face))
|
||||
(field_declaration
|
||||
name: (field_identifier) @font-lock-constant-face))
|
||||
|
||||
;; Redefine functions calls without changes after the property feature
|
||||
;; change, to ensure they are still highlighted correctly.
|
||||
:feature 'function
|
||||
:override t
|
||||
'((call_expression
|
||||
function: (identifier) @font-lock-function-call-face)
|
||||
(call_expression
|
||||
function: (selector_expression
|
||||
field: (field_identifier) @font-lock-function-call-face))))
|
||||
|
||||
(when (fboundp 'highlight-symbol-mode)
|
||||
(highlight-symbol-mode -1))
|
||||
(when (fboundp 'auto-highlight-symbol-mode)
|
||||
(auto-highlight-symbol-mode -1)))
|
||||
|
||||
(defun siren-go-ts-mode-font-lock-overrides ()
|
||||
"Returns a list of overide treesit font-lock rules."
|
||||
(let ((language 'go))
|
||||
(treesit-font-lock-rules
|
||||
;; Highlight `true', `false', `nil' and `iota' as built-in constants,
|
||||
;; and const declarations as variable names.
|
||||
:language language
|
||||
:override t
|
||||
:feature 'constant
|
||||
`([(false) (nil) (true)] @font-lock-builtin-face
|
||||
,@(when (go-ts-mode--iota-query-supported-p)
|
||||
'((iota) @font-lock-builtin-face))
|
||||
(const_declaration
|
||||
(const_spec name: (identifier) @font-lock-variable-name-face)))
|
||||
)))
|
||||
|
||||
:config
|
||||
(require 'siren-treesit)
|
||||
(siren-treesit-auto-ensure-grammar 'go)
|
||||
(siren-treesit-auto-ensure-grammar 'gomod)
|
||||
|
||||
(siren-define-golines-format-mode)
|
||||
|
||||
@@ -155,31 +168,20 @@
|
||||
|
||||
:preface
|
||||
(defun siren-go-mod-ts-mode-setup ()
|
||||
(setq-local tab-width siren-go-tab-width
|
||||
treesit-font-lock-settings
|
||||
(append treesit-font-lock-settings
|
||||
(siren-go-mod-ts-mode-font-lock-overrides)))
|
||||
(setq-local tab-width siren-go-tab-width)
|
||||
|
||||
(add-to-list 'treesit-font-lock-feature-list '((module) (module_path))))
|
||||
(siren-treesit-add-features '(module_path module))
|
||||
(siren-treesit-append-font-lock-settings
|
||||
:default-language 'gomod
|
||||
|
||||
(defun siren-go-mod-ts-mode-font-lock-overrides ()
|
||||
"Returns a list of overide treesit font-lock rules."
|
||||
(let ((language 'gomod))
|
||||
(treesit-font-lock-rules
|
||||
:language language
|
||||
:override t
|
||||
:feature 'module_path
|
||||
'(((module_path) @font-lock-constant-face))
|
||||
:feature 'module
|
||||
'((module_directive (module_path) @font-lock-type-face))
|
||||
|
||||
:language language
|
||||
:override t
|
||||
:feature 'module
|
||||
'((module_directive (module_path) @font-lock-type-face))
|
||||
:feature 'module_path
|
||||
'(((module_path) @font-lock-constant-face))))
|
||||
|
||||
:language language
|
||||
:override t
|
||||
:feature 'number
|
||||
'([(go_version) (version)] @font-lock-number-face))))))
|
||||
:config
|
||||
(siren-treesit-auto-ensure-grammar 'gomod)))
|
||||
|
||||
(use-package lsp-go
|
||||
:straight lsp-mode
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
(require 'siren-projectile)
|
||||
(require 'siren-reformatter)
|
||||
(require 'siren-string-inflection)
|
||||
(require 'siren-treesit)
|
||||
|
||||
(defun siren-define-stree-format-mode ()
|
||||
"Setup stree (syntax_tree) formatter."
|
||||
@@ -138,36 +139,29 @@
|
||||
(setq-local c-tab-always-indent nil
|
||||
tab-width 2)
|
||||
|
||||
(setq-local treesit-font-lock-settings
|
||||
(append treesit-font-lock-settings
|
||||
(siren-ruby-ts-mode-font-lock-overrides)))
|
||||
(siren-treesit-add-features '(block-braces))
|
||||
(siren-treesit-append-font-lock-settings
|
||||
:default-language 'ruby
|
||||
|
||||
(hs-minor-mode t))
|
||||
|
||||
(defun siren-ruby-ts-mode-font-lock-overrides ()
|
||||
"Returns a list of overide treesit font-lock rules."
|
||||
(let ((language 'ruby))
|
||||
(treesit-font-lock-rules
|
||||
;; Use custom operators list.
|
||||
:language language
|
||||
:override t
|
||||
:feature 'operator
|
||||
`("!" @font-lock-negation-char-face
|
||||
;; Use custom operators list.
|
||||
:feature 'operator
|
||||
:override t
|
||||
`("!" @font-lock-negation-char-face
|
||||
[,@siren-ruby-ts-operators] @font-lock-operator-face)
|
||||
|
||||
;; Braces, when used to denote a block, have the same function as
|
||||
;; "do" and "end" and should be highlighted similarly.
|
||||
:language language
|
||||
:override t
|
||||
:feature 'block-braces
|
||||
'((block ["{" "}"] @font-lock-keyword-face))
|
||||
;; Braces, when used to denote a block, have the same function as
|
||||
;; "do" and "end" and should be highlighted similarly.
|
||||
:feature 'block-braces
|
||||
:override t
|
||||
'((block ["{" "}"] @font-lock-keyword-face))
|
||||
|
||||
;; Highlight string interpolation begin/end markers as keywords.
|
||||
:language language
|
||||
:override t
|
||||
:feature 'interpolation
|
||||
'((interpolation "#{" @font-lock-keyword-face)
|
||||
(interpolation "}" @font-lock-keyword-face)))))
|
||||
;; Highlight string interpolation begin/end markers as keywords.
|
||||
:feature 'interpolation
|
||||
:override t
|
||||
'((interpolation "#{" @font-lock-keyword-face)
|
||||
(interpolation "}" @font-lock-keyword-face)))
|
||||
|
||||
(hs-minor-mode t))
|
||||
|
||||
:config
|
||||
(siren-treesit-auto-ensure-grammar 'ruby)
|
||||
@@ -181,7 +175,7 @@
|
||||
;; Must be defined after ruby-ts-mode is loaded, as we need access to the
|
||||
;; `ruby-ts--operators' variable.
|
||||
(defcustom siren-ruby-ts-operators
|
||||
(append ruby-ts--operators '("->"))
|
||||
(append ruby-ts--operators '("->" "||="))
|
||||
"Ruby operators for tree-sitter font-locking."
|
||||
:group 'siren-ruby-ts)))
|
||||
|
||||
|
||||
@@ -22,6 +22,80 @@
|
||||
(when (not (treesit-ready-p ',lang t))
|
||||
(treesit-install-language-grammar ',lang))))))
|
||||
|
||||
(defun siren-treesit-add-features (&rest features)
|
||||
"Add font-lock features to treesit."
|
||||
(add-to-list 'treesit-font-lock-feature-list features) t)
|
||||
|
||||
(defun siren-treesit-append-font-lock-settings (&rest query-specs)
|
||||
"Replace existing features in font-lock settings, retaining feature order."
|
||||
(setq-local
|
||||
treesit-font-lock-settings
|
||||
(append treesit-font-lock-settings
|
||||
(apply 'treesit-font-lock-rules query-specs))))
|
||||
|
||||
|
||||
(defun siren-treesit-add-font-lock-settings (&rest query-specs)
|
||||
"Add features after existing ones in font-lock settings."
|
||||
(dolist (item (apply 'treesit-font-lock-rules query-specs))
|
||||
(let* ((feature (nth 2 item))
|
||||
(existing (cl-find-if (lambda (x) (eq (nth 2 x) feature))
|
||||
(reverse treesit-font-lock-settings))))
|
||||
(if existing
|
||||
(siren-add-after treesit-font-lock-settings existing item)
|
||||
(add-to-list 'treesit-font-lock-settings item t)))))
|
||||
|
||||
(defun siren-treesit-replace-font-lock-settings (&rest query-specs)
|
||||
"Replace existing features in font-lock settings, retaining feature order."
|
||||
(setq-local
|
||||
treesit-font-lock-settings
|
||||
(siren-treesit--replace-font-lock-settings
|
||||
treesit-font-lock-settings
|
||||
(apply 'treesit-font-lock-rules query-specs))))
|
||||
|
||||
(defun siren-treesit-replace-or-add-font-lock-settings (&rest query-specs)
|
||||
"Set font-lock settings for treesit, merging with existing settings."
|
||||
(setq-local treesit-font-lock-settings
|
||||
(siren-treesit--merge-font-lock-settings
|
||||
treesit-font-lock-settings
|
||||
(apply 'treesit-font-lock-rules query-specs))))
|
||||
|
||||
(defun siren-treesit--feature (compiled-query)
|
||||
"Get the feature from a compiled treesit query."
|
||||
(nth 2 compiled-query))
|
||||
|
||||
(defun siren-treesit--replace-font-lock-settings (a b)
|
||||
"Replace treesit font-lock settings A with B based on feature."
|
||||
(let ((merged (copy-tree a)))
|
||||
(dolist (replacement b)
|
||||
(let* ((feature (siren-treesit--feature replacement))
|
||||
(existing (cl-find-if
|
||||
(lambda (x) (eq (siren-treesit--feature x) feature))
|
||||
merged)))
|
||||
(if existing
|
||||
(setf (car (member existing merged)) replacement)
|
||||
)))
|
||||
merged))
|
||||
|
||||
(defun siren-treesit--merge-font-lock-settings (a b)
|
||||
"Merge two treesit font-lock settings A and B into a new list.
|
||||
|
||||
This function merges the two treesit font-lock settings lists, returning
|
||||
a new list.
|
||||
|
||||
Features from B will replace features in A if they are present in both.
|
||||
Features only present in A will be kept, and features only present in B
|
||||
will be appended."
|
||||
(let ((merged (copy-tree a)))
|
||||
(dolist (item-b b)
|
||||
(let* ((key (siren-treesit--feature item-b))
|
||||
(existing (cl-find-if
|
||||
(lambda (item) (eq (siren-treesit--feature item) key))
|
||||
merged)))
|
||||
(if existing
|
||||
(setf (car (member existing merged)) item-b)
|
||||
(setq merged (append merged (list item-b))))))
|
||||
merged))
|
||||
|
||||
(use-package treesit-auto
|
||||
:demand t
|
||||
:if (fboundp 'treesit-ready-p)
|
||||
@@ -30,9 +104,14 @@
|
||||
|
||||
:preface
|
||||
(defun siren-treesit-auto-ensure-grammar (grammar)
|
||||
"Ensure that treesit GRAMMAR is installed and ready for use."
|
||||
"Ensure treesit GRAMMAR is installed and ready for use."
|
||||
(when (and (fboundp 'treesit-ready-p)
|
||||
(not (treesit-ready-p grammar t)))
|
||||
(siren-treesit-install-grammar grammar)))
|
||||
|
||||
(defun siren-treesit-install-grammar (grammar)
|
||||
"Install treesit GRAMMAR."
|
||||
(when (fboundp 'treesit-ready-p)
|
||||
(let ((treesit-language-source-alist
|
||||
(treesit-auto--build-treesit-source-alist)))
|
||||
(treesit-install-language-grammar grammar))))
|
||||
|
||||
@@ -25,8 +25,8 @@
|
||||
|
||||
'(font-lock-comment-face :foreground (doom-lighten comments 0.15))
|
||||
'(font-lock-operator-face :inherit 'font-lock-keyword-face)
|
||||
'(font-lock-property-name-face :foreground (doom-lighten constants 0.1))
|
||||
'(font-lock-property-use-face :inherit 'font-lock-property-name-face)
|
||||
'(font-lock-property-name-face :inherit 'font-lock-variable-name-face)
|
||||
'(font-lock-property-use-face :inherit 'font-lock-variable-name-face)
|
||||
'(font-lock-variable-name-face :foreground (doom-lighten blue 0.25))
|
||||
|
||||
;; built-in completion faces, based on doom-themes' defaults for orderless
|
||||
|
||||
Reference in New Issue
Block a user