[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[nongnu] elpa/eat a04999011f 3/9: Annotate shell prompts
From: |
ELPA Syncer |
Subject: |
[nongnu] elpa/eat a04999011f 3/9: Annotate shell prompts |
Date: |
Tue, 6 Dec 2022 13:58:46 -0500 (EST) |
branch: elpa/eat
commit a04999011f303ec0940cf7edc19b1c98f7608f40
Author: Akib Azmain Turja <akib@disroot.org>
Commit: Akib Azmain Turja <akib@disroot.org>
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.
---
eat.el | 252 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 235 insertions(+), 17 deletions(-)
diff --git a/eat.el b/eat.el
index 2c2908b80a..824277e028 100644
--- a/eat.el
+++ b/eat.el
@@ -161,6 +161,63 @@ the history of commands like `eat', `shell-command' and
:group 'eat-ui
: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
(let ((cur-type
'(choice
@@ -4112,6 +4169,18 @@ return \"eat-color\", otherwise return \"eat-mono\"."
(defvar eat--synchronize-scroll-function nil
"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 ()
"Perform a terminal reset."
(interactive)
@@ -4170,11 +4239,118 @@ If HOST isn't the host Emacs is running on, don't do
anything."
(ignore-errors
(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)
"Add CMD to `shell-command-history'."
(when eat-enable-shell-command-history
(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.
@@ -4546,21 +4722,27 @@ END if it's safe to do so."
(define-derived-mode eat-mode fundamental-mode "Eat"
"Major mode for Eat."
:group 'eat-ui
- (mapc #'make-local-variable '(buffer-read-only
- buffer-undo-list
- filter-buffer-substring-function
- mode-line-process
- mode-line-buffer-identification
- glyphless-char-display
- cursor-type
- track-mouse
- eat--terminal
- eat--process
- eat--synchronize-scroll-function
- eat--mouse-grabbing-type
- eat--pending-output-chunks
- eat--output-queue-first-chunk-time
- eat--process-output-queue-timer))
+ (mapc #'make-local-variable
+ '(buffer-read-only
+ buffer-undo-list
+ filter-buffer-substring-function
+ mode-line-process
+ mode-line-buffer-identification
+ glyphless-char-display
+ cursor-type
+ track-mouse
+ eat--terminal
+ eat--process
+ eat--synchronize-scroll-function
+ eat--mouse-grabbing-type
+ eat--shell-command-status
+ 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.
(setq buffer-read-only nil
buffer-undo-list t
@@ -4634,7 +4816,24 @@ mouse-3: Switch to char mode"
;; that would break the display.
(eat--setup-glyphless-chars)
(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.
@@ -4653,6 +4852,9 @@ The output chunks are pushed, so last output appears
first.")
(defvar eat--process-output-queue-timer nil
"Timer to process output queue.")
+(defvar eat--shell-prompt-annotation-update-timer nil
+ "Timer to update shell prompt annotations.")
+
(defun eat-kill-process ()
"Kill Eat process in current buffer."
(interactive)
@@ -4708,6 +4910,13 @@ OS's."
(max (point-min)
(- (eat-term-display-beginning eat--terminal)
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
(funcall eat--synchronize-scroll-function))))))
@@ -4717,6 +4926,8 @@ OS's."
(with-current-buffer (process-buffer process)
(when 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
(setq eat--output-queue-first-chunk-time (current-time)))
(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-term-ring-bell-function eat--terminal) #'eat--bell
(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.
(let* ((size (eat-term-size eat--terminal))
(process-environment
- [nongnu] elpa/eat updated (d35864ca6b -> 693940c733), ELPA Syncer, 2022/12/06
- [nongnu] elpa/eat 693940c733 9/9: * README.org: Add shell integration instructions, ELPA Syncer, 2022/12/06
- [nongnu] elpa/eat 8188f71562 8/9: * eat-tests.el (eat-test-set-cwd): Update test, ELPA Syncer, 2022/12/06
- [nongnu] elpa/eat 62a09caef1 7/9: * eat.el (eat--t-term): Fix initial value of 'cwd', ELPA Syncer, 2022/12/06
- [nongnu] elpa/eat a04999011f 3/9: Annotate shell prompts,
ELPA Syncer <=
- [nongnu] elpa/eat e287487b42 6/9: Document everything about shell integration, ELPA Syncer, 2022/12/06
- [nongnu] elpa/eat 2c6afa4dc0 4/9: Add shell prompt navigation commands, ELPA Syncer, 2022/12/06
- [nongnu] elpa/eat 9caa496e45 1/9: Tighter shell integration, ELPA Syncer, 2022/12/06
- [nongnu] elpa/eat b42687f146 5/9: Fix prompt navigation when annotation is disabled, ELPA Syncer, 2022/12/06
- [nongnu] elpa/eat b4d07cb474 2/9: Add shell commands run in Eat to Emacs history, ELPA Syncer, 2022/12/06