Skip to content

Commit c7483ab

Browse files
committed
feat: visual format buffer (early WIP)
1 parent a2d6892 commit c7483ab

File tree

1 file changed

+84
-0
lines changed

1 file changed

+84
-0
lines changed

elisp/visual-format.el

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
(defun visual-format--cleanup (start end)
2+
(while (and (< start end)
3+
(setq start (text-property-any start end 'display visual-format--space)))
4+
(remove-text-properties
5+
start
6+
(setq start (or (text-property-not-all start end 'display visual-format--space)
7+
end))
8+
'(display nil))))
9+
10+
(require 'treesit)
11+
12+
(defvar-local visual-format--buffer nil)
13+
(defvar-local visual-format--buffer-formatted nil)
14+
15+
(defmacro visual-format--with-buff (&rest body)
16+
`(with-current-buffer visual-format--buffer
17+
,@body))
18+
19+
(defmacro visual-format--with-buff-fmt (&rest body)
20+
`(with-current-buffer visual-format--buffer-formatted
21+
,@body))
22+
23+
(defun visual-format--depth-first-walk (&optional node node-fmt prev-node prev-node-fmt depth)
24+
(let ((node (or node (visual-format--with-buff (treesit-buffer-root-node))))
25+
(node-fmt (or node-fmt (visual-format--with-buff-fmt (treesit-buffer-root-node))))
26+
(prev-leaf prev-node)
27+
(prev-leaf-fmt prev-node-fmt)
28+
(depth (or depth 0)))
29+
(cl-assert (= (treesit-node-child-count node) (treesit-node-child-count node-fmt)))
30+
(dotimes (i (treesit-node-child-count node))
31+
(let* ((n (treesit-node-child node i))
32+
(n-fmt (treesit-node-child node-fmt i)))
33+
(if (zerop (treesit-node-child-count n)) ; leaf
34+
(let* ((pos-beg
35+
(visual-format--with-buff
36+
(or (and prev-leaf (max 1 (1- (treesit-node-end prev-leaf))))
37+
(point-min))))
38+
(pos-end (treesit-node-start n))
39+
(pos-beg-fmt
40+
(visual-format--with-buff-fmt
41+
(or (and prev-leaf-fmt (max 1 (1- (treesit-node-end prev-leaf-fmt))))
42+
(point-min))))
43+
(pos-end-fmt (treesit-node-start n-fmt))
44+
(fmt-spaces (visual-format--with-buff-fmt (buffer-substring pos-beg-fmt pos-end-fmt))))
45+
(visual-format--with-buff
46+
(message "Token at (%d):\t %s \t\t\t\t Prev: %s"
47+
depth
48+
(treesit-node-text n t)
49+
(treesit-node-text prev-leaf t))
50+
(unless (string= (buffer-substring pos-beg pos-end) fmt-spaces)
51+
(put-text-property pos-beg pos-end 'display fmt-spaces)))
52+
(setq prev-leaf n
53+
prev-leaf-fmt n-fmt))
54+
(let ((last-nodes (visual-format--depth-first-walk n n-fmt prev-leaf prev-leaf-fmt (1+ depth))))
55+
(setq prev-leaf (car last-nodes)
56+
prev-leaf-fmt (cdr last-nodes))))))
57+
(cons prev-leaf prev-leaf-fmt)))
58+
59+
(defvar visual-format-function #'apheleia-format-buffer)
60+
61+
(defun visual-format-buffer ()
62+
"Visually format the buffer without modifing it."
63+
(interactive)
64+
(visual-format--cleanup (point-min) (point-max))
65+
(let ((visual-format--buffer (current-buffer))
66+
(visual-format--buffer-formatted (get-buffer-create (format " *visual-format: %s*" (buffer-name))))
67+
(buf-str (buffer-string))
68+
(buf-mode major-mode))
69+
(visual-format--with-buff-fmt
70+
(delay-mode-hooks (funcall buf-mode))
71+
(delete-region (point-min) (point-max))
72+
(insert buf-str)
73+
(call-interactively visual-format-function))
74+
(with-silent-modifications
75+
(visual-format--depth-first-walk))))
76+
77+
;;;###autoload
78+
(define-minor-mode visual-format-mode
79+
"Format code without modifying the buffer."
80+
:lighter " VFmt"
81+
:global nil
82+
(if visual-format-mode
83+
(visual-format-buffer)
84+
(visual-format--cleanup (point-min) (point-max))))

0 commit comments

Comments
 (0)