From 6ffe6c3c483c0efa3d0fb97c0a2f76def98d11dc Mon Sep 17 00:00:00 2001 From: Jim Porter Date: Sun, 8 Jan 2023 13:00:47 -0800 Subject: [PATCH 1/3] Set the 'field' property for Eshell output This makes Eshell work more like 'M-x shell', and lets us remove 'eshell-bol'. * lisp/eshell/em-prompt.el (eshell-emit-prompt): Add 'field' property to prompt. * lisp/eshell/esh-io.el: Declare 'eshell-interactive-print'... (eshell-output-object-to-target): ... use it. * lisp/eshell/esh-mode.el (eshell-output-filter-functions): Update docstring. (eshell-interactive-print): Set the output to have a field value of 'command-output'. (eshell-output-filter): Rename to... (eshell-interactive-filter): ... this, and take a buffer instead of a process. * lisp/eshell/esh-proc.el (eshell-interactive-process-filter): New function, adapted from 'eshell-output-filter'... (eshell-gather-process-output): ... use it. * test/lisp/eshell/em-prompt-tests.el: New file. --- lisp/eshell/em-prompt.el | 21 +++++--- lisp/eshell/esh-io.el | 6 +-- lisp/eshell/esh-mode.el | 25 +++++---- lisp/eshell/esh-proc.el | 22 ++++++-- test/lisp/eshell/em-prompt-tests.el | 81 +++++++++++++++++++++++++++++ 5 files changed, 131 insertions(+), 24 deletions(-) create mode 100644 test/lisp/eshell/em-prompt-tests.el diff --git a/lisp/eshell/em-prompt.el b/lisp/eshell/em-prompt.el index 575b5a595f1..866a21540d1 100644 --- a/lisp/eshell/em-prompt.el +++ b/lisp/eshell/em-prompt.el @@ -134,14 +134,19 @@ eshell-emit-prompt (if (not eshell-prompt-function) (set-marker eshell-last-output-end (point)) (let ((prompt (funcall eshell-prompt-function))) - (and eshell-highlight-prompt - (add-text-properties 0 (length prompt) - '(read-only t - font-lock-face eshell-prompt - front-sticky (font-lock-face read-only) - rear-nonsticky (font-lock-face read-only)) - prompt)) - (eshell-interactive-print prompt))) + (add-text-properties + 0 (length prompt) + (if eshell-highlight-prompt + '( read-only t + field prompt + font-lock-face eshell-prompt + front-sticky (read-only field font-lock-face) + rear-nonsticky (read-only field font-lock-face)) + '( field prompt + front-sticky (field) + rear-nonsticky (field))) + prompt) + (eshell-interactive-filter nil prompt))) (run-hooks 'eshell-after-prompt-hook)) (defun eshell-backward-matching-input (regexp arg) diff --git a/lisp/eshell/esh-io.el b/lisp/eshell/esh-io.el index 4dad4c7429a..cccdb49ce2a 100644 --- a/lisp/eshell/esh-io.el +++ b/lisp/eshell/esh-io.el @@ -74,6 +74,8 @@ (eval-when-compile (require 'cl-lib)) +(declare-function eshell-interactive-print "esh-mode" (string)) + (defgroup eshell-io nil "Eshell's I/O management code provides a scheme for treating many different kinds of objects -- symbols, files, buffers, etc. -- as @@ -597,8 +599,6 @@ eshell-printn (eshell-print object) (eshell-print "\n")) -(autoload 'eshell-output-filter "esh-mode") - (defun eshell-output-object-to-target (object target) "Insert OBJECT into TARGET. Returns what was actually sent, or nil if nothing was sent." @@ -608,7 +608,7 @@ eshell-output-object-to-target ((symbolp target) (if (eq target t) ; means "print to display" - (eshell-output-filter nil (eshell-stringify object)) + (eshell-interactive-print (eshell-stringify object)) (if (not (symbol-value target)) (set target object) (setq object (eshell-stringify object)) diff --git a/lisp/eshell/esh-mode.el b/lisp/eshell/esh-mode.el index d80f1d1f390..97edc826c9a 100644 --- a/lisp/eshell/esh-mode.el +++ b/lisp/eshell/esh-mode.el @@ -155,7 +155,8 @@ eshell-output-filter-functions eshell-watch-for-password-prompt) "Functions to call before output is displayed. These functions are only called for output that is displayed -interactively, and not for output which is redirected." +interactively (see `eshell-interactive-filter'), and not for +output which is redirected." :type 'hook) (defcustom eshell-preoutput-filter-functions nil @@ -525,9 +526,13 @@ eshell-goto-input-start (custom-add-option 'eshell-pre-command-hook #'eshell-goto-input-start) -(defsubst eshell-interactive-print (string) +(defun eshell-interactive-print (string) "Print STRING to the eshell display buffer." - (eshell-output-filter nil string)) + (when string + (add-text-properties 0 (length string) + '(field command-output rear-nonsticky (field)) + string) + (eshell-interactive-filter nil string))) (defsubst eshell-begin-on-new-line () "This function outputs a newline if not at beginning of line." @@ -687,14 +692,14 @@ eshell-kill-new (custom-add-option 'eshell-input-filter-functions 'eshell-kill-new) -(defun eshell-output-filter (process string) - "Send the output from PROCESS (STRING) to the interactive display. +(defun eshell-interactive-filter (buffer string) + "Send output (STRING) to the interactive display, using BUFFER. This is done after all necessary filtering has been done." - (let ((oprocbuf (if process (process-buffer process) - (current-buffer))) - (inhibit-modification-hooks t)) - (when (and string oprocbuf (buffer-name oprocbuf)) - (with-current-buffer oprocbuf + (unless buffer + (setq buffer (current-buffer))) + (when (and string (buffer-live-p buffer)) + (let ((inhibit-modification-hooks t)) + (with-current-buffer buffer (let ((functions eshell-preoutput-filter-functions)) (while (and functions string) (setq string (funcall (car functions) string)) diff --git a/lisp/eshell/esh-proc.el b/lisp/eshell/esh-proc.el index 8a803c67e46..9bae812c922 100644 --- a/lisp/eshell/esh-proc.el +++ b/lisp/eshell/esh-proc.el @@ -304,7 +304,7 @@ eshell-gather-process-output :name (concat (file-name-nondirectory command) "-stderr") :buffer (current-buffer) :filter (if (eshell-interactive-output-p eshell-error-handle) - #'eshell-output-filter + #'eshell-interactive-process-filter #'eshell-insertion-filter) :sentinel #'eshell-sentinel)) (eshell-record-process-properties stderr-proc eshell-error-handle)) @@ -320,7 +320,7 @@ eshell-gather-process-output :buffer (current-buffer) :command (cons command args) :filter (if (eshell-interactive-output-p) - #'eshell-output-filter + #'eshell-interactive-process-filter #'eshell-insertion-filter) :sentinel #'eshell-sentinel :connection-type conn-type @@ -381,7 +381,7 @@ eshell-gather-process-output line (buffer-substring-no-properties lbeg lend)) (set-buffer oldbuf) (if interact-p - (eshell-output-filter nil line) + (eshell-interactive-process-filter nil line) (eshell-output-object line)) (setq lbeg lend) (set-buffer proc-buf)) @@ -402,6 +402,22 @@ eshell-gather-process-output (setq proc t)))) proc)) +(defun eshell-interactive-process-filter (process string) + "Send the output from PROCESS (STRING) to the interactive display. +This is done after all necessary filtering has been done." + (when string + (add-text-properties 0 (length string) + '(field command-output rear-nonsticky (field)) + string) + (require 'esh-mode) + (declare-function eshell-interactive-filter "esh-mode" (buffer string)) + (eshell-interactive-filter (if process (process-buffer process) + (current-buffer)) + string))) + +(define-obsolete-function-alias 'eshell-output-filter + #'eshell-interactive-process-filter "30.1") + (defun eshell-insertion-filter (proc string) "Insert a string into the eshell buffer, or a process/file/buffer. PROC is the process for which we're inserting output. STRING is the diff --git a/test/lisp/eshell/em-prompt-tests.el b/test/lisp/eshell/em-prompt-tests.el new file mode 100644 index 00000000000..b67c74e86d0 --- /dev/null +++ b/test/lisp/eshell/em-prompt-tests.el @@ -0,0 +1,81 @@ +;;; em-prompt-tests.el --- em-prompt test suite -*- lexical-binding:t -*- + +;; Copyright (C) 2022-2023 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 . + +;;; Commentary: + +;; Tests for Eshell's prompt support. + +;;; Code: + +(require 'ert) +(require 'eshell) +(require 'em-prompt) + +(require 'eshell-tests-helpers + (expand-file-name "eshell-tests-helpers" + (file-name-directory (or load-file-name + default-directory)))) + +;;; Tests: + +(ert-deftest em-prompt-test/field-properties () + "Check that field properties are properly set on Eshell output/prompts." + (with-temp-eshell + (eshell-insert-command "echo hello") + (let ((last-prompt (field-string (1- eshell-last-input-start))) + (last-input (field-string (1+ eshell-last-input-start))) + (last-output (field-string (1+ eshell-last-input-end)))) + (should (equal-including-properties + last-prompt + (propertize + (format "%s $ " (directory-file-name default-directory)) + 'read-only t + 'field 'prompt + 'font-lock-face 'eshell-prompt + 'front-sticky '(read-only field font-lock-face) + 'rear-nonsticky '(read-only field font-lock-face)))) + (should (equal last-input "echo hello\n")) + (should (equal-including-properties + last-output + (propertize "hello\n" 'rear-nonsticky '(field) + 'field 'command-output)))))) + +(ert-deftest em-prompt-test/field-properties/no-highlight () + "Check that field properties are properly set on Eshell output/prompts. +This tests the case when `eshell-highlight-prompt' is nil." + (let ((eshell-highlight-prompt nil)) + (with-temp-eshell + (eshell-insert-command "echo hello") + (let ((last-prompt (field-string (1- eshell-last-input-start))) + (last-input (field-string (1+ eshell-last-input-start))) + (last-output (field-string (1+ eshell-last-input-end)))) + (should (equal-including-properties + last-prompt + (propertize + (format "%s $ " (directory-file-name default-directory)) + 'field 'prompt + 'front-sticky '(field) + 'rear-nonsticky '(field)))) + (should (equal last-input "echo hello\n")) + (should (equal-including-properties + last-output + (propertize "hello\n" 'rear-nonsticky '(field) + 'field 'command-output))))))) + +;;; em-prompt-tests.el ends here -- 2.25.1