From 5231bdb0757df1b140c2d2e94fbc99c438ed35df Mon Sep 17 00:00:00 2001 From: Jen-Chieh Shen Date: Wed, 24 Jul 2024 17:28:14 -0700 Subject: [PATCH] feat: Fold markdown heading (#123) * feat: Fold markdown heading * fix: markdown html_block --- ts-fold-parsers.el | 8 +++++-- ts-fold-summary.el | 7 ++++--- ts-fold-util.el | 24 ++++++++++++--------- ts-fold.el | 52 ++++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 74 insertions(+), 17 deletions(-) diff --git a/ts-fold-parsers.el b/ts-fold-parsers.el index fe3c97f..5f9ad01 100644 --- a/ts-fold-parsers.el +++ b/ts-fold-parsers.el @@ -72,6 +72,9 @@ (declare-function ts-fold-range-lua-do-loop "ts-fold.el") (declare-function ts-fold-range-lua-repeat "ts-fold.el") (declare-function ts-fold-range-make-recipe "ts-fold.el") +(declare-function ts-fold-range-markdown-heading "ts-fold.el") +(declare-function ts-fold-range-markdown-code-block "ts-fold.el") +(declare-function ts-fold-range-markdown-html-block "ts-fold.el") (declare-function ts-fold-range-matlab-function "ts-fold.el") (declare-function ts-fold-range-matlab-statements "ts-fold.el") (declare-function ts-fold-range-matlab-blocks "ts-fold.el") @@ -430,8 +433,9 @@ (defun ts-fold-parsers-markdown () "Rule set for Markdown." - '((fenced_code_block . (ts-fold-range-seq 2 -2)) - (html_block . ts-fold-range-html))) + '((fenced_code_block . ts-fold-range-markdown-code-block) + (section . ts-fold-range-markdown-heading) + (html_block . ts-fold-range-markdown-html-block))) (defun ts-fold-parsers-matlab () "Rule set for MATLAB." diff --git a/ts-fold-summary.el b/ts-fold-summary.el index e11379a..c815427 100644 --- a/ts-fold-summary.el +++ b/ts-fold-summary.el @@ -89,7 +89,8 @@ type of content by checking the word boundary's existence." (defun ts-fold-summary--doc-extract (doc-str sym) "Default way to extract the doc summary from DOC-STR using SYM." - (let* ((lines (ts-fold-summary--extract-summary doc-str sym)) (summary (nth 0 lines))) + (let* ((lines (ts-fold-summary--extract-summary doc-str sym)) + (summary (nth 0 lines))) (when summary (setq summary (string-trim summary))) (if (string-empty-p summary) nil summary))) @@ -159,8 +160,8 @@ type of content by checking the word boundary's existence." (defun ts-fold-summary-c-macro (doc-str) "Parse C macro summary from DOC-STR." (when (ts-fold--is-face doc-str - '(font-lock-preprocessor-face - preproc-font-lock-preprocessor-background)) + '( font-lock-preprocessor-face + preproc-font-lock-preprocessor-background)) (ts-fold-summary--doc-extract doc-str ""))) (defun ts-fold-summary-c (doc-str) diff --git a/ts-fold-util.el b/ts-fold-util.el index cb16f9c..6967965 100644 --- a/ts-fold-util.el +++ b/ts-fold-util.el @@ -64,9 +64,13 @@ Like function `s-count-matches' but faster." ;; (@* "Cons" ) ;; -(defun ts-fold--cons-add (c1 c2) - "Addition for two cons C1 and C2." - (cons (+ (car c1) (car c2)) (+ (cdr c1) (cdr c2)))) +(defun ts-fold--cons-add (&rest args) + "Addition for list of cons ARGS." + (let ((v1 0) (v2 0)) + (dolist (c args) + (setq v1 (+ v1 (car c)) + v2 (+ v2 (cdr c)))) + (cons v1 v2))) ;; ;; (@* "Overlay" ) @@ -86,13 +90,13 @@ Like function `s-count-matches' but faster." ;; (defvar ts-fold--doc-faces - '(font-lock-doc-face - font-lock-comment-face - font-lock-comment-delimiter-face - tree-sitter-hl-face:comment - tree-sitter-hl-face:doc - hl-todo - rst-comment) + '( font-lock-doc-face + font-lock-comment-face + font-lock-comment-delimiter-face + tree-sitter-hl-face:comment + tree-sitter-hl-face:doc + hl-todo + rst-comment) "List of face that apply for document string.") (defun ts-fold--get-face (obj trim) diff --git a/ts-fold.el b/ts-fold.el index cb53c6c..0031239 100644 --- a/ts-fold.el +++ b/ts-fold.el @@ -547,13 +547,13 @@ then return the last iterated node. Argument NEXT is a boolean type. If non-nil iterate forward; otherwise iterate in backward direction." (let* ((iter-node node) (last-node node) - (last-line (car (tsc-node-start-point node))) line text break + (last-line (car (tsc-node-start-position node))) line text break (line-range 1) (last-line-range 1) max-line-range (indentation (ts-fold--indentation (tsc-node-start-position iter-node))) next-indentation) (while (and iter-node (not break)) (setq text (string-trim (tsc-node-text iter-node)) - line (car (tsc-node-start-point iter-node)) + line (car (tsc-node-start-position iter-node)) line-range (1+ (ts-fold--count-matches "\n" text)) max-line-range (max line-range last-line-range) next-indentation (ts-fold--indentation (tsc-node-start-position iter-node))) @@ -1088,6 +1088,54 @@ more information." (end (tsc-node-end-position last-child))) (ts-fold--cons-add (cons beg end) offset))) +(defun ts-fold-range-markdown-next-heading (node siblings) + "Return first heading from SIBLINGS with start point after NODE. +If there is no sibling, then return nil." + (or + (seq-find + (lambda (n) + (when-let ((child (tsc-get-nth-child n 0))) + (and (> (tsc-node-start-position child) (tsc-node-start-position node)) + (ts-fold--compare-type child "atx_heading")))) + (remove node siblings)) + (tsc-get-next-sibling (tsc-get-parent node)))) + +(defun ts-fold-range-markdown-heading (node offset) + "Define fold range for Markdown headings. + +For arguments NODE and OFFSET, see function `ts-fold-range-seq' for +more information." + (when-let* + ((parent (tsc-get-parent node)) + (head (tsc-get-nth-child node 0)) + (beg (tsc-node-start-position node)) + (siblings (ts-fold-find-children parent "section")) + (end (1- (or (ignore-errors (tsc-node-start-position + (ts-fold-range-markdown-next-heading node siblings))) + (point-max)))) + (name (length (string-trim (or (tsc-node-text head) ""))))) + (ts-fold--cons-add (cons beg end) (cons name 0) offset))) + +(defun ts-fold-range-markdown-code-block (node offset) + "Define fold range for Markdown code blocks. +For arguments NODE and OFFSET, see function `ts-fold-range-seq' for +more information." + (let* ((beg (1+ (tsc-node-start-position node))) + (end (1- (tsc-node-end-position node))) + (name (+ 2 (length + (or (tsc-node-text (tsc-get-nth-child node 1)) + ""))))) + (ts-fold--cons-add (cons beg end) (cons name -2) offset))) + +(defun ts-fold-range-markdown-html-block (node offset) + "Define fold range for Markdown `html_block'. + +For arguments NODE and OFFSET, see function `ts-fold-range-seq' for +more information." + (let* ((beg (+ (tsc-node-start-position node) 2)) + (end (- (tsc-node-end-position node) 3))) + (ts-fold--cons-add (cons beg end) offset))) + (defun ts-fold-range-matlab-blocks (node offset) "Define fold range for MATLAB blocks.