From 5a430f90c1182ace27883a2a7ee808f3e5d722ce Mon Sep 17 00:00:00 2001 From: Jim Porter Date: Sat, 2 Sep 2023 14:44:33 -0700 Subject: [PATCH] Be more precise about navigating forward/backward through Eshell prompts * lisp/eshell/em-prompt.el (eshell-next-prompt): Make N optional. When navigating, first move to the end of the prompt. This makes the subsequent navigation more predictable. (eshell-previous-prompt): Mane N optional. * test/lisp/eshell/em-prompt-tests.el (em-prompt-test--with-multiline): Move to "Code" section. (em-prompt-test/next-previous-prompt-with): Rename to... (em-prompt-test/next-previous-prompt-1): ... this, and add additional test cases. Update callers. (em-prompt-test/forward-backward-matching-input-with): Rename to... (em-prompt-test/forward-backward-matching-input-1): ... this, and improve existing test cases. --- lisp/eshell/em-prompt.el | 21 +++++-- test/lisp/eshell/em-prompt-tests.el | 87 +++++++++++++++++++---------- 2 files changed, 72 insertions(+), 36 deletions(-) diff --git a/lisp/eshell/em-prompt.el b/lisp/eshell/em-prompt.el index 42f8f273b52..e334d3956e2 100644 --- a/lisp/eshell/em-prompt.el +++ b/lisp/eshell/em-prompt.el @@ -172,16 +172,27 @@ negative, find the Nth next match." (interactive (eshell-regexp-arg "Backward input matching (regexp): ")) (eshell-forward-matching-input regexp (- arg))) -(defun eshell-next-prompt (n) +(defun eshell-next-prompt (&optional n) "Move to end of Nth next prompt in the buffer." (interactive "p") + (unless n (setq n 1)) + ;; First, move point to our starting position: the end of the + ;; current prompt (aka the beginning of the input), if any. (The + ;; welcome message and output from commands don't count as having a + ;; current prompt.) + (pcase (get-text-property (point) 'field) + ('command-output) + ('prompt (goto-char (field-end))) + (_ (when-let ((match (text-property-search-backward 'field 'prompt t))) + (goto-char (prop-match-end match))))) + ;; Now, move forward/backward to our destination prompt. (if (natnump n) (while (and (> n 0) (text-property-search-forward 'field 'prompt t)) (setq n (1- n))) (let (match this-match) - ;; Don't count the current prompt. - (text-property-search-backward 'field 'prompt t) + ;; Go to the beginning of the current prompt. + (goto-char (field-beginning (point) t)) (while (and (< n 0) (setq this-match (text-property-search-backward 'field 'prompt t))) @@ -190,10 +201,10 @@ negative, find the Nth next match." (when match (goto-char (prop-match-end match)))))) -(defun eshell-previous-prompt (n) +(defun eshell-previous-prompt (&optional n) "Move to end of Nth previous prompt in the buffer." (interactive "p") - (eshell-next-prompt (- n))) + (eshell-next-prompt (- (or n 1)))) (defun eshell-skip-prompt () "Skip past the text matching regexp `eshell-prompt-regexp'. diff --git a/test/lisp/eshell/em-prompt-tests.el b/test/lisp/eshell/em-prompt-tests.el index 93bf9d84ab3..f6a63ac0db5 100644 --- a/test/lisp/eshell/em-prompt-tests.el +++ b/test/lisp/eshell/em-prompt-tests.el @@ -32,6 +32,11 @@ (file-name-directory (or load-file-name default-directory)))) +(defmacro em-prompt-test--with-multiline (&rest body) + "Execute BODY with a multiline Eshell prompt." + `(let ((eshell-prompt-function (lambda () "multiline prompt\n$ "))) + ,@body)) + ;;; Tests: (ert-deftest em-prompt-test/field-properties () @@ -80,39 +85,56 @@ This tests the case when `eshell-highlight-prompt' is nil." (apply #'propertize "hello\n" eshell-command-output-properties))))))) -(defmacro em-prompt-test--with-multiline (&rest body) - "Execute BODY with a multiline Eshell prompt." - `(let ((eshell-prompt-function (lambda () "multiline prompt\n$ "))) - ,@body)) - -(defun em-prompt-test/next-previous-prompt-with () +(defun em-prompt-test/next-previous-prompt-1 () "Helper for checking forward/backward navigation of old prompts." (with-temp-eshell (eshell-insert-command "echo one") (eshell-insert-command "echo two") (eshell-insert-command "echo three") (insert "echo fou") ; A partially-entered command. - ;; Go back one prompt. - (eshell-previous-prompt 1) - (should (equal (eshell-get-old-input) "echo three")) - ;; Go back two prompts, starting from the end of this line. - (end-of-line) - (eshell-previous-prompt 2) - (should (equal (eshell-get-old-input) "echo one")) - ;; Go forward three prompts. - (eshell-next-prompt 3) - (should (equal (eshell-get-old-input) "echo fou")))) + (ert-info ("Go back one prompt") + (eshell-previous-prompt) + (should (equal (point) (field-beginning))) + (should (equal (field-string) "echo three\n"))) + (ert-info ("Go back two prompts, starting from the end of the input") + (end-of-line) + (eshell-previous-prompt 2) + (should (equal (point) (field-beginning))) + (should (equal (field-string) "echo one\n"))) + (ert-info ("Go to the current prompt, starting from the end of the input") + (end-of-line) + (eshell-previous-prompt 0) + (should (equal (point) (field-beginning))) + (should (equal (field-string) "echo one\n"))) + (ert-info ("Go forward one prompt") + (eshell-next-prompt) + (should (equal (point) (field-beginning))) + (should (equal (field-string) "echo two\n"))) + (ert-info ("Go forward two prompts") + (eshell-next-prompt 2) + (should (equal (point) (field-beginning))) + (should (equal (field-string) "echo fou"))) + (ert-info ("Go back one prompt, starting from the beginning of the line") + (forward-line 0) + (eshell-previous-prompt 1) + (should (equal (point) (field-beginning))) + (should (equal (field-string) "echo three\n"))) + (ert-info ("Go back one prompt, starting from the previous prompt's output") + (forward-line -1) + (eshell-previous-prompt 1) + (should (equal (point) (field-beginning))) + (should (equal (field-string) "echo two\n"))))) (ert-deftest em-prompt-test/next-previous-prompt () "Check that navigating forward/backward through old prompts works correctly." - (em-prompt-test/next-previous-prompt-with)) + (em-prompt-test/next-previous-prompt-1)) (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-with))) + (em-prompt-test/next-previous-prompt-1))) -(defun em-prompt-test/forward-backward-matching-input-with () +(defun em-prompt-test/forward-backward-matching-input-1 () "Helper for checking forward/backward navigation via regexps." (with-temp-eshell (eshell-insert-command "echo one") @@ -120,24 +142,27 @@ This tests the case when `eshell-highlight-prompt' is nil." (eshell-insert-command "echo two") (eshell-insert-command "echo three") (insert "echo fou") ; A partially-entered command. - ;; Go back one prompt. - (eshell-backward-matching-input "echo" 1) - (should (equal (eshell-get-old-input) "echo three")) - ;; Go back two prompts, starting from the end of this line. - (end-of-line) - (eshell-backward-matching-input "echo" 2) - (should (equal (eshell-get-old-input) "echo one")) - ;; Go forward three prompts. - (eshell-forward-matching-input "echo" 3) - (should (equal (eshell-get-old-input) "echo fou")))) + (ert-info ("Go back one prompt") + (eshell-backward-matching-input "echo" 1) + (should (equal (point) (field-beginning))) + (should (equal (field-string) "echo three\n"))) + (ert-info ("Go back two prompts, starting from the end of this line") + (end-of-line) + (eshell-backward-matching-input "echo" 2) + (should (equal (point) (field-beginning))) + (should (equal (field-string) "echo one\n"))) + (ert-info ("Go forward three prompts") + (eshell-forward-matching-input "echo" 3) + (should (equal (point) (field-beginning))) + (should (equal (field-string) "echo fou"))))) (ert-deftest em-prompt-test/forward-backward-matching-input () "Check that navigating forward/backward via regexps works correctly." - (em-prompt-test/forward-backward-matching-input-with)) + (em-prompt-test/forward-backward-matching-input-1)) (ert-deftest em-prompt-test/forward-backward-matching-input-multiline () "Check forward/backward regexp navigation for multiline prompts." (em-prompt-test--with-multiline - (em-prompt-test/forward-backward-matching-input-with))) + (em-prompt-test/forward-backward-matching-input-1))) ;;; em-prompt-tests.el ends here -- 2.39.2