From a0c0f6d1e29a177b9978e08e2c203058788a6783 Mon Sep 17 00:00:00 2001 From: Jeremy Dormitzer Date: Tue, 7 May 2024 16:58:51 -0400 Subject: [PATCH] Add ruby support to origami-treesit and make folding level configurable --- emacs/.emacs.d/config/init-treesit.el | 4 +- .../origami-treesit/origami-treesit.el | 123 ++++++++++++++++-- 2 files changed, 116 insertions(+), 11 deletions(-) diff --git a/emacs/.emacs.d/config/init-treesit.el b/emacs/.emacs.d/config/init-treesit.el index f678dc7..9ac7de4 100644 --- a/emacs/.emacs.d/config/init-treesit.el +++ b/emacs/.emacs.d/config/init-treesit.el @@ -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) diff --git a/emacs/.emacs.d/packages/origami-treesit/origami-treesit.el b/emacs/.emacs.d/packages/origami-treesit/origami-treesit.el index 29df87b..c1a256c 100644 --- a/emacs/.emacs.d/packages/origami-treesit/origami-treesit.el +++ b/emacs/.emacs.d/packages/origami-treesit/origami-treesit.el @@ -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