]> git.eshelyaron.com Git - emacs.git/commitdiff
Ensure navigating by paragraphs in Eshell stops at prompts and paragraphs
authorJim Porter <jporterbugs@gmail.com>
Fri, 14 Jun 2024 04:26:53 +0000 (21:26 -0700)
committerEshel Yaron <me@eshelyaron.com>
Fri, 21 Jun 2024 19:01:20 +0000 (21:01 +0200)
The previous implementation in 6ae2b74ed20 only stopped at prompts,
which isn't the right behavior (bug#61545).

* lisp/eshell/em-prompt.el (eshell-forward-paragraph)
(eshell-backward-paragraph): Reimplement to handle prompts and
paragraphs (the latter by calling the original 'forward-paragraph').

* test/lisp/eshell/em-prompt-tests.el
(em-prompt-test/next-previous-prompt/multiline): Rename.
(em-prompt-test/forward-backward-paragraph-1): New function.
(em-prompt-test/forward-backward-paragraph)
(em-prompt-test/forward-backward-paragraph/multiline): New tests.

(cherry picked from commit e22b072423a6764632328d4e0fecc06a6e7efe9b)

lisp/eshell/em-prompt.el
test/lisp/eshell/em-prompt-tests.el

index b6556d29544635361cbea9540a7b9e98ff022c8c..7de2bd4dc217c6c6b3c7832822372df1ce0b58de 100644 (file)
@@ -167,17 +167,39 @@ negative, find the Nth next match."
 
 (defun eshell-forward-paragraph (&optional n)
   "Move to the beginning of the Nth next prompt in the buffer.
-Like `forward-paragraph', but navigates using fields."
+Like `forward-paragraph', but also stops at the beginning of each prompt."
   (interactive "p")
-  (eshell-next-prompt n)
-  (goto-char (field-beginning (point) t)))
+  (unless n (setq n 1))
+  (let (;; We'll handle the "paragraph" starts ourselves.
+        (paragraph-start regexp-unmatchable)
+        (inhibit-field-text-motion t))
+    (cond
+     ((> n 0)
+      (while (and (> n 0) (< (point) (point-max)))
+        (let ((next-paragraph (save-excursion (forward-paragraph) (point)))
+              (next-prompt (save-excursion
+                             (if-let ((match (text-property-search-forward
+                                              'field 'prompt t t)))
+                                 (prop-match-beginning match)
+                               (point-max)))))
+          (goto-char (min next-paragraph next-prompt)))
+        (setq n (1- n))))
+     ((< n 0)
+      (while (and (< n 0) (> (point) (point-min)))
+        (let ((prev-paragraph (save-excursion (backward-paragraph) (point)))
+              (prev-prompt (save-excursion
+                             (if (text-property-search-backward
+                                  'field 'prompt t)
+                                 (point)
+                               (point-min)))))
+          (goto-char (max prev-paragraph prev-prompt)))
+        (setq n (1+ n)))))))
 
 (defun eshell-backward-paragraph (&optional n)
   "Move to the beginning of the Nth previous prompt in the buffer.
 Like `backward-paragraph', but navigates using fields."
   (interactive "p")
-  (eshell-previous-prompt n)
-  (goto-char (field-beginning (point) t)))
+  (eshell-forward-paragraph (- (or n 1))))
 
 (defun eshell-next-prompt (&optional n)
   "Move to end of Nth next prompt in the buffer."
index 964609e6410ef97ae0fa1d422ead4b87ec15c80e..fbadade061f67b32b6019bd99e926c37785c5579 100644 (file)
@@ -39,6 +39,9 @@
 
 ;;; Tests:
 
+\f
+;; Prompt output
+
 (ert-deftest em-prompt-test/field-properties ()
   "Check that field properties are properly set on Eshell output/prompts."
   (with-temp-eshell
@@ -104,6 +107,9 @@ This tests the case when `eshell-highlight-prompt' is nil."
                'front-sticky '(read-only field font-lock-face)
                'rear-nonsticky '(read-only field font-lock-face)))))))
 
+\f
+;; Prompt navigation
+
 (defun em-prompt-test/next-previous-prompt-1 ()
   "Helper for checking forward/backward navigation of old prompts."
   (with-temp-eshell
@@ -150,11 +156,52 @@ This tests the case when `eshell-highlight-prompt' is nil."
   "Check that navigating forward/backward through old prompts works correctly."
   (em-prompt-test/next-previous-prompt-1))
 
-(ert-deftest em-prompt-test/next-previous-prompt-multiline ()
+(ert-deftest em-prompt-test/next-previous-prompt/multiline ()
   "Check old prompt forward/backward navigation for multiline prompts."
   (em-prompt-test--with-multiline
    (em-prompt-test/next-previous-prompt-1)))
 
+(defun em-prompt-test/forward-backward-paragraph-1 ()
+  "Helper for checking forward/backward navigation by paragraphs."
+  (with-temp-eshell
+    (cl-flet ((at-prompt-for-command-p (command)
+                (and (equal (point) (field-beginning))
+                     (equal (get-text-property (point) 'field) 'prompt)
+                     (save-excursion
+                       (goto-char (field-end))
+                       (equal (field-string) command)))))
+      (eshell-insert-command "echo 'high five'")
+      (eshell-insert-command "echo 'up high\n\ndown low'")
+      (eshell-insert-command "echo 'too slow'")
+      (insert "echo goodby")            ; A partially-entered command.
+      (ert-info ("Go back to the last prompt")
+        (eshell-backward-paragraph)
+        (should (at-prompt-for-command-p "echo goodby")))
+      (ert-info ("Go back to the paragraph break")
+        (eshell-backward-paragraph 2)
+        (should (looking-at "\ndown low\n")))
+      (ert-info ("Go forward to the third prompt")
+        (eshell-forward-paragraph)
+        (should (at-prompt-for-command-p "echo 'too slow'\n")))
+      (ert-info ("Go backward to before the first prompt")
+        (eshell-backward-paragraph 5)
+        (should (looking-back "Welcome to the Emacs shell\n")))
+      (ert-info ("Go backward to the beginning of the buffer")
+        (eshell-backward-paragraph)
+        (should (bobp)))
+      (ert-info ("Go forward to the second prompt")
+        (eshell-forward-paragraph 3)
+        (should (at-prompt-for-command-p "echo 'up high\n\ndown low'\n"))))))
+
+(ert-deftest em-prompt-test/forward-backward-paragraph ()
+  "Check that navigating forward/backward through paragraphs works correctly."
+  (em-prompt-test/forward-backward-paragraph-1))
+
+(ert-deftest em-prompt-test/forward-backward-paragraph/multiline ()
+  "Check paragraph forward/backward navigation for multiline prompts."
+  (em-prompt-test--with-multiline
+   (em-prompt-test/forward-backward-paragraph-1)))
+
 (defun em-prompt-test/forward-backward-matching-input-1 ()
   "Helper for checking forward/backward navigation via regexps."
   (with-temp-eshell