Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rip modelocal #69

Merged
merged 9 commits into from
Nov 24, 2023
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

test:
cask
TESTING=1 cask exec buttercup -L . -l "tests/setup.el"
TESTING=1 cask exec buttercup -L . -l "tests/setup.el" --traceback pretty

clean:
rm -rf .cask
Expand Down
201 changes: 103 additions & 98 deletions evil-tree-edit.el
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ moving the sibling index by the provided value."
,@body
(run-hooks 'evil-tree-edit-after-change-hook)
(evil-tree-edit-set-current-node
(tree-edit--node-from-steps ,location-sym))
(tree-edit--node-from-steps ,location-sym))
(evil-tree-edit--update-overlay))))

(defun evil-tree-edit--preserve-current-node-before (_ __)
Expand All @@ -104,11 +104,12 @@ but it seems to not work reliably with `tree-edit--node-from-steps'."
"Move NODE to the next (interesting) named sibling."
(let ((parent (treesit-node-parent node)))
(cond
((not parent) node)
((or (not parent)
(not (treesit-node-parent parent))) node)
((treesit-node-eq parent (treesit-buffer-root-node)) node)
((--any (member (treesit-node-type parent)
(cons it (alist-get it tree-edit--subtypes '())))
tree-edit-significant-node-types)
(tree-edit-significant-node-types))
parent)
(t (evil-tree-edit--get-sig-parent parent)))))

Expand Down Expand Up @@ -199,13 +200,13 @@ If RETURN-NODE is unset, `evil-tree-edit-current-node' is used."
(defun evil-tree-edit-append-sibling-placeholder-and-change ()
"Add a placeholder node and then change it."
(interactive)
(evil-tree-edit-insert-sibling tree-edit-placeholder-node-type)
(evil-tree-edit-insert-sibling (tree-edit-placeholder-node-type))
(evil-tree-edit-change))

(defun evil-tree-edit-insert-child-placeholder-and-change ()
"Add a placeholder node and then change it."
(interactive)
(evil-tree-edit-insert-child tree-edit-placeholder-node-type)
(evil-tree-edit-insert-child (tree-edit-placeholder-node-type))
(evil-tree-edit-change))

(defun evil-tree-edit-sig-avy-jump (node-type)
Expand All @@ -217,7 +218,7 @@ NODE-TYPE can be a symbol or a list of symbol."
(evil-tree-edit--remember)
(let ((query-node
(if (member (treesit-node-type (evil-tree-edit-current-node))
tree-edit-significant-node-types)
(tree-edit-significant-node-types))
(evil-tree-edit-current-node)
(evil-tree-edit--get-sig-parent (evil-tree-edit-current-node)))))
(-> node-type
Expand Down Expand Up @@ -342,12 +343,19 @@ See `tree-edit-insert-sibling'."
(evil-tree-edit-insert-sibling type :before))

(defun evil-tree-edit-insert-child (type-or-text)
"Insert a node of the given TYPE-OR-TEXT inside of the current node."
"Insert a node of the given TYPE-OR-TEXT inside of the current node at the beginning."
(interactive)
(evil-tree-edit-ensure-current-node)
(tree-edit-insert-child type-or-text (evil-tree-edit-current-node))
(evil-tree-edit-goto-child))

(defun evil-tree-edit-insert-child-last (type-or-text)
"Insert a node of the given TYPE-OR-TEXT inside of the current node at the end."
(interactive)
(evil-tree-edit-ensure-current-node)
(tree-edit-insert-child type-or-text (evil-tree-edit-current-node) -1)
(evil-tree-edit--goto-node (treesit-node-child (evil-tree-edit-current-node) -1 :named)))

(defun evil-tree-edit-slurp ()
"Transform current node's next sibling into it's leftmost child, if possible."
(interactive)
Expand All @@ -366,15 +374,15 @@ See `tree-edit-insert-sibling'."
Placeholder is defined by `tree-edit-placeholder-node-type'."
(interactive)
(evil-tree-edit-ensure-current-node)
(unless tree-edit-placeholder-node-type
(unless (tree-edit-placeholder-node-type)
(user-error "`tree-edit-placeholder-node-type' not set!"))
(pcase (tree-edit-query
(format "((%s) (#equal @node %s))"
(tree-edit--format-query-string
(cons tree-edit-placeholder-node-type
(tree-edit-all-aliases-for-type tree-edit-placeholder-node-type)))
(cons (tree-edit-placeholder-node-type)
(tree-edit-all-aliases-for-type (tree-edit-placeholder-node-type))))
;; XXX: Assuming the placeholder type is a singleton list containing a string
(car (alist-get tree-edit-placeholder-node-type tree-edit-syntax-snippets)))
(car (alist-get (tree-edit-placeholder-node-type) (tree-edit-syntax-snippets))))
(evil-tree-edit-current-node)
:want-text t)
(`(,first . ,_) (evil-tree-edit--goto-node first))
Expand Down Expand Up @@ -408,7 +416,7 @@ Placeholder is defined by `tree-edit-placeholder-node-type'."
(plist-get it :type)
`(,(plist-get it :type))))
(plist-get it :key))
tree-edit-nodes)))))
(tree-edit-nodes))))))

(defun evil-tree-edit-preview-node ()
"Preview the different variations of the current node."
Expand Down Expand Up @@ -507,9 +515,9 @@ This is so that the current node will be properly highlighted in explorer mode."
(let ((node (treesit-node-descendant-for-range
(treesit-buffer-root-node) (point) (point))))
(evil-tree-edit-set-current-node
(if (tree-edit--boring-nodep node)
(tree-edit--apply-until-interesting #'treesit-node-parent node)
node)))
(if (tree-edit--boring-nodep node)
(tree-edit--apply-until-interesting #'treesit-node-parent node)
node)))
(overlay-put evil-tree-edit--node-overlay 'face 'region)
(evil-tree-edit--update-overlay))

Expand Down Expand Up @@ -582,104 +590,101 @@ This is so that the current node will be properly highlighted in explorer mode."
"Define a key command in KEYMAP prefixed by KEY calling FUNC.

FUNC must take one argument, a symbol of the node type."
(dolist (node (append tree-edit-nodes tree-edit-query-nodes))
(dolist (node (append (tree-edit-nodes) (tree-edit-query-nodes)))
(define-key
keymap
(string-join (list key (plist-get node :key)))
(cons
;; emacs-which-key integration
(cond ((plist-get node :name) (plist-get node :name))
((listp (plist-get node :type)) (s-join "/" (--map (s-replace "_" " " (symbol-name it)) (plist-get node :type))))
(t (s-replace "_" " " (symbol-name (plist-get node :type)))))
`(lambda ()
(interactive)
(,func ',(plist-get node :type)))))))
keymap
(string-join (list key (plist-get node :key)))
(cons
;; emacs-which-key integration
(cond ((plist-get node :name) (plist-get node :name))
((listp (plist-get node :type)) (s-join "/" (--map (s-replace "_" " " (symbol-name it)) (plist-get node :type))))
(t (s-replace "_" " " (symbol-name (plist-get node :type)))))
`(lambda ()
(interactive)
(,func ',(plist-get node :type)))))))

(defun define-evil-tree-edit-verb (keymap key func &optional wrap)
"Define a key command in KEYMAP prefixed by KEY calling FUNC.

FUNC must take one argument, a symbol of the node type.
If WRAP is t, include :wrap-override."
(dolist (node tree-edit-nodes)
(dolist (node (tree-edit-nodes))
(define-key
keymap
(string-join (list key (plist-get node :key)))
(cons
;; emacs-which-key integration
(cond ((plist-get node :name) (plist-get node :name))
((listp (plist-get node :type)) (s-join "/" (--map (s-replace "_" " " (symbol-name it)) (plist-get node :type))))
(t (s-replace "_" " " (symbol-name (plist-get node :type)))))
`(lambda ()
(interactive)
(let ((tree-edit-syntax-snippets
(append ,(plist-get node :node-override)
,(if wrap (plist-get node :wrap-override))
tree-edit-syntax-snippets)))
(,func ',(plist-get node :type)))))))
keymap
(string-join (list key (plist-get node :key)))
(cons
;; emacs-which-key integration
(cond ((plist-get node :name) (plist-get node :name))
((listp (plist-get node :type)) (s-join "/" (--map (s-replace "_" " " (symbol-name it)) (plist-get node :type))))
(t (s-replace "_" " " (symbol-name (plist-get node :type)))))
`(lambda ()
(interactive)
(let ((tree-edit-syntax-snippets
(append ,(plist-get node :node-override)
,(if wrap (plist-get node :wrap-override))
tree-edit-syntax-snippets)))
(,func ',(plist-get node :type)))))))
;; Can this be integrated into the loop?
(define-key
keymap
(string-join (list key "p"))
(cons
"yank"
`(lambda ()
(interactive)
(,func (car kill-ring)))))
keymap
(string-join (list key "p"))
(cons
"yank"
`(lambda ()
(interactive)
(,func (car kill-ring)))))
(define-key
keymap
(string-join (list key "P"))
(cons
"yank-pop"
`(lambda ()
(interactive)
(,func (evil-tree-edit--read-from-kill-ring "Kill-ring: "))))))

(defun evil-tree-edit-set-state-bindings (mode)
keymap
(string-join (list key "P"))
(cons
"yank-pop"
`(lambda ()
(interactive)
(,func (evil-tree-edit--read-from-kill-ring "Kill-ring: "))))))

(defun evil-tree-edit-set-state-bindings (parser)
"Set keybindings for MODE in `evil-tree-state'.

Should only be used in the context of mode-local bindings, as
each language will have it's own set of nouns."
(with-mode-local-symbol mode
(let ((mode-local-keymap (make-composed-keymap (make-sparse-keymap) evil-suppress-map)))
(define-evil-tree-edit-verb mode-local-keymap "i" #'evil-tree-edit-insert-sibling-before)
(define-evil-tree-edit-verb mode-local-keymap "a" #'evil-tree-edit-insert-sibling)
(define-evil-tree-edit-verb mode-local-keymap "I" #'evil-tree-edit-insert-child)
(define-evil-tree-edit-verb mode-local-keymap "e" #'evil-tree-edit-exchange)
(define-evil-tree-edit-verb mode-local-keymap "w" #'evil-tree-edit-wrap-node t)
(define-evil-tree-edit-avy-jump mode-local-keymap "s" #'evil-tree-edit-avy-jump)
(define-evil-tree-edit-avy-jump mode-local-keymap "q" #'evil-tree-edit-sig-avy-jump)
(define-evil-tree-edit-avy-jump mode-local-keymap "o" #'evil-tree-edit-out)
(define-key mode-local-keymap [escape] 'evil-normal-state)
(define-key mode-local-keymap ">" #'evil-tree-edit-slurp)
(define-key mode-local-keymap "<" #'evil-tree-edit-barf)
(define-key mode-local-keymap "j" #'evil-tree-edit-goto-next-sibling)
(define-key mode-local-keymap "k" #'evil-tree-edit-goto-prev-sibling)
(define-key mode-local-keymap "h" #'evil-tree-edit-goto-parent)
(define-key mode-local-keymap "f" #'evil-tree-edit-goto-child)
(define-key mode-local-keymap "b" #'evil-tree-edit-back)
(define-key mode-local-keymap "x" #'evil-tree-edit-append-sibling-placeholder-and-change)
(define-key mode-local-keymap "X" #'evil-tree-edit-insert-child-placeholder-and-change)
(define-key mode-local-keymap "n" #'evil-tree-edit-goto-next-placeholder)
(define-key mode-local-keymap "N" #'evil-tree-edit-change-next-placeholder)
(define-key mode-local-keymap "c" #'evil-tree-edit-change)
(define-key mode-local-keymap "d" #'evil-tree-edit-delete)
(define-key mode-local-keymap "m" #'evil-tree-edit-move)
(define-key mode-local-keymap "r" #'evil-tree-edit-raise)
(define-key mode-local-keymap "y" #'evil-tree-edit-copy)
(define-key mode-local-keymap "p" #'evil-tree-edit-yank)
(define-key mode-local-keymap "P" #'evil-tree-edit-yank-pop)
(define-key mode-local-keymap "C" #'evil-tree-edit-clone)
(define-key mode-local-keymap "u" #'evil-tree-edit-undo)
(define-key mode-local-keymap "A" #'evil-tree-edit-goto-sig-parent)
(define-key mode-local-keymap "?" #'evil-tree-edit-node-info)
(define-key mode-local-keymap "v" #'evil-tree-edit-select-in-visual-state)
(define-key mode-local-keymap "V" #'evil-tree-edit-toggle-tree-view)
(define-key mode-local-keymap "zz" #'evil-scroll-line-to-center)
;; `setq-mode-local' macroexpanded, since it doesn't accept symbols
(mode-local-bind `((evil-tree-state-map . ,mode-local-keymap)) '(mode-variable-flag t) mode)
(mode-local-map-mode-buffers
(lambda () (set (make-local-variable 'evil-tree-state-map) mode-local-keymap))
mode))))
(let ((mode-local-keymap (make-composed-keymap (make-sparse-keymap) evil-suppress-map)))
(define-evil-tree-edit-verb mode-local-keymap "i" #'evil-tree-edit-insert-sibling-before)
(define-evil-tree-edit-verb mode-local-keymap "a" #'evil-tree-edit-insert-sibling)
(define-evil-tree-edit-verb mode-local-keymap "I" #'evil-tree-edit-insert-child)
(define-evil-tree-edit-verb mode-local-keymap "A" #'evil-tree-edit-insert-child-last)
(define-evil-tree-edit-verb mode-local-keymap "e" #'evil-tree-edit-exchange)
(define-evil-tree-edit-verb mode-local-keymap "w" #'evil-tree-edit-wrap-node t)
(define-evil-tree-edit-avy-jump mode-local-keymap "s" #'evil-tree-edit-avy-jump)
(define-evil-tree-edit-avy-jump mode-local-keymap "q" #'evil-tree-edit-sig-avy-jump)
(define-evil-tree-edit-avy-jump mode-local-keymap "o" #'evil-tree-edit-out)
(define-key mode-local-keymap [escape] 'evil-normal-state)
(define-key mode-local-keymap ">" #'evil-tree-edit-slurp)
(define-key mode-local-keymap "<" #'evil-tree-edit-barf)
(define-key mode-local-keymap "j" #'evil-tree-edit-goto-next-sibling)
(define-key mode-local-keymap "k" #'evil-tree-edit-goto-prev-sibling)
(define-key mode-local-keymap "h" #'evil-tree-edit-goto-parent)
(define-key mode-local-keymap "f" #'evil-tree-edit-goto-child)
(define-key mode-local-keymap "b" #'evil-tree-edit-back)
(define-key mode-local-keymap "x" #'evil-tree-edit-append-sibling-placeholder-and-change)
(define-key mode-local-keymap "X" #'evil-tree-edit-insert-child-placeholder-and-change)
(define-key mode-local-keymap "n" #'evil-tree-edit-goto-next-placeholder)
(define-key mode-local-keymap "N" #'evil-tree-edit-change-next-placeholder)
(define-key mode-local-keymap "c" #'evil-tree-edit-change)
(define-key mode-local-keymap "d" #'evil-tree-edit-delete)
(define-key mode-local-keymap "m" #'evil-tree-edit-move)
(define-key mode-local-keymap "r" #'evil-tree-edit-raise)
(define-key mode-local-keymap "y" #'evil-tree-edit-copy)
(define-key mode-local-keymap "p" #'evil-tree-edit-yank)
(define-key mode-local-keymap "P" #'evil-tree-edit-yank-pop)
(define-key mode-local-keymap "C" #'evil-tree-edit-clone)
(define-key mode-local-keymap "u" #'evil-tree-edit-undo)
(define-key mode-local-keymap "A" #'evil-tree-edit-goto-sig-parent)
(define-key mode-local-keymap "?" #'evil-tree-edit-node-info)
(define-key mode-local-keymap "v" #'evil-tree-edit-select-in-visual-state)
(define-key mode-local-keymap "V" #'evil-tree-edit-toggle-tree-view)
(define-key mode-local-keymap "zz" #'evil-scroll-line-to-center)
;; TODO: This could probably be better
(setq-local evil-tree-state-map mode-local-keymap)))

(unless evil-tree-edit-disable-nontree-bindings
(evil-define-key 'normal evil-tree-edit-mode-map "Q" #'evil-tree-state)
Expand Down
2 changes: 1 addition & 1 deletion tests/setup.el
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ executable programs, such as the C/C++ compiler and linker."
(funcall mode)

(treesit-parser-create
(or (alist-get mode tree-edit--test-major-mode-mapping)
(or (alist-get mode tree-edit-language-alist)
(user-error "[test harness] no grammar specified for %s" major-mode))
temp-buffer)

Expand Down
9 changes: 9 additions & 0 deletions tests/test-elisp.el
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
(require 'evil-tree-edit)
(ignore-errors (load-file "setup.el"))

(describe "elisp regressions"
(it "properly spaces the cons ."
;; Fixed in commit 0393dc6
(expect (with-tree-test-buffer #'emacs-lisp-mode "'([foo] . bar)"
(evil-tree-edit-exchange 'symbol))
:to-have-buffer-contents"'([TREE] . bar)")))
22 changes: 11 additions & 11 deletions tests/test-java.el
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@
(with-base-test-buffer #'java-mode ""
(let ((evil-tree-state-map (make-sparse-keymap))
(tree-edit-nodes
'((:type if_statement
:key "i"))))
'((java (:type if_statement
:key "i")))))
(define-evil-tree-edit-verb evil-tree-state-map "t" #'dummy-verb)
(evil-tree-state)
(expect (key-binding "ti"))
Expand All @@ -44,7 +44,7 @@
(it "loads grammar"
(with-base-test-buffer #'java-mode "" (expect tree-edit-grammar)))
(it "errors and disables tree-edit-mode on unknown mode"
(expect (with-base-test-buffer #'emacs-lisp-mode "") :to-throw 'error))
(expect (with-base-test-buffer #'fundamental-mode "") :to-throw 'error))

;; TODO
(xit "uses node overrides"))
Expand Down Expand Up @@ -445,14 +445,14 @@ class Main {[void bar() {}]
break;[break;]
}")
;; (expect (with-tree-test-buffer #'java-mode "
;; class Main {[public] void main() {}
;; }"
;; ;; FIXME: Test selects anonymous keyword 'public', instead of 'modifiers
;; (evil-tree-edit-goto-parent)
;; (evil-tree-edit-delete))
;; :to-have-buffer-contents "
;; class Main {[void] main() {}
;; }")
;; class Main {[public] void main() {}
;; }"
;; ;; FIXME: Test selects anonymous keyword 'public', instead of 'modifiers
;; (evil-tree-edit-goto-parent)
;; (evil-tree-edit-delete))
;; :to-have-buffer-contents "
;; class Main {[void] main() {}
;; }")
(expect (with-tree-test-buffer #'java-mode "{foo([x],y);}"
(evil-tree-edit-delete))
:to-have-buffer-contents "{foo([y]);}")
Expand Down
1 change: 1 addition & 0 deletions tree-edit-build.el
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,7 @@ ACCEPT-ALL, if non-nil, installs all grammars without confirmation."
(`(,lang . ,url)
'((python "https://github.com/tree-edit/tree-sitter-python")
(c "https://github.com/tree-edit/tree-sitter-c")
(elisp "https://github.com/tree-edit/tree-sitter-elisp")
(java "https://github.com/tree-edit/tree-sitter-java")))
(when
;; TODO: Some way to detect if the grammar is out of date
Expand Down
Loading