From: Jim Porter Date: Thu, 23 May 2024 21:55:59 +0000 (-0700) Subject: Rework how 'eshell-ensure-newline-p' adds newlines X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=bd9f5472b98183e69ef82ca3f9b7d6d779246eb5;p=emacs.git Rework how 'eshell-ensure-newline-p' adds newlines This allows for other output targets (see the following commit) to be "line-oriented". * lisp/eshell/esh-io.el (eshell-ensure-newline-p): Move from esh-cmd.el. (eshell-target-line-oriented-p, eshell--output-maybe-n) (eshell-print-maybe-n, eshell-error-maybe-n) (eshell-maybe-output-newline): New functions. * lisp/eshell/esh-cmd.el (eshell-lisp-command): Don't print a newline in this function directly; instead, use 'eshell-print-maybe-n' and 'eshell-error-maybe-n'. (eshell-ensure-newline-p): Move to esh-io.el. * lisp/eshell/em-unix.el (eshell/cat): Remove now-unnecessary override of 'eshell-ensure-newline-p'. (cherry picked from commit eac608cb8041222ba3b2eac48ac6f76ac36bab16) --- diff --git a/lisp/eshell/em-unix.el b/lisp/eshell/em-unix.el index 7f976d22681..4137c05fa41 100644 --- a/lisp/eshell/em-unix.el +++ b/lisp/eshell/em-unix.el @@ -683,9 +683,7 @@ Concatenate FILE(s), or standard input, to standard output.") (with-current-buffer curbuf (eshell-buffered-print str))) (forward-line))))) - (eshell-flush) - ;; if the file does not end in a newline, do not emit one - (setq eshell-ensure-newline-p nil)))) + (eshell-flush)))) (put 'eshell/cat 'eshell-no-numeric-conversions t) (put 'eshell/cat 'eshell-filename-arguments t) diff --git a/lisp/eshell/esh-cmd.el b/lisp/eshell/esh-cmd.el index 57aeff59266..1072646ec15 100644 --- a/lisp/eshell/esh-cmd.el +++ b/lisp/eshell/esh-cmd.el @@ -254,11 +254,6 @@ the command." :type 'sexp :risky t) -(defvar eshell-ensure-newline-p nil - "If non-nil, ensure that a newline is emitted after a Lisp form. -This can be changed by Lisp forms that are evaluated from the Eshell -command line.") - ;;; Internal Variables: ;; These variables have been merged into `eshell-foreground-command'. @@ -1499,7 +1494,7 @@ a string naming a Lisp function." (catch 'eshell-external ; deferred to an external command (setq eshell-last-command-status 0 eshell-last-arguments args) - (let* ((eshell-ensure-newline-p (eshell-interactive-output-p)) + (let* ((eshell-ensure-newline-p t) (command-form-p (functionp object)) (result (if command-form-p @@ -1526,14 +1521,13 @@ a string naming a Lisp function." (setq args (cdr args)))) (setq eshell-last-command-name (concat "#")) - (eshell-apply object eshell-last-arguments)) + (eshell-apply* #'eshell-print-maybe-n + #'eshell-error-maybe-n + object eshell-last-arguments)) (setq eshell-last-command-name "#") - (eshell-eval object)))) - (if (and eshell-ensure-newline-p - (save-excursion - (goto-char eshell-last-output-end) - (not (bolp)))) - (eshell-print "\n")) + (eshell-eval* #'eshell-print-maybe-n + #'eshell-error-maybe-n + object)))) (eshell-close-handles ;; If `eshell-lisp-form-nil-is-failure' is non-nil, Lisp forms ;; that succeeded but have a nil result should have an exit diff --git a/lisp/eshell/esh-io.el b/lisp/eshell/esh-io.el index 9b35125cd28..c7017ee1d70 100644 --- a/lisp/eshell/esh-io.el +++ b/lisp/eshell/esh-io.el @@ -162,6 +162,12 @@ ordinary function or `eshell-generic-target' as desribed above)." (define-error 'eshell-pipe-broken "Pipe broken") +(defvar eshell-ensure-newline-p nil + "If non-nil, ensure that a newline is emitted after a Lisp form. +This can be changed by Lisp forms that are evaluated from the +Eshell command line. This behavior only applies to line-oriented +output targets (see `eshell-target-line-oriented-p'.") + ;;; Internal Variables: (defconst eshell-redirection-operators-alist @@ -493,15 +499,37 @@ after all printing is over with no argument." "Output OBJECT to the standard error handle." (eshell-output-object object eshell-error-handle)) +(defsubst eshell-printn (object) + "Output OBJECT followed by a newline to the standard output handle." + (eshell-print object) + (eshell-print "\n")) + (defsubst eshell-errorn (object) "Output OBJECT followed by a newline to the standard error handle." (eshell-error object) (eshell-error "\n")) -(defsubst eshell-printn (object) - "Output OBJECT followed by a newline to the standard output handle." - (eshell-print object) - (eshell-print "\n")) +(defun eshell--output-maybe-n (object handle) + "Output OBJECT to HANDLE. +For any line-oriented output targets on HANDLE, ensure the output +ends in a newline." + (eshell-output-object object handle) + (when (and eshell-ensure-newline-p + (not (and (stringp object) + (string-suffix-p object "\n")))) + (eshell-maybe-output-newline handle))) + +(defsubst eshell-print-maybe-n (object) + "Output OBJECT to the standard output handle. +For any line-oriented output targets, ensure the output ends in a +newline." + (eshell--output-maybe-n object eshell-output-handle)) + +(defsubst eshell-error-maybe-n (object) + "Output OBJECT to the standard error handle. +For any line-oriented output targets, ensure the output ends in a +newline." + (eshell--output-maybe-n object eshell-error-handle)) (cl-defstruct (eshell-generic-target (:constructor nil)) "An Eshell target. @@ -678,6 +706,16 @@ Returns what was actually sent, or nil if nothing was sent.") "Output OBJECT to the Eshell function TARGET." (funcall (eshell-function-target-output-function target) object)) +(cl-defgeneric eshell-target-line-oriented-p (_target) + "Return non-nil if the specified TARGET is line-oriented. +Line-oriented targets are those that expect a newline after +command output when `eshell-ensure-newline-p' is non-nil." + nil) + +(cl-defmethod eshell-target-line-oriented-p ((_target (eql t))) + "Return non-nil to indicate that the display is line-oriented." + t) + (defun eshell-output-object (object &optional handle-index handles) "Insert OBJECT, using HANDLE-INDEX specifically. If HANDLE-INDEX is nil, output to `eshell-output-handle'. @@ -688,5 +726,18 @@ HANDLES is the set of file handles to use; if nil, use (dolist (target targets) (eshell-output-object-to-target object target)))) +(defun eshell-maybe-output-newline (&optional handle-index handles) + "Maybe insert a newline, using HANDLE-INDEX specifically. +This inserts a newline for all line-oriented output targets. + +If HANDLE-INDEX is nil, output to `eshell-output-handle'. +HANDLES is the set of file handles to use; if nil, use +`eshell-current-handles'." + (let ((targets (caar (aref (or handles eshell-current-handles) + (or handle-index eshell-output-handle))))) + (dolist (target targets) + (when (eshell-target-line-oriented-p target) + (eshell-output-object-to-target "\n" target))))) + (provide 'esh-io) ;;; esh-io.el ends here