]> git.eshelyaron.com Git - emacs.git/commitdiff
Limit the amount of text we examine when looking for password prompts
authorJim Porter <jporterbugs@gmail.com>
Sat, 15 Jun 2024 18:03:33 +0000 (11:03 -0700)
committerEshel Yaron <me@eshelyaron.com>
Fri, 21 Jun 2024 19:01:14 +0000 (21:01 +0200)
Both Comint and Eshell do this, and it can significantly slow down
commands that write a lot of output (bug#71576).

* lisp/comint.el (comint-password-prompt-max-length): New variable...
(comint-watch-for-password-prompt): ... use it.  Additionally, use the
matched result for the Emacs-based password prompt.

* lisp/eshell/esh-mode.el (eshell-password-prompt-max-length): New
variable...
(eshell-watch-for-password-prompt): ... use it.

* etc/NEWS: Announce this change.

(cherry picked from commit 1a55e957ae57ec32ae960eabdb170b5b427392d4)

etc/NEWS
lisp/comint.el
lisp/eshell/esh-mode.el

index 9b7d8447d8712ca3f43a667b1a1138a0b3101c4e..504807261f73fff307d8df606f7df66273bf0385 100644 (file)
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -979,9 +979,16 @@ more information on this notation.
 ---
 *** Performance improvements for interactive output in Eshell.
 Interactive output in Eshell should now be significantly faster,
-especially for built-in commands that can print large amounts of output
-(e.g. "cat").  In addition, these commands can now update the display
-periodically to show their progress.
+especially for commands that can print large amounts of output
+(e.g. "cat").  For external commands, Eshell saves time by only looking
+for password prompts in the last 256 characters of each block of output.
+To restore the previous behavior when checking for password prompts, set
+'eshell-password-prompt-max-length' to 'most-positive-fixnum'.
+
+---
+*** Eshell built-in commands can now display progress.
+Eshell built-in commands like "cat" and "ls" now update the display
+periodically while running to show their progress.
 
 +++
 *** New special reference type '#<marker POSITION BUFFER>'.
@@ -1247,6 +1254,14 @@ environment variable 'HISTFILE'.
 
 In a 'shell' buffer, this user option is connection-local.
 
+---
+*** Performance improvements for interactive output.
+Interactive output in Shell mode now scans more selectively for password
+prompts by only examining the last 256 characters of each block of
+output, reducing the time spent when printing large amounts of output.
+To restore the old behavior, set 'comint-password-prompt-max-length' to
+'most-positive-fixnum'.
+
 ** Make mode
 
 *** The Makefile browser is now obsolete.
index 90f974c5def749777175a6d0d52a265e20a82e68..6cf72bd039feb54154e3d244020d02e8a6239c0d 100644 (file)
@@ -426,6 +426,11 @@ This is used by `comint-watch-for-password-prompt'."
   :type 'regexp
   :group 'comint)
 
+(defvar comint-password-prompt-max-length 256
+  "The maximum amount of text to examine when matching password prompts.
+This is used by `comint-watch-for-password-prompt' to reduce the amount
+of time spent searching for password prompts.")
+
 ;; Here are the per-interpreter hooks.
 (defvar comint-get-old-input (function comint-get-old-input-default)
   "Function that returns old text in Comint mode.
@@ -2563,23 +2568,26 @@ to detect the need to (prompt and) send a password.  Ignores any
 carriage returns (\\r) in STRING.
 
 This function could be in the list `comint-output-filter-functions'."
-  (when (let ((case-fold-search t))
-         (string-match comint-password-prompt-regexp
-                        (string-replace "\r" "" string)))
-    ;; Use `run-at-time' in order not to pause execution of the
-    ;; process filter with a minibuffer
-    (run-at-time
-     0 nil
-     (lambda (current-buf)
-       (with-current-buffer current-buf
-         (let ((comint--prompt-recursion-depth
-                (1+ comint--prompt-recursion-depth)))
-           (if (> comint--prompt-recursion-depth 10)
-               (message "Password prompt recursion too deep")
-             (when (get-buffer-process (current-buffer))
-               (comint-send-invisible
-                (string-trim string "[ \n\r\t\v\f\b\a]+" "\n+")))))))
-     (current-buffer))))
+  (let ((string (string-limit string comint-password-prompt-max-length t))
+        prompt)
+    (when (let ((case-fold-search t))
+            (string-match comint-password-prompt-regexp
+                          (string-replace "\r" "" string)))
+      (setq prompt (string-trim (match-string 0 string)
+                                "[ \n\r\t\v\f\b\a]+" "\n+"))
+      ;; Use `run-at-time' in order not to pause execution of the
+      ;; process filter with a minibuffer
+      (run-at-time
+       0 nil
+       (lambda (current-buf)
+         (with-current-buffer current-buf
+           (let ((comint--prompt-recursion-depth
+                  (1+ comint--prompt-recursion-depth)))
+             (if (> comint--prompt-recursion-depth 10)
+                 (message "Password prompt recursion too deep")
+               (when (get-buffer-process (current-buffer))
+                 (comint-send-invisible prompt))))))
+       (current-buffer)))))
 \f
 ;; Low-level process communication
 
index ec1a07b7e2f5ee95580c99eca4db8effb1b07e10..34ce82cfbc427d385b0445263cfaaf38fab705dc 100644 (file)
@@ -198,6 +198,11 @@ This is used by `eshell-watch-for-password-prompt'."
   :type 'directory
   :group 'eshell)
 
+(defvar eshell-password-prompt-max-length 256
+  "The maximum amount of text to examine when matching password prompts.
+This is used by `eshell-watch-for-password-prompt' to reduce the amount
+of time spent searching for password prompts.")
+
 (defvar eshell-first-time-p t
   "A variable which is non-nil the first time Eshell is loaded.")
 
@@ -949,19 +954,20 @@ buffer's process if STRING contains a password prompt defined by
 This function could be in the list `eshell-output-filter-functions'."
   (when (eshell-head-process)
     (save-excursion
-      (let ((case-fold-search t))
-       (goto-char eshell-last-output-block-begin)
-       (beginning-of-line)
-       (if (re-search-forward eshell-password-prompt-regexp
-                              eshell-last-output-end t)
-            ;; Use `run-at-time' in order not to pause execution of
-            ;; the process filter with a minibuffer
-           (run-at-time
-             0 nil
-             (lambda (current-buf)
-               (with-current-buffer current-buf
-                 (eshell-send-invisible)))
-             (current-buffer)))))))
+      (goto-char (max eshell-last-output-block-begin
+                      (- eshell-last-output-end
+                         eshell-password-prompt-max-length)))
+      (when (let ((case-fold-search t))
+              (re-search-forward eshell-password-prompt-regexp
+                                 eshell-last-output-end t))
+        ;; Use `run-at-time' in order not to pause execution of the
+        ;; process filter with a minibuffer.
+        (run-at-time
+         0 nil
+         (lambda (current-buf)
+           (with-current-buffer current-buf
+             (eshell-send-invisible)))
+         (current-buffer))))))
 
 (custom-add-option 'eshell-output-filter-functions
                   'eshell-watch-for-password-prompt)