From 62a96c4065f49aa827a938c1b1638e3095eec268 Mon Sep 17 00:00:00 2001 From: Jim Porter Date: Sun, 8 Jan 2023 13:50:50 -0800 Subject: [PATCH 3/3] Use the 'field' property to navigate through Eshell prompts * lisp/eshell/esh-mode.el (eshell-skip-prompt-function): Make obsolete. * lisp/eshell/em-prompt.el (eshell-prompt-regexp): Update docstring. (eshell-prompt-initialize): Don't set 'eshell-skip-prompt-function'. (eshell-next-prompt): Search for the 'field' property set to 'prompt' to find the next prompt. (eshell-previous-prompt): Move 'forward-line' call into 'eshell-next-prompt'. (eshell-skip-prompt): Make obsolete. * test/lisp/eshell/em-prompt-tests.el (em-prompt-test/next-previous-prompt): New test. --- lisp/eshell/em-prompt.el | 47 +++++++++++++++-------------- lisp/eshell/esh-mode.el | 2 ++ test/lisp/eshell/em-prompt-tests.el | 18 +++++++++++ 3 files changed, 44 insertions(+), 23 deletions(-) diff --git a/lisp/eshell/em-prompt.el b/lisp/eshell/em-prompt.el index 9fad36a3d5e..8e8dc21d6ab 100644 --- a/lisp/eshell/em-prompt.el +++ b/lisp/eshell/em-prompt.el @@ -29,6 +29,8 @@ (require 'esh-mode) (eval-when-compile (require 'eshell)) +(require 'text-property-search) + ;;;###autoload (progn (defgroup eshell-prompt nil @@ -58,11 +60,12 @@ eshell-prompt-function :group 'eshell-prompt) (defcustom eshell-prompt-regexp "^[^#$\n]* [#$] " - "A regexp which fully matches your eshell prompt. -This setting is important, since it affects how eshell will interpret -the lines that are passed to it. -If this variable is changed, all Eshell buffers must be exited and -re-entered for it to take effect." + "A regexp which fully matches your Eshell prompt. +This is useful for navigating by paragraph using \ +\\[forward-paragraph] and \\[backward-paragraph]. + +If this variable is changed, all Eshell buffers must be exited +and re-entered for it to take effect." :type 'regexp :group 'eshell-prompt) @@ -123,7 +126,6 @@ eshell-prompt-initialize (if eshell-prompt-regexp (setq-local paragraph-start eshell-prompt-regexp)) - (setq-local eshell-skip-prompt-function #'eshell-skip-prompt) (eshell-prompt-mode))) (defun eshell-emit-prompt () @@ -174,32 +176,31 @@ eshell-forward-matching-input (eshell-backward-matching-input regexp (- arg))) (defun eshell-next-prompt (n) - "Move to end of Nth next prompt in the buffer. -See `eshell-prompt-regexp'." + "Move to end of Nth next prompt in the buffer." (interactive "p") - (if eshell-highlight-prompt - (progn - (while (< n 0) - (while (and (re-search-backward eshell-prompt-regexp nil t) - (not (get-text-property (match-beginning 0) 'read-only)))) - (setq n (1+ n))) - (while (> n 0) - (while (and (re-search-forward eshell-prompt-regexp nil t) - (not (get-text-property (match-beginning 0) 'read-only)))) - (setq n (1- n)))) - (re-search-forward eshell-prompt-regexp nil t n)) - (eshell-skip-prompt)) + (if (natnump n) + (while (and (> n 0) + (text-property-search-forward 'field 'prompt t)) + (setq n (1- n))) + (let (match this-match) + (forward-line 0) ; Don't count prompt on current line. + (while (and (< n 0) + (setq this-match (text-property-search-backward + 'field 'prompt t))) + (setq match this-match + n (1+ n))) + (when match + (goto-char (prop-match-end match)))))) (defun eshell-previous-prompt (n) - "Move to end of Nth previous prompt in the buffer. -See `eshell-prompt-regexp'." + "Move to end of Nth previous prompt in the buffer." (interactive "p") - (forward-line 0) ; Don't count prompt on current line. (eshell-next-prompt (- n))) (defun eshell-skip-prompt () "Skip past the text matching regexp `eshell-prompt-regexp'. If this takes us past the end of the current line, don't skip at all." + (declare (obsolete nil "29.1")) (let ((eol (line-end-position))) (if (and (looking-at eshell-prompt-regexp) (<= (match-end 0) eol)) diff --git a/lisp/eshell/esh-mode.el b/lisp/eshell/esh-mode.el index 90e003d188b..50a87e9bb9b 100644 --- a/lisp/eshell/esh-mode.el +++ b/lisp/eshell/esh-mode.el @@ -176,6 +176,8 @@ eshell-skip-prompt-function "A function called from beginning of line to skip the prompt." :type '(choice (const nil) function)) +(make-obsolete-variable 'eshell-skip-prompt-function nil "29.1") + (defcustom eshell-status-in-mode-line t "If non-nil, let the user know a command is running in the mode line." :type 'boolean) diff --git a/test/lisp/eshell/em-prompt-tests.el b/test/lisp/eshell/em-prompt-tests.el index b67c74e86d0..05cb92dada9 100644 --- a/test/lisp/eshell/em-prompt-tests.el +++ b/test/lisp/eshell/em-prompt-tests.el @@ -78,4 +78,22 @@ em-prompt-test/field-properties/no-highlight (propertize "hello\n" 'rear-nonsticky '(field) 'field 'command-output))))))) +(ert-deftest em-prompt-test/next-previous-prompt () + "Check that navigating forward/backward through old prompts works correctly." + (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")))) + ;;; em-prompt-tests.el ends here -- 2.25.1