Annotate shell prompts
* eat.el (eat-enable-shell-prompt-annotation) (eat-shell-prompt-annotation-position) (eat-shell-prompt-annotation-running-margin-indicator) (eat-shell-prompt-annotation-success-margin-indicator) (eat-shell-prompt-annotation-failure-margin-indicator) (eat-shell-prompt-annotation-delay): New user option. * eat.el (eat-shell-prompt-annotation-running) (eat-shell-prompt-annotation-success) (eat-shell-prompt-annotation-failure): New face. * eat.el (eat--shell-command-status, eat--shell-prompt-begin) (eat--shell-prompt-mark, eat--shell-prompt-mark-overlays): New variable. * eat.el (eat--pre-prompt, eat--post-prompt) (eat--update-shell-prompt-mark-overlays, eat--pre-cmd) (eat--set-cmd-status): New function. * eat.el (eat-mode): Make 'eat--shell-command-status', 'eat--shell-prompt-begin', 'eat--shell-prompt-mark', 'eat--shell-prompt-mark-overlays' and 'eat--shell-prompt-annotation-update-timer' local. Set margin width if shell prompt annotation is enabled. * eat.el (eat--shell-prompt-annotation-update-timer): New variable. * eat.el (eat--process-output-queue): Call or schedule 'eat--update-shell-prompt-mark-overlays' call. * eat.el (eat--filter): Cancel timer 'eat--shell-prompt-annotation-update-timer'. * eat.el (eat-exec): Set prompt start & end and command start & end functions.
This commit is contained in:
parent
b4d07cb474
commit
a04999011f
1 changed files with 235 additions and 17 deletions
252
eat.el
252
eat.el
|
@ -161,6 +161,63 @@ the history of commands like `eat', `shell-command' and
|
||||||
:group 'eat-ui
|
:group 'eat-ui
|
||||||
:group 'eat-eshell)
|
:group 'eat-eshell)
|
||||||
|
|
||||||
|
(defcustom eat-enable-shell-prompt-annotation t
|
||||||
|
"Non-nil means annotate shell prompt with the status of command.
|
||||||
|
|
||||||
|
When non-nil, display a mark in front of shell prompt describing the
|
||||||
|
status of the command executed in that prompt."
|
||||||
|
:type 'boolean
|
||||||
|
:group 'eat-ui)
|
||||||
|
|
||||||
|
(defcustom eat-shell-prompt-annotation-position 'left-margin
|
||||||
|
"The position where to display shell prompt annotation.
|
||||||
|
|
||||||
|
The value can be one of the following:
|
||||||
|
|
||||||
|
`left-margin' Use the left margin.
|
||||||
|
`right-margin' Use the right margin."
|
||||||
|
:type '(choice (const :tag "Left margin" left-margin)
|
||||||
|
(const :tag "Right margin" right-margin))
|
||||||
|
:group 'eat-ui)
|
||||||
|
|
||||||
|
(defcustom eat-shell-prompt-annotation-running-margin-indicator "-"
|
||||||
|
"String in margin annotation to indicate the command is running."
|
||||||
|
:type 'string
|
||||||
|
:group 'eat-ui)
|
||||||
|
|
||||||
|
(defface eat-shell-prompt-annotation-running
|
||||||
|
'((t :inherit compilation-info))
|
||||||
|
"Face used in annotation to indicate the command is running."
|
||||||
|
:group 'eat-ui)
|
||||||
|
|
||||||
|
(defcustom eat-shell-prompt-annotation-success-margin-indicator "0"
|
||||||
|
"String in margin annotation to indicate the command has succeeded."
|
||||||
|
:type 'string
|
||||||
|
:group 'eat-ui)
|
||||||
|
|
||||||
|
(defface eat-shell-prompt-annotation-success
|
||||||
|
'((t :inherit success))
|
||||||
|
"Face used in annotation to indicate the command has succeeded."
|
||||||
|
:group 'eat-ui)
|
||||||
|
|
||||||
|
(defcustom eat-shell-prompt-annotation-failure-margin-indicator "X"
|
||||||
|
"String in margin annotation to indicate the command has failed."
|
||||||
|
:type 'string
|
||||||
|
:group 'eat-ui)
|
||||||
|
|
||||||
|
(defface eat-shell-prompt-annotation-failure
|
||||||
|
'((t :inherit error))
|
||||||
|
"Face used in annotation to indicate the command has failed."
|
||||||
|
:group 'eat-ui)
|
||||||
|
|
||||||
|
(defcustom eat-shell-prompt-annotation-delay 0.1
|
||||||
|
"Seconds to wait before updating prompt annotations.
|
||||||
|
|
||||||
|
Nil means update immediately."
|
||||||
|
:type '(choice (const :tag "Immediately" nil)
|
||||||
|
number)
|
||||||
|
:group 'eat-ui)
|
||||||
|
|
||||||
(defconst eat--cursor-type-value-type
|
(defconst eat--cursor-type-value-type
|
||||||
(let ((cur-type
|
(let ((cur-type
|
||||||
'(choice
|
'(choice
|
||||||
|
@ -4112,6 +4169,18 @@ return \"eat-color\", otherwise return \"eat-mono\"."
|
||||||
(defvar eat--synchronize-scroll-function nil
|
(defvar eat--synchronize-scroll-function nil
|
||||||
"Function to synchronize scrolling between terminal and window.")
|
"Function to synchronize scrolling between terminal and window.")
|
||||||
|
|
||||||
|
(defvar eat--shell-command-status 0
|
||||||
|
"If the current shell command has finished, its exit status.")
|
||||||
|
|
||||||
|
(defvar eat--shell-prompt-begin nil
|
||||||
|
"Beginning of last shell prompt.")
|
||||||
|
|
||||||
|
(defvar eat--shell-prompt-mark nil
|
||||||
|
"Display property used to put a mark before the previous prompt.")
|
||||||
|
|
||||||
|
(defvar eat--shell-prompt-mark-overlays nil
|
||||||
|
"List of overlay used to put marks before shell prompts.")
|
||||||
|
|
||||||
(defun eat-reset ()
|
(defun eat-reset ()
|
||||||
"Perform a terminal reset."
|
"Perform a terminal reset."
|
||||||
(interactive)
|
(interactive)
|
||||||
|
@ -4170,11 +4239,118 @@ If HOST isn't the host Emacs is running on, don't do anything."
|
||||||
(ignore-errors
|
(ignore-errors
|
||||||
(cd-absolute cwd))))
|
(cd-absolute cwd))))
|
||||||
|
|
||||||
|
(defun eat--pre-prompt (_)
|
||||||
|
"Save the beginning position of shell prompt."
|
||||||
|
(when eat-enable-shell-prompt-annotation
|
||||||
|
(setq eat--shell-prompt-begin (point-marker))))
|
||||||
|
|
||||||
|
(defun eat--post-prompt (_)
|
||||||
|
"Put a mark in the marginal area on current line."
|
||||||
|
(when eat-enable-shell-prompt-annotation
|
||||||
|
(let ((indicator
|
||||||
|
(if (zerop eat--shell-command-status)
|
||||||
|
(propertize
|
||||||
|
eat-shell-prompt-annotation-success-margin-indicator
|
||||||
|
'face 'eat-shell-prompt-annotation-success)
|
||||||
|
(propertize
|
||||||
|
eat-shell-prompt-annotation-failure-margin-indicator
|
||||||
|
'face 'eat-shell-prompt-annotation-failure))))
|
||||||
|
;; Update previous prompt's indicator using side-effect.
|
||||||
|
(when eat--shell-prompt-mark
|
||||||
|
(setf (cadr eat--shell-prompt-mark) indicator)
|
||||||
|
(setq eat--shell-prompt-mark nil))
|
||||||
|
;; Show this prompt's indicator.
|
||||||
|
(when eat--shell-prompt-begin
|
||||||
|
(when (< eat--shell-prompt-begin (point))
|
||||||
|
;; Save it, we'll use side-effect.
|
||||||
|
(setq eat--shell-prompt-mark
|
||||||
|
`((margin ,eat-shell-prompt-annotation-position)
|
||||||
|
,indicator))
|
||||||
|
;; Make overlay and put bookkeeping properties.
|
||||||
|
(let ((identifier (gensym "eat--prompt-mark-identifier-"))
|
||||||
|
(before-str
|
||||||
|
(propertize " " 'display eat--shell-prompt-mark))
|
||||||
|
(ov (make-overlay eat--shell-prompt-begin
|
||||||
|
(1+ eat--shell-prompt-begin))))
|
||||||
|
(overlay-put ov 'before-string before-str)
|
||||||
|
(overlay-put ov 'eat--shell-prompt-mark-id identifier)
|
||||||
|
(add-text-properties
|
||||||
|
eat--shell-prompt-begin (1+ eat--shell-prompt-begin)
|
||||||
|
(list 'eat--before-string before-str
|
||||||
|
'eat--shell-prompt-mark-id identifier
|
||||||
|
'eat--shell-prompt-mark-overlay ov))
|
||||||
|
(push ov eat--shell-prompt-mark-overlays)))
|
||||||
|
(setq eat--shell-prompt-begin nil)))))
|
||||||
|
|
||||||
|
(defun eat--update-shell-prompt-mark-overlays (buffer)
|
||||||
|
"Update all overlays used to add mark before shell prompt.
|
||||||
|
|
||||||
|
BUFFER is the terminal buffer."
|
||||||
|
(when (and (buffer-live-p buffer)
|
||||||
|
eat-enable-shell-prompt-annotation)
|
||||||
|
(with-current-buffer buffer
|
||||||
|
(while-no-input
|
||||||
|
;; Delete all outdated overlays.
|
||||||
|
(dolist (ov eat--shell-prompt-mark-overlays)
|
||||||
|
(unless (eq (overlay-get ov 'eat--shell-prompt-mark-id)
|
||||||
|
(get-text-property (overlay-start ov)
|
||||||
|
'eat--shell-prompt-mark-id))
|
||||||
|
(delete-overlay ov)
|
||||||
|
(setq eat--shell-prompt-mark-overlays
|
||||||
|
(delq ov eat--shell-prompt-mark-overlays))))
|
||||||
|
(save-excursion
|
||||||
|
;; Recreate overlays if needed.
|
||||||
|
(goto-char (eat-term-beginning eat--terminal))
|
||||||
|
(while (< (point) (eat-term-end eat--terminal))
|
||||||
|
(when (get-text-property
|
||||||
|
(point) 'eat--shell-prompt-mark-id)
|
||||||
|
(let ((ov (get-text-property
|
||||||
|
(point) 'eat--shell-prompt-mark-overlay)))
|
||||||
|
(unless
|
||||||
|
(and ov
|
||||||
|
(overlay-buffer ov)
|
||||||
|
(eq (overlay-get
|
||||||
|
ov 'eat--shell-prompt-mark-id)
|
||||||
|
(get-text-property
|
||||||
|
(point) 'eat--shell-prompt-mark-id)))
|
||||||
|
;; Recreate.
|
||||||
|
(when ov
|
||||||
|
(delete-overlay ov)
|
||||||
|
(setq eat--shell-prompt-mark-overlays
|
||||||
|
(delq ov eat--shell-prompt-mark-overlays)))
|
||||||
|
(setq ov (make-overlay (point) (1+ (point))))
|
||||||
|
(overlay-put ov 'before-string
|
||||||
|
(get-text-property
|
||||||
|
(point) 'eat--before-string))
|
||||||
|
(overlay-put ov 'eat--shell-prompt-mark-id
|
||||||
|
(get-text-property
|
||||||
|
(point) 'eat--shell-prompt-mark-id))
|
||||||
|
(push ov eat--shell-prompt-mark-overlays))))
|
||||||
|
(goto-char (or (next-single-property-change
|
||||||
|
(point) 'eat--shell-prompt-mark-id nil
|
||||||
|
(eat-term-end eat--terminal))
|
||||||
|
(eat-term-end eat--terminal)))))))))
|
||||||
|
|
||||||
(defun eat--set-cmd (_ cmd)
|
(defun eat--set-cmd (_ cmd)
|
||||||
"Add CMD to `shell-command-history'."
|
"Add CMD to `shell-command-history'."
|
||||||
(when eat-enable-shell-command-history
|
(when eat-enable-shell-command-history
|
||||||
(add-to-history 'shell-command-history cmd)))
|
(add-to-history 'shell-command-history cmd)))
|
||||||
|
|
||||||
|
(defun eat--pre-cmd (_)
|
||||||
|
"Update shell prompt mark to indicate command is running."
|
||||||
|
(when (and eat-enable-shell-prompt-annotation
|
||||||
|
eat--shell-prompt-mark)
|
||||||
|
(setf (cadr eat--shell-prompt-mark)
|
||||||
|
(propertize
|
||||||
|
eat-shell-prompt-annotation-running-margin-indicator
|
||||||
|
'face 'eat-shell-prompt-annotation-running))))
|
||||||
|
|
||||||
|
(defun eat--set-cmd-status (_ code)
|
||||||
|
"Set CODE as the current shell command's exit status."
|
||||||
|
(when eat-enable-shell-prompt-annotation
|
||||||
|
;; We'll update the mark later when the prompt appears.
|
||||||
|
(setq eat--shell-command-status code)))
|
||||||
|
|
||||||
|
|
||||||
;;;;; Input.
|
;;;;; Input.
|
||||||
|
|
||||||
|
@ -4546,21 +4722,27 @@ END if it's safe to do so."
|
||||||
(define-derived-mode eat-mode fundamental-mode "Eat"
|
(define-derived-mode eat-mode fundamental-mode "Eat"
|
||||||
"Major mode for Eat."
|
"Major mode for Eat."
|
||||||
:group 'eat-ui
|
:group 'eat-ui
|
||||||
(mapc #'make-local-variable '(buffer-read-only
|
(mapc #'make-local-variable
|
||||||
buffer-undo-list
|
'(buffer-read-only
|
||||||
filter-buffer-substring-function
|
buffer-undo-list
|
||||||
mode-line-process
|
filter-buffer-substring-function
|
||||||
mode-line-buffer-identification
|
mode-line-process
|
||||||
glyphless-char-display
|
mode-line-buffer-identification
|
||||||
cursor-type
|
glyphless-char-display
|
||||||
track-mouse
|
cursor-type
|
||||||
eat--terminal
|
track-mouse
|
||||||
eat--process
|
eat--terminal
|
||||||
eat--synchronize-scroll-function
|
eat--process
|
||||||
eat--mouse-grabbing-type
|
eat--synchronize-scroll-function
|
||||||
eat--pending-output-chunks
|
eat--mouse-grabbing-type
|
||||||
eat--output-queue-first-chunk-time
|
eat--shell-command-status
|
||||||
eat--process-output-queue-timer))
|
eat--shell-prompt-begin
|
||||||
|
eat--shell-prompt-mark
|
||||||
|
eat--shell-prompt-mark-overlays
|
||||||
|
eat--pending-output-chunks
|
||||||
|
eat--output-queue-first-chunk-time
|
||||||
|
eat--process-output-queue-timer
|
||||||
|
eat--shell-prompt-annotation-update-timer))
|
||||||
;; This is intended; input methods don't work on read-only buffers.
|
;; This is intended; input methods don't work on read-only buffers.
|
||||||
(setq buffer-read-only nil
|
(setq buffer-read-only nil
|
||||||
buffer-undo-list t
|
buffer-undo-list t
|
||||||
|
@ -4634,7 +4816,24 @@ mouse-3: Switch to char mode"
|
||||||
;; that would break the display.
|
;; that would break the display.
|
||||||
(eat--setup-glyphless-chars)
|
(eat--setup-glyphless-chars)
|
||||||
(when eat-enable-blinking-text
|
(when eat-enable-blinking-text
|
||||||
(eat-blink-mode +1)))
|
(eat-blink-mode +1))
|
||||||
|
(when eat-enable-shell-prompt-annotation
|
||||||
|
(let ((margin-width
|
||||||
|
(max
|
||||||
|
(string-width
|
||||||
|
eat-shell-prompt-annotation-running-margin-indicator)
|
||||||
|
(string-width
|
||||||
|
eat-shell-prompt-annotation-success-margin-indicator)
|
||||||
|
(string-width
|
||||||
|
eat-shell-prompt-annotation-failure-margin-indicator))))
|
||||||
|
(pcase-exhaustive eat-shell-prompt-annotation-position
|
||||||
|
('left-margin
|
||||||
|
(setq left-margin-width margin-width))
|
||||||
|
('right-margin
|
||||||
|
(setq right-margin-width margin-width))))
|
||||||
|
;; Make sure the marginal area is resized.
|
||||||
|
(dolist (win (get-buffer-window-list))
|
||||||
|
(set-window-buffer win (current-buffer)))))
|
||||||
|
|
||||||
|
|
||||||
;;;;; Process Handling.
|
;;;;; Process Handling.
|
||||||
|
@ -4653,6 +4852,9 @@ The output chunks are pushed, so last output appears first.")
|
||||||
(defvar eat--process-output-queue-timer nil
|
(defvar eat--process-output-queue-timer nil
|
||||||
"Timer to process output queue.")
|
"Timer to process output queue.")
|
||||||
|
|
||||||
|
(defvar eat--shell-prompt-annotation-update-timer nil
|
||||||
|
"Timer to update shell prompt annotations.")
|
||||||
|
|
||||||
(defun eat-kill-process ()
|
(defun eat-kill-process ()
|
||||||
"Kill Eat process in current buffer."
|
"Kill Eat process in current buffer."
|
||||||
(interactive)
|
(interactive)
|
||||||
|
@ -4708,6 +4910,13 @@ OS's."
|
||||||
(max (point-min)
|
(max (point-min)
|
||||||
(- (eat-term-display-beginning eat--terminal)
|
(- (eat-term-display-beginning eat--terminal)
|
||||||
eat-term-scrollback-size))))
|
eat-term-scrollback-size))))
|
||||||
|
(if (null eat-shell-prompt-annotation-delay)
|
||||||
|
(eat--update-shell-prompt-mark-overlays buffer)
|
||||||
|
(setq eat--shell-prompt-annotation-update-timer
|
||||||
|
(run-with-timer
|
||||||
|
eat-shell-prompt-annotation-delay
|
||||||
|
nil #'eat--update-shell-prompt-mark-overlays
|
||||||
|
buffer)))
|
||||||
(when synchronize-scroll
|
(when synchronize-scroll
|
||||||
(funcall eat--synchronize-scroll-function))))))
|
(funcall eat--synchronize-scroll-function))))))
|
||||||
|
|
||||||
|
@ -4717,6 +4926,8 @@ OS's."
|
||||||
(with-current-buffer (process-buffer process)
|
(with-current-buffer (process-buffer process)
|
||||||
(when eat--process-output-queue-timer
|
(when eat--process-output-queue-timer
|
||||||
(cancel-timer eat--process-output-queue-timer))
|
(cancel-timer eat--process-output-queue-timer))
|
||||||
|
(when eat--shell-prompt-annotation-update-timer
|
||||||
|
(cancel-timer eat--shell-prompt-annotation-update-timer))
|
||||||
(unless eat--output-queue-first-chunk-time
|
(unless eat--output-queue-first-chunk-time
|
||||||
(setq eat--output-queue-first-chunk-time (current-time)))
|
(setq eat--output-queue-first-chunk-time (current-time)))
|
||||||
(push output eat--pending-output-chunks)
|
(push output eat--pending-output-chunks)
|
||||||
|
@ -4816,7 +5027,14 @@ same Eat buffer. The hook `eat-exec-hook' is run after each exec."
|
||||||
#'eat--manipulate-kill-ring
|
#'eat--manipulate-kill-ring
|
||||||
(eat-term-ring-bell-function eat--terminal) #'eat--bell
|
(eat-term-ring-bell-function eat--terminal) #'eat--bell
|
||||||
(eat-term-set-cwd-function eat--terminal) #'eat--set-cwd
|
(eat-term-set-cwd-function eat--terminal) #'eat--set-cwd
|
||||||
(eat-term-set-cmd-function eat--terminal) #'eat--set-cmd)
|
(eat-term-prompt-start-function eat--terminal)
|
||||||
|
#'eat--pre-prompt
|
||||||
|
(eat-term-prompt-end-function eat--terminal)
|
||||||
|
#'eat--post-prompt
|
||||||
|
(eat-term-set-cmd-function eat--terminal) #'eat--set-cmd
|
||||||
|
(eat-term-cmd-start-function eat--terminal) #'eat--pre-cmd
|
||||||
|
(eat-term-cmd-finish-function eat--terminal)
|
||||||
|
#'eat--set-cmd-status)
|
||||||
;; Crank up a new process.
|
;; Crank up a new process.
|
||||||
(let* ((size (eat-term-size eat--terminal))
|
(let* ((size (eat-term-size eat--terminal))
|
||||||
(process-environment
|
(process-environment
|
||||||
|
|
Loading…
Add table
Reference in a new issue