]> git.eshelyaron.com Git - emacs.git/commitdiff
Add cache to Python block navigation functions
authorkobarity <kobarity@gmail.com>
Mon, 21 Apr 2025 14:17:37 +0000 (23:17 +0900)
committerEshel Yaron <me@eshelyaron.com>
Sat, 26 Apr 2025 17:31:10 +0000 (19:31 +0200)
* lisp/progmodes/python.el (python-nav-cache)
(python-nav-cache-tick): New variables.
(python-nav-cache-get, python-nav-cache-set)
(python-nav-with-cache): New functions.
(python-nav-beginning-of-block, python-nav-end-of-block): New
wrapper functions.
(python-nav--beginning-of-block): Renamed from
'python-nav-beginning-of-block'.
(python-nav--end-of-block): Renamed from
'python-nav-end-of-block'.  (Bug#77620)

(cherry picked from commit 9ae82726d8ea4530f26f2baa16b705ba3cd71834)

lisp/progmodes/python.el

index 256a9e2838a20d2b31dce51baec38347588ec0f2..813bec2ad8a1bb71fc9f84aa8f50d79d535d8f21 100644 (file)
@@ -2380,9 +2380,54 @@ backward to previous statement."
     (python-nav-beginning-of-statement)
     (setq arg (1+ arg))))
 
+(defvar python-nav-cache nil
+  "Cache to hold the results of navigation functions.")
+
+(defvar python-nav-cache-tick 0
+  "`buffer-chars-modified-tick' when registering the navigation cache.")
+
+(defun python-nav-cache-get (kind)
+  "Get value from the navigation cache.
+If the current buffer is not modified, the navigation cache is searched
+using KIND and the current line number as a key."
+  (and (= (buffer-chars-modified-tick) python-nav-cache-tick)
+       (cdr (assoc (cons kind (line-number-at-pos nil t)) python-nav-cache))))
+
+(defun python-nav-cache-set (kind current target)
+  "Add a key-value pair to the navigation cache.
+Invalidate the navigation cache if the current buffer has been modified.
+Then add a key-value pair to the navigation cache.  The key consists of
+KIND and CURRENT line number, and the value is TARGET position."
+  (let ((tick (buffer-chars-modified-tick)))
+    (when (/= tick python-nav-cache-tick)
+      (setq-local python-nav-cache nil
+                  python-nav-cache-tick tick))
+    (push (cons (cons kind current) target) python-nav-cache)
+    target))
+
+(defun python-nav-with-cache (kind func)
+  "Cached version of the navigation FUNC.
+If a value is obtained from the navigation cache using KIND, it will
+navigate there and return the position.  Otherwise, use FUNC to navigate
+and cache the result."
+  (let ((target (python-nav-cache-get kind)))
+    (if target
+        (progn
+          (goto-char target)
+          (point-marker))
+      (let ((current (line-number-at-pos nil t)))
+        (python-nav-cache-set kind current (funcall func))))))
+
 (defun python-nav-beginning-of-block ()
   "Move to start of current block."
   (interactive "^")
+  (python-nav-with-cache
+   'beginning-of-block #'python-nav--beginning-of-block))
+
+(defun python-nav--beginning-of-block ()
+  "Move to start of current block.
+This is an internal implementation of `python-nav-beginning-of-block'
+without the navigation cache."
   (let ((starting-pos (point)))
     ;; Go to first line beginning a statement
     (while (and (not (bobp))
@@ -2407,6 +2452,13 @@ backward to previous statement."
 (defun python-nav-end-of-block ()
   "Move to end of current block."
   (interactive "^")
+  (python-nav-with-cache
+   'end-of-block #'python-nav--end-of-block))
+
+(defun python-nav--end-of-block ()
+  "Move to end of current block.
+This is an internal implementation of `python-nav-end-of-block' without
+the navigation cache."
   (when (python-nav-beginning-of-block)
     (let ((block-indentation (current-indentation)))
       (python-nav-end-of-statement)