branch: elpa/treesit-fold
commit 56e6743bacdc8ad4057c878e93baa792ceae601c
Author: Jen-Chieh Shen <[email protected]>
Commit: GitHub <[email protected]>

    feat: Improve folding for C preproc operators (#46)
    
    * feat: Improve folding for C preproc operators
    
    * changelog
    
    * imp
---
 CHANGELOG.md    |  1 +
 ts-fold-util.el | 49 +++++++++++++++++++++++++++++++++++++++++++++++++
 ts-fold.el      | 33 +++++++++++++++++++--------------
 3 files changed, 69 insertions(+), 14 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index b873d35944..19deaf481e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -16,6 +16,7 @@ Check [Keep a Changelog](http://keepachangelog.com/) for 
recommendations on how
 * Remove redundant fold node alist (#36)
 * Change global mode to turn on with tree-sitter (#41)
 * Add minor-mode `ts-fold-line-comment-mode` for line comment folding (#45)
+* Improve folding for C preprocessor operators (#46)
 
 ## 0.1.0
 > Released Oct 18, 2021
diff --git a/ts-fold-util.el b/ts-fold-util.el
index 2cf7ae91fb..d9681320ac 100644
--- a/ts-fold-util.el
+++ b/ts-fold-util.el
@@ -25,6 +25,14 @@
 
 ;;; Code:
 
+;;
+;; (@* "Util" )
+;;
+
+(defun ts-fold-2-str (object)
+  "Convert OBJECT to string."
+  (format "%s" object))
+
 ;;
 ;; (@* "Cons" )
 ;;
@@ -86,5 +94,46 @@ Optional argument TRIM, see function `ts-fold--get-face'."
   "Check to see if IN-VAL is between IN-MIN and IN-MAX."
   (and (<= in-min in-val) (<= in-val in-max)))
 
+;;
+;; (@* "TS node" )
+;;
+
+(defun ts-fold--compare-type (node type)
+  "Compare NODE's type to TYPE."
+  (string= (ts-fold-2-str (tsc-node-type node)) type))
+
+(defun ts-fold-children (node)
+  "Return children from NODE."
+  (let (children)
+    (dotimes (index (tsc-count-children node))
+      (push (tsc-get-nth-child node index) children))
+    (reverse children)))
+
+(defun ts-fold-children-traverse (node)
+  "Return children from NODE but traverse it."
+  (let (nodes)
+    (tsc-traverse-mapc (lambda (next) (push next nodes)) node)
+    (reverse nodes)))
+
+(defun ts-fold-find-children (node type)
+  "Search node TYPE from children; this return a list."
+  (cl-remove-if-not (lambda (next) (ts-fold--compare-type next type))
+                    (ts-fold-children node)))
+
+(defun ts-fold-find-children-traverse (node type)
+  "Like function `ts-fold-find-children' but traverse it."
+  (cl-remove-if-not (lambda (next) (ts-fold--compare-type next type))
+                    (ts-fold-children-traverse node)))
+
+(defun ts-fold-find-parent (node type)
+  "Find the TYPE of parent from NODE."
+  (let ((parent (tsc-get-parent node))
+        (break))
+    (while (and parent (not break))
+      (setq break (ts-fold--compare-type parent type))
+      (unless break
+        (setq parent (tsc-get-parent parent))))
+    parent))
+
 (provide 'ts-fold-util)
 ;;; ts-fold-util.el ends here
diff --git a/ts-fold.el b/ts-fold.el
index 09bc224a4c..0412d5cbd4 100644
--- a/ts-fold.el
+++ b/ts-fold.el
@@ -445,7 +445,8 @@ more information."
 For arguments NODE and OFFSET, see function `ts-fold-range-seq' for
 more information."
   (let* ((named-node (tsc-get-child-by-field node :condition))
-         (else (tsc-get-child-by-field node :alternative))
+         (else (or (tsc-get-child-by-field node :alternative)
+                   (car (ts-fold-find-children node "#endif"))))
          (beg (tsc-node-end-position named-node))
          (end (1- (tsc-node-start-position else))))
     (ts-fold--cons-add (cons beg end) offset)))
@@ -456,7 +457,8 @@ more information."
 For arguments NODE and OFFSET, see function `ts-fold-range-seq' for
 more information."
   (when-let* ((named-node (tsc-get-child-by-field node :name))
-              (else (tsc-get-child-by-field node :alternative))
+              (else (or (tsc-get-child-by-field node :alternative)
+                        (car (ts-fold-find-children node "#endif"))))
               (beg (tsc-node-end-position named-node))
               (end (1- (tsc-node-start-position else))))
     (ts-fold--cons-add (cons beg end) offset)))
@@ -467,9 +469,12 @@ more information."
 For arguments NODE and OFFSET, see function `ts-fold-range-seq' for
 more information."
   (when-let* ((named-node (tsc-get-child-by-field node :condition))
-              (else (tsc-get-child-by-field node :alternative))
+              (parent (or (ts-fold-find-parent node "preproc_if")
+                          (ts-fold-find-parent node "preproc_ifdef")))
+              (next (or (tsc-get-child-by-field node :alternative)
+                        (car (ts-fold-find-children parent "#endif"))))
               (beg (tsc-node-end-position named-node))
-              (end (1- (tsc-node-start-position else))))
+              (end (1- (tsc-node-start-position next))))
     (ts-fold--cons-add (cons beg end) offset)))
 
 (defun ts-fold-range-c-preproc-else (node offset)
@@ -477,10 +482,12 @@ more information."
 
 For arguments NODE and OFFSET, see function `ts-fold-range-seq' for
 more information."
-  (when-let* ((target "#else")
-              (len (length target))
-              (beg (+ (tsc-node-start-position node) len))
-              (end (tsc-node-end-position node)))
+  (when-let* ((else-str (car (split-string (tsc-node-text node) "\n")))
+              (parent (or (ts-fold-find-parent node "preproc_if")
+                          (ts-fold-find-parent node "preproc_ifdef")))
+              (next (car (ts-fold-find-children parent "#endif")))
+              (beg (+ (tsc-node-start-position node) (length else-str)))
+              (end (1- (tsc-node-start-position next))))
     (ts-fold--cons-add (cons beg end) offset)))
 
 (defun ts-fold-range-html (node offset)
@@ -501,12 +508,10 @@ more information."
 For arguments NODE and OFFSET, see function `ts-fold-range-seq' for
 more information."
   (unless (ts-fold--one-liner-node node)
-    (when-let*
-        ((text  (tsc-node-text node))
-         (beg   (if (string-prefix-p "(* " text)
-                    (+ 2 (tsc-node-start-position node))
-                  (+ 3 (tsc-node-start-position node))))
-         (end   (- (tsc-node-end-position node) 2)))
+    (when-let* ((text (tsc-node-text node))
+                (beg  (+ (if (string-prefix-p "(* " text) 2 3)
+                         (tsc-node-start-position node)))
+                (end  (- (tsc-node-end-position node) 2)))
       (ts-fold--cons-add (cons beg end) offset))))
 
 (defun ts-fold-range-ocaml-module-definition (node offset)

Reply via email to