Add ruby support to origami-treesit and make folding level configurable

This commit is contained in:
Jeremy Dormitzer 2024-05-07 16:58:51 -04:00
parent 0209cf16c5
commit a0c0f6d1e2
2 changed files with 116 additions and 11 deletions

View File

@ -113,6 +113,8 @@
:straight (:type built-in)
:ensure nil
:load-path "packages/origami-treesit"
:after origami)
:after origami
:custom
(origami-treesit-level 4))
(provide 'init-treesit)

View File

@ -29,6 +29,12 @@
(require 'cl-lib)
(require 'dash)
(defcustom origami-treesit-level 2
"The level of folding to use for origami-treesit."
:type 'integer
:group 'origami
:options '(1 2 3 4))
(cl-defun make-treesit-parser (create
lang
&key
@ -38,20 +44,24 @@
(let* ((parser (treesit-parser-create lang))
(root (treesit-parser-root-node parser)))
(cl-labels ((get-node-folds (node)
(if (funcall node-matcher-fn node)
(cl-destructuring-bind (start end offset child-nodes) (funcall fold-fn node)
(list (funcall create start end offset (-mapcat #'get-node-folds child-nodes))))
(if (funcall node-matcher-fn node origami-treesit-level)
(cl-destructuring-bind
(start end offset child-nodes &optional sibling-nodes)
(funcall fold-fn node)
(cons (funcall create start end offset (-mapcat #'get-node-folds child-nodes))
(-mapcat #'get-node-folds sibling-nodes)))
(-mapcat #'get-node-folds (treesit-node-children node)))))
(get-node-folds root)))))
(defun origami-yaml-treesit-parser (create)
(make-treesit-parser create 'yaml
:node-matcher-fn (lambda (node)
(member (treesit-node-type node)
'("block_mapping_pair"
"flow_mapping"
"flow_pair"
"flow_sequence")))
:node-matcher-fn (lambda (node _level)
(and (treesit-node-check node 'named)
(member (treesit-node-type node)
'("block_mapping_pair"
"flow_mapping"
"flow_pair"
"flow_sequence"))))
:fold-fn (lambda (node)
(pcase (treesit-node-type node)
((or "block_mapping_pair" "flow_pair")
@ -83,9 +93,102 @@
(child-nodes (treesit-node-children node)))
(list start end offset child-nodes)))))))
(defun origami-ruby-treesit-parser (create)
(make-treesit-parser create 'ruby
:node-matcher-fn
(lambda (node level)
(let ((foldable-node-types '()))
(when (>= level 1)
(setq foldable-node-types
(append foldable-node-types
'("class" "method" "do_block" "hash" "array"))))
(when (>= level 2)
(setq foldable-node-types
(append foldable-node-types
'("block" "then" "else"))))
(when (>= level 3)
(setq foldable-node-types
(append foldable-node-types
'("call" "assignment"))))
(and (treesit-node-check node 'named)
(member (treesit-node-type node) foldable-node-types)
(or (not (member (treesit-node-type node)
'("class"
"method"
"do_block"
"block")))
(treesit-node-child-by-field-name node "body"))
(or (not (equal (treesit-node-type node) "hash"))
(treesit-search-subtree
node
(lambda (n)
(equal (treesit-node-type n) "pair"))))
(or (not (equal (treesit-node-type node) "call"))
(treesit-node-child-by-field-name node "arguments"))
(or (not (member (treesit-node-type node) '("then" "else")))
(treesit-node-children node)))))
:fold-fn
(lambda (node)
(pcase (treesit-node-type node)
("class" (let* ((start (treesit-node-start node))
(end (- (treesit-node-end node) 4))
(body (treesit-node-child-by-field-name node "body"))
(offset (save-excursion
(goto-char start)
(forward-line)
(back-to-indentation)
(- (point) start)))
(child-nodes (treesit-node-children node)))
(list start end offset child-nodes)))
((or "method" "do_block" "block")
(let* ((body
(treesit-node-child-by-field-name node "body"))
(start (treesit-node-start node))
(end (treesit-node-end body))
(offset (- (treesit-node-start body) start))
(child-nodes (treesit-node-children node)))
(list start end offset child-nodes)))
("hash" (let* ((pairs (-filter (lambda (n)
(equal (treesit-node-type n) "pair"))
(treesit-node-children node)))
(start (treesit-node-start node))
(end (treesit-node-end (car (last pairs))))
(offset (- (treesit-node-start (first pairs)) start))
(child-nodes (treesit-node-children node)))
(list start end offset child-nodes)))
("array" (let* ((start (treesit-node-start node))
(end (- (treesit-node-end node) 1))
(offset 1)
(child-nodes (treesit-node-children node)))
(list start end offset child-nodes)))
("call" (let* ((args (treesit-node-child-by-field-name node "arguments"))
(method (treesit-node-child-by-field-name node "method"))
(start (treesit-node-start method))
(end (- (treesit-node-end args) 1))
(offset (1+ (- (treesit-node-start args) start)))
(child-nodes (list args))
(sibling-nodes (when-let
((block
(treesit-node-child-by-field-name node "block")))
(list block))))
(list start end offset child-nodes sibling-nodes)))
((or "then" "else") (let* ((child-nodes (treesit-node-children node))
(start (treesit-node-start node))
(end (treesit-node-end (car (last child-nodes))))
(offset (- (treesit-node-start (first child-nodes)) start)))
(list start end offset child-nodes)))
("assignment" (let* ((right (treesit-node-child-by-field-name node "right"))
(start (treesit-node-start node))
(end (treesit-node-end node))
(offset (- (treesit-node-start right) start))
(child-nodes (list right)))
(list start end offset child-nodes)))))))
(with-eval-after-load 'origami
(add-to-list 'origami-parser-alist '(yaml-ts-mode . origami-yaml-treesit-parser))
(add-to-list 'origami-parser-alist '(yaml-mode . origami-yaml-treesit-parser)))
(add-to-list 'origami-parser-alist '(yaml-mode . origami-yaml-treesit-parser))
(add-to-list 'origami-parser-alist '(ruby-ts-mode . origami-ruby-treesit-parser))
(add-to-list 'origami-parser-alist '(ruby-mode . origami-ruby-treesit-parser)))
(provide 'origami-treesit)
;;; origami-treesit.el ends here