Add message passing support
* eat.el (eat-message-handler-alist): New user option. * eat.el (eat--handle-message): New function. * eat.el (eat--handle-uic, eat--eshell-handle-uic): Handle message passing sequence. * eat.texi (Message Passing): New section in chapter "Shell Integration". * integration/bash (__eat_enable_integration): Remove the unnecessary complex code to update PROMPT_COMMAND. * integration/bash (_eat_msg): * integration/zsh (_eat_msg): New function.
This commit is contained in:
parent
9e129f33a2
commit
b2ad1be411
4 changed files with 100 additions and 13 deletions
46
eat.el
46
eat.el
|
@ -296,6 +296,20 @@ the history of commands like `eat', `shell-command' and
|
|||
:group 'eat-ui
|
||||
:group 'eat-eshell)
|
||||
|
||||
(defcustom eat-message-handler-alist nil
|
||||
"Alist of message handler name and its handler function.
|
||||
|
||||
The keys are the names of message handlers, and the values are their
|
||||
respective handler functions.
|
||||
|
||||
Shells can send Eat messages, as defined in this user option. If an
|
||||
appropiate message handler is defined, it's called with the other
|
||||
arguments, otherwise it's ignored."
|
||||
:type '(alist :key-type string
|
||||
:value-type function)
|
||||
:group 'eat-ui
|
||||
:group 'eat-eshell)
|
||||
|
||||
(defcustom eat-enable-native-shell-prompt-editing nil
|
||||
"Non-nil means allowing editing shell prompt using Emacs commands.
|
||||
|
||||
|
@ -5215,6 +5229,22 @@ BUFFER is the terminal buffer."
|
|||
locale-coding-system))
|
||||
format))))
|
||||
|
||||
(defun eat--handle-message (name &rest args)
|
||||
"Handle message with handler name NAME and ARGS."
|
||||
(when-let* ((name (ignore-errors (decode-coding-string
|
||||
(base64-decode-string name)
|
||||
locale-coding-system)))
|
||||
(handler (assoc name eat-message-handler-alist)))
|
||||
(save-restriction
|
||||
(widen)
|
||||
(save-excursion
|
||||
(apply (cdr handler)
|
||||
(mapcar (lambda (arg)
|
||||
(ignore-errors (decode-coding-string
|
||||
(base64-decode-string arg)
|
||||
locale-coding-system)))
|
||||
args))))))
|
||||
|
||||
(defun eat--handle-uic (_ cmd)
|
||||
"Handle UI Command sequence CMD."
|
||||
(pcase cmd
|
||||
|
@ -5257,20 +5287,27 @@ BUFFER is the terminal buffer."
|
|||
(let status (one-or-more digit))
|
||||
string-end)
|
||||
(eat--set-cmd-status (string-to-number status)))
|
||||
;; UIC e ; I ; <n> ST.
|
||||
;; UIC e ; I ; 0 ; <t> ; <t> ; <t> ST.
|
||||
((rx string-start "e;I;0;"
|
||||
(let format (zero-or-more (not ?\;)))
|
||||
?\; (let host (zero-or-more (not ?\;)))
|
||||
?\; (let path (zero-or-more anything))
|
||||
string-end)
|
||||
(eat--get-shell-history (cons host path) format))
|
||||
;; UIC e ; I ; 1 ; <t> ; <t> ST.
|
||||
((rx string-start "e;I;1;"
|
||||
(let format (zero-or-more (not ?\;)))
|
||||
?\; (let hist (zero-or-more anything))
|
||||
string-end)
|
||||
(eat--get-shell-history hist format))
|
||||
;; UIC e ; J ST.
|
||||
("e;J"
|
||||
(eat--before-new-prompt))))
|
||||
(eat--before-new-prompt))
|
||||
;; UIC e ; M ; ... ST.
|
||||
((rx string-start "e;M;"
|
||||
(let msg (zero-or-more anything))
|
||||
string-end)
|
||||
(apply #'eat--handle-message (string-split msg ";")))))
|
||||
|
||||
(defun eat-previous-shell-prompt (&optional arg)
|
||||
"Go to the previous shell prompt.
|
||||
|
@ -6894,6 +6931,11 @@ PROGRAM can be a shell command."
|
|||
;; UIC e ; I ; 0 ; <t> ST.
|
||||
((rx string-start "e;I;0;" (zero-or-more anything) string-end)
|
||||
(eat-term-send-string eat--terminal "\e]51;e;I;0\e\\"))
|
||||
;; UIC e ; M ; ... ST.
|
||||
((rx string-start "e;M;"
|
||||
(let msg (zero-or-more anything))
|
||||
string-end)
|
||||
(apply #'eat--handle-message (string-split msg ";")))
|
||||
;; Other sequences are ignored.
|
||||
))
|
||||
|
||||
|
|
35
eat.texi
35
eat.texi
|
@ -479,7 +479,6 @@ When set to @code{right-margin}, Eat uses the right margin.
|
|||
@vindex eat-shell-prompt-annotation-success
|
||||
@vindex eat-shell-prompt-annotation-failure-margin-indicator
|
||||
@vindex eat-shell-prompt-annotation-failure
|
||||
|
||||
Eat uses the strings ``-'', ``0'' and ``X'' respectively to indicate
|
||||
the command is running, the command has succeeded and the command has
|
||||
failed. You can also customize the them. The user option
|
||||
|
@ -495,6 +494,40 @@ face @code{eat-shell-prompt-annotation-failure} control the indicator
|
|||
used to indicate the command has exited unsuccessfully with non-zero
|
||||
exit status.
|
||||
|
||||
@anchor{Message Passing}
|
||||
@section Message Passing
|
||||
|
||||
After enabling shell integration, you can send messages to Emacs from
|
||||
your shell. Then you can handle the message on Emacs side using usual
|
||||
Emacs Lisp function.
|
||||
|
||||
When shell integration script is loaded, a function named
|
||||
@command{_eat_msg} is defined in your shell. You can use this to send
|
||||
any message to Emacs. (The @samp{_} in the beginning of the function
|
||||
name is intentional to prevent shadowing any actual command.)
|
||||
|
||||
@deffn Command _eat_msg @var{handler-name} @var{message}...
|
||||
Send message @var{message}, handled by the handler named
|
||||
@var{handler-name} in Emacs.
|
||||
@end deffn
|
||||
|
||||
The messages are handled with the handlers defined in
|
||||
@code{eat-message-handler-alist}.
|
||||
|
||||
@vindex eat-message-handler-alist
|
||||
@defopt eat-message-handler-alist
|
||||
Alist of message handler name and its handler function. The keys are
|
||||
the names of message handlers (i.e. the @var{handler-name} argument of
|
||||
@command{_eat_msg}), and the values are their respective handler
|
||||
functions. The handler function is called with the @var{message}
|
||||
arguments of @command{_eat_msg}. Messages with undefined handlers are
|
||||
ignored. To disable message passing, set this to nil.
|
||||
@end defopt
|
||||
|
||||
Beware, messages can be sent by malicious and/or buggy programs
|
||||
running in the shell, therefore you should always verify the message
|
||||
before doing anywhere.
|
||||
|
||||
@anchor{Native Shell Prompt Editing}
|
||||
@cindex native shell prompt editing
|
||||
@cindex shell prompt native editing
|
||||
|
|
|
@ -89,21 +89,13 @@ __eat_enable_integration ()
|
|||
PROMPT_COMMAND+=(__eat_prompt_command)
|
||||
trap '__eat_before_exec' DEBUG
|
||||
# Wrap 'PROMPT_COMMAND' to avoid it getting trapped in 'DEBUG' trap.
|
||||
# Step 1: Append to PROMPT_COMMAND.
|
||||
PROMPT_COMMAND+=(__eat_after_prompt_command)
|
||||
# Step 2: Prepend to PROMPT_COMMAND.
|
||||
# Step 2.1: Move all elements to make the first index free.
|
||||
# Fun fact: Microsoft doesn't still about know this simple trick.
|
||||
# They ended up using something as silly and pityful as
|
||||
# 'VAR=$PROMPT_COMMAND' to copy a Bash array in VSCode Bash
|
||||
# integration script, which simply won't work ever, and then
|
||||
# complain about Bash in the comments! xD
|
||||
for i in $(eval "echo {${#PROMPT_COMMAND[*]}..1..-1}")
|
||||
do
|
||||
PROMPT_COMMAND[$i]=${PROMPT_COMMAND[$((i-1))]}
|
||||
done
|
||||
# Step 2.2: Assign the first element.
|
||||
PROMPT_COMMAND[0]=__eat_before_prompt_command
|
||||
PROMPT_COMMAND+=(__eat_after_prompt_command)
|
||||
PROMPT_COMMAND=(__eat_before_prompt_command "${PROMPT_COMMAND[@]}")
|
||||
# Send the history, for native shell prompt.
|
||||
printf '\e]51;e;I;0;bash;%s;%s\e\\' \
|
||||
"$(printf "%s" "$HOSTNAME" | base64)" \
|
||||
|
@ -117,6 +109,16 @@ __eat_enable_integration ()
|
|||
fi
|
||||
}
|
||||
|
||||
_eat_msg () {
|
||||
local msg=$'\e]51;e;M'
|
||||
for _ in $(eval "echo {1..$#}")
|
||||
do
|
||||
msg="$msg;$(printf "%s" "$1" | base64)"
|
||||
shift
|
||||
done
|
||||
printf "%s\e\\" "$msg"
|
||||
}
|
||||
|
||||
# Enable.
|
||||
if test -z "$__eat_integration_enabled" && \
|
||||
test "${TERM:0:4}" = "eat-"
|
||||
|
|
|
@ -80,6 +80,16 @@ __eat_enable_integration ()
|
|||
fi
|
||||
}
|
||||
|
||||
_eat_msg () {
|
||||
local msg=$'\e]51;e;M'
|
||||
for _ in $(eval "echo {1..$#}")
|
||||
do
|
||||
msg="$msg;$(printf "%s" "$1" | base64)"
|
||||
shift
|
||||
done
|
||||
printf "%s\e\\" "$msg"
|
||||
}
|
||||
|
||||
# Enable.
|
||||
if test -z "$__eat_integration_enabled" && \
|
||||
test "${TERM:0:4}" = "eat-"
|
||||
|
|
Loading…
Add table
Reference in a new issue