(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."
;;; 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
'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
"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