From aada192458bf4f7ffcc469bc461c62413242489a Mon Sep 17 00:00:00 2001 From: Jim Porter Date: Sat, 15 Jun 2024 11:03:33 -0700 Subject: [PATCH] Limit the amount of text we examine when looking for password prompts 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 | 21 ++++++++++++++++++--- lisp/comint.el | 42 ++++++++++++++++++++++++----------------- lisp/eshell/esh-mode.el | 32 ++++++++++++++++++------------- 3 files changed, 62 insertions(+), 33 deletions(-) diff --git a/etc/NEWS b/etc/NEWS index 9b7d8447d87..504807261f7 100644 --- 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 '#'. @@ -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. diff --git a/lisp/comint.el b/lisp/comint.el index 90f974c5def..6cf72bd039f 100644 --- a/lisp/comint.el +++ b/lisp/comint.el @@ -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))))) ;; Low-level process communication diff --git a/lisp/eshell/esh-mode.el b/lisp/eshell/esh-mode.el index ec1a07b7e2f..34ce82cfbc4 100644 --- a/lisp/eshell/esh-mode.el +++ b/lisp/eshell/esh-mode.el @@ -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) -- 2.39.2