refactor(treecrumbs): macro for language definitions

Adds a macro that provides a more convenient syntax for defining new
languages for treecrumbs (and that can also be easily used outside of
the core treecrumbs code).

This macro automatically takes care of compiling tree-sitter queries
for reuse.

Change-Id: I6a0b892a083c3f243e8b8f0e1c865a9a8a1a5cf5
Reviewed-on: https://cl.tvl.fyi/c/depot/+/11107
Reviewed-by: tazjin <tazjin@tvl.su>
Autosubmit: tazjin <tazjin@tvl.su>
Tested-by: BuildkiteCI
This commit is contained in:
Vincent Ambo 2024-03-09 15:55:18 +03:00 committed by clbot
parent 2c9bbe37be
commit 470f7dfa45

View file

@ -34,6 +34,7 @@
;;; Code: ;;; Code:
(require 'seq)
(require 'treesit) (require 'treesit)
(defvar treecrumbs-languages nil (defvar treecrumbs-languages nil
@ -45,30 +46,49 @@ Alist of symbols representing tree-sitter languages (e.g. `yaml')
to another alist (the \"node type list\") describing how to another alist (the \"node type list\") describing how
different node types should be displayed in the crumbs. different node types should be displayed in the crumbs.
The node type list has string keys (corresponding to tree-sitter See `define-treecrumbs-language' for more details on how to add a
node type names), and its values are either a static language.")
string (which is displayed verbatim in the crumbs if such a node
is encountered), or a tree-sitter query.
Tree-sitter queries are executed on the node, and MUST capture (defmacro define-treecrumbs-language (lang &rest clauses)
exactly one argument named `@key', which should be a node whose "Defines a new language for use in treecrumbs. LANG should be a
text value will become the braedcrumb (e.g. the name of a symbol representing the language as understood by treesit (e.g.
function, the key in a map, ...). `yaml').
Each of CLAUSES is a cons cell mapping the name of a tree
node (in string format) to one of either:
1. a static string, which will become the breadcrumb verbatim
2. a tree-sitter query (in S-expression syntax) which must capture
exactly one argument named `@key' that will become the
breadcrumb (e.g. the name of a function, the key in a map, ...)
Treecrumbs will only consider node types that are mentioned in Treecrumbs will only consider node types that are mentioned in
the node type list. All other nodes are ignored when constructing CLAUSES. All other nodes are ignored when constructing the
the crumbs.") crumbs.
(setq treecrumbs-languages The defined languages are stored in `treecrumbs-languages'."
`(;; In YAML documents, crumbs are generated from the keys of maps,
;; and from elements of arrays. (declare (indent 1))
(yaml . (("block_mapping_pair" . (let ((compiled
,(treesit-query-compile 'yaml '((block_mapping_pair key: (_) @key)))) (seq-map (lambda (clause)
("block_sequence" . "[]") (if (stringp (cdr clause))
("flow_pair" . `(cons ,(car clause) ,(cdr clause))
;; TODO: Why can this query not match on to (flow_pair)? `(cons ,(car clause)
,(treesit-query-compile 'yaml '((_) key: (_) @key))) (treesit-query-compile ',lang ',(cdr clause)))))
("flow_sequence" . "[]"))))) clauses)))
`(setf (alist-get ',lang treecrumbs-languages nil nil #'equal) (list ,@compiled))))
(define-treecrumbs-language yaml
;; In YAML documents, crumbs are generated from the keys of maps, and from
;; elements of arrays. "block"-nodes are standard YAML syntax, "flow"-nodes
;; are inline JSON-ish syntax.
("block_mapping_pair" . ((block_mapping_pair key: (_) @key)))
("block_sequence" . "[]")
;; TODO: Why can this query not match on to (flow_pair)?
("flow_pair" . ((_) key: (_) @key))
("flow_sequence" . "[]"))
(defvar-local treecrumbs--current-crumbs nil (defvar-local treecrumbs--current-crumbs nil
"Current crumbs to display in the header line. Only updated when "Current crumbs to display in the header line. Only updated when