emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

feature/tree-sitter 2b4d46f99b 1/7: Mimic existing python-mode beg/end-o


From: Yuan Fu
Subject: feature/tree-sitter 2b4d46f99b 1/7: Mimic existing python-mode beg/end-of-defun behavior better
Date: Wed, 9 Nov 2022 18:52:04 -0500 (EST)

branch: feature/tree-sitter
commit 2b4d46f99be3735823666c2a6d9f058cedeb031c
Author: Yuan Fu <casouri@gmail.com>
Commit: Yuan Fu <casouri@gmail.com>

    Mimic existing python-mode beg/end-of-defun behavior better
    
    * lisp/progmodes/python.el (python-treesit-beginning-of-defun)
    (python-treesit-end-of-defun): New functions.
    * lisp/progmodes/python.el (python-mode): Use custom beg/end-of-defun
    functions.
---
 lisp/progmodes/python.el | 56 ++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 52 insertions(+), 4 deletions(-)

diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el
index 8db96b117f..61f29dd005 100644
--- a/lisp/progmodes/python.el
+++ b/lisp/progmodes/python.el
@@ -2354,6 +2354,55 @@ position, else returns nil."
       (ignore (goto-char point)))))
 
 
+;;; Tree-sitter navigation
+
+(defun python-treesit-beginning-of-defun (&optional arg)
+  "Tree-sitter `beginning-of-defun' function.
+ARG is the same as in `beginning-of-defun'."
+  (let ((arg (or arg 1))
+        (node (treesit-node-at (point)))
+        (function-or-class (rx (or "function" "class") "_definition")))
+    (if (> arg 0)
+        ;; Go backward.
+        (while (and (> arg 0)
+                    (setq node (treesit-search-forward-goto
+                                node function-or-class t t)))
+          ;; Here we deviate from `treesit-beginning-of-defun': if
+          ;; NODE is function_definition, find the top-level
+          ;; function_definition, if NODE is class_definition, find
+          ;; the top-level class_definition, don't mix the two like
+          ;; `treesit-beginning-of-defun' would.
+          (setq node (or (treesit-node-top-level node)
+                         node))
+          (setq arg (1- arg)))
+      ;; Go forward.
+      (while (and (< arg 0)
+                  (setq node (treesit-search-forward-goto
+                              node function-or-class)))
+        (setq node (or (treesit-node-top-level node)
+                       node))
+        (setq arg (1+ arg))))
+    (when node
+      (goto-char (treesit-node-start node))
+      t)))
+
+(defun python-treesit-end-of-defun ()
+  "Tree-sitter `end-of-defun' function."
+  ;; Why not simply get the largest node at point: when point is at
+  ;; (point-min), that gives us the root node.
+  (let* ((node (treesit-node-at (point)))
+         (top-func (treesit-node-top-level
+                    node
+                    "function_definition"))
+         (top-class (treesit-node-top-level
+                     node
+                     "class_definition")))
+    ;; Prefer function_definition over class_definition: when we are
+    ;; in a function_definition inside a class_definition, jump to the
+    ;; end of function_definition.
+    (goto-char (or (treesit-node-end (or top-func top-class)) (point)))))
+
+
 ;;; Shell integration
 
 (defcustom python-shell-buffer-name "Python"
@@ -6508,10 +6557,9 @@ Add import for undefined name `%s' (empty to skip): "
     (setq-local treesit-font-lock-settings python--treesit-settings)
     (setq-local imenu-create-index-function
                 #'python-imenu-treesit-create-index)
-    (setq-local treesit-defun-type-regexp (rx bol
-                                              (or "function" "class")
-                                              "_definition"
-                                              eol))
+    (setq-local beginning-of-defun-function
+                #'python-treesit-beginning-of-defun)
+    (setq-local end-of-defun-function #'python-treesit-end-of-defun)
     (treesit-major-mode-setup))
    ;; Elisp.
    (t



reply via email to

[Prev in Thread] Current Thread [Next in Thread]