]> git.eshelyaron.com Git - emacs.git/commitdiff
Improve implementations of some Eshell output filter functions
authorJim Porter <jporterbugs@gmail.com>
Tue, 4 Jun 2024 05:06:49 +0000 (22:06 -0700)
committerEshel Yaron <me@eshelyaron.com>
Sun, 9 Jun 2024 05:31:51 +0000 (07:31 +0200)
* lisp/eshell/esh-mode.el (eshell-postoutput-scroll-to-bottom): Use
'get-buffer-window-list' for simplicity.
(eshell-handle-control-codes): Use 're-search-forward'; this way is much
faster.

* test/lisp/eshell/esh-mode-tests.el: New file.

(cherry picked from commit 15f515c7a37f29117ff123821265a760ff0d040d)

lisp/eshell/esh-mode.el
test/lisp/eshell/esh-mode-tests.el [new file with mode: 0644]

index e6f3cb5f6ad01b3263083c9c1b6e069c2185ece2..ec1a07b7e2f5ee95580c99eca4db8effb1b07e10 100644 (file)
@@ -765,30 +765,25 @@ This function should be in the list `eshell-output-filter-functions'."
         (current (current-buffer))
         (scroll eshell-scroll-to-bottom-on-output))
     (unwind-protect
-       (walk-windows
-         (lambda (window)
-           (if (eq (window-buffer window) current)
-               (progn
-                 (select-window window)
-                 (if (and (< (point) eshell-last-output-end)
-                          (or (eq scroll t) (eq scroll 'all)
-                              ;; Maybe user wants point to jump to end.
-                              (and (eq scroll 'this)
-                                   (eq selected window))
-                              (and (eq scroll 'others)
-                                   (not (eq selected window)))
-                              ;; If point was at the end, keep it at end.
-                              (>= (point) eshell-last-output-start)))
-                     (goto-char eshell-last-output-end))
-                 ;; Optionally scroll so that the text
-                 ;; ends at the bottom of the window.
-                 (if (and eshell-scroll-show-maximum-output
-                          (>= (point) eshell-last-output-end))
-                     (save-excursion
-                       (goto-char (point-max))
-                       (recenter -1)))
-                 (select-window selected))))
-        nil t)
+        (dolist (window (get-buffer-window-list current nil t))
+          (with-selected-window window
+            (when (and (< (point) eshell-last-output-end)
+                       (or (eq scroll t) (eq scroll 'all)
+                           ;; Maybe user wants point to jump to end.
+                           (and (eq scroll 'this)
+                                (eq selected window))
+                           (and (eq scroll 'others)
+                                (not (eq selected window)))
+                           ;; If point was at the end, keep it at end.
+                           (>= (point) eshell-last-output-start)))
+              (goto-char eshell-last-output-end))
+            ;; Optionally scroll so that the text ends at the bottom of
+            ;; the window.
+            (when (and eshell-scroll-show-maximum-output
+                       (>= (point) eshell-last-output-end))
+              (save-excursion
+                (goto-char (point-max))
+                (recenter -1)))))
       (set-buffer current))))
 
 (defun eshell-beginning-of-input ()
@@ -977,27 +972,24 @@ This function could be in the list `eshell-output-filter-functions'."
     (goto-char eshell-last-output-block-begin)
     (unless (eolp)
       (beginning-of-line))
-    (while (< (point) eshell-last-output-end)
-      (let ((char (char-after)))
+    (while (re-search-forward (rx (any ?\r ?\a ?\C-h))
+                              eshell-last-output-end t)
+      (let ((char (char-before)))
         (cond
          ((eq char ?\r)
-          (if (< (1+ (point)) eshell-last-output-end)
-              (if (memq (char-after (1+ (point)))
-                        '(?\n ?\r))
-                  (delete-char 1)
-                (let ((end (1+ (point))))
+          (if (< (point) eshell-last-output-end)
+              (if (memq (char-after (point)) '(?\n ?\r))
+                  (delete-char -1)
+                (let ((end (point)))
                   (beginning-of-line)
                   (delete-region (point) end)))
-            (add-text-properties (point) (1+ (point))
-                                 '(invisible t))
-            (forward-char)))
+            (add-text-properties (1- (point)) (point)
+                                 '(invisible t))))
          ((eq char ?\a)
-          (delete-char 1)
+          (delete-char -1)
           (beep))
          ((eq char ?\C-h)
-          (delete-region (1- (point)) (1+ (point))))
-         (t
-          (forward-char)))))))
+          (delete-region (- (point) 2) (point))))))))
 
 (custom-add-option 'eshell-output-filter-functions
                   'eshell-handle-control-codes)
diff --git a/test/lisp/eshell/esh-mode-tests.el b/test/lisp/eshell/esh-mode-tests.el
new file mode 100644 (file)
index 0000000..306e11c
--- /dev/null
@@ -0,0 +1,62 @@
+;;; esh-mode-tests.el --- esh-mode test suite  -*- lexical-binding:t -*-
+
+;; Copyright (C) 2022-2024 Free Software Foundation, Inc.
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Tests for Eshell's command invocation.
+
+;;; Code:
+
+(require 'ert)
+(require 'esh-mode)
+(require 'eshell)
+
+(require 'eshell-tests-helpers
+         (expand-file-name "eshell-tests-helpers"
+                           (file-name-directory (or load-file-name
+                                                    default-directory))))
+
+;;; Tests:
+
+(ert-deftest esh-mode-test/handle-control-codes/carriage-return ()
+  "Test that Eshell handles carriage returns properly."
+  (with-temp-eshell
+    (eshell-match-command-output "(format \"hello\r\ngoodbye\")"
+                                 "\\`hello\ngoodbye\n")
+    (eshell-match-command-output "(format \"hello\rgoodbye\")"
+                                 "\\`goodbye\n")
+    (eshell-match-command-output "(format \"hello\r\")"
+                                 "\\`hello")))
+
+(ert-deftest esh-mode-test/handle-control-codes/bell ()
+  "Test that Eshell handles bells properly."
+  (cl-letf* ((beep-called nil)
+             ((symbol-function 'beep) (lambda () (setq beep-called t))))
+    (with-temp-eshell
+      (eshell-match-command-output "(format \"hello\athere\")"
+                                   "\\`hellothere\n")
+      (should beep-called))))
+
+(ert-deftest esh-mode-test/handle-control-codes/backspace ()
+  "Test that Eshell handles backspaces properly."
+  (with-temp-eshell
+    (eshell-match-command-output (format "(format \"hello%c%cp\")" ?\C-h ?\C-h)
+                                 "\\`help\n")))
+
+;; esh-mode-tests.el ends here