emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[nongnu] elpa/eat b2ad1be411: Add message passing support


From: ELPA Syncer
Subject: [nongnu] elpa/eat b2ad1be411: Add message passing support
Date: Sun, 17 Sep 2023 12:59:10 -0400 (EDT)

branch: elpa/eat
commit b2ad1be4113f1e1716d2723cab509bb7b8d24105
Author: Akib Azmain Turja <akib@disroot.org>
Commit: Akib Azmain Turja <akib@disroot.org>

    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.
---
 eat.el           | 46 ++++++++++++++++++++++++++++++++++++++++++++--
 eat.texi         | 35 ++++++++++++++++++++++++++++++++++-
 integration/bash | 22 ++++++++++++----------
 integration/zsh  | 10 ++++++++++
 4 files changed, 100 insertions(+), 13 deletions(-)

diff --git a/eat.el b/eat.el
index 4ef38a8e75..c84be7798d 100644
--- a/eat.el
+++ b/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.
     ))
 
diff --git a/eat.texi b/eat.texi
index 767b0c6b81..bfe36d9f79 100644
--- a/eat.texi
+++ b/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
diff --git a/integration/bash b/integration/bash
index e760942dd1..897c11d21a 100644
--- a/integration/bash
+++ b/integration/bash
@@ -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-"
diff --git a/integration/zsh b/integration/zsh
index 28480a1a48..6b7d7ac613 100644
--- a/integration/zsh
+++ b/integration/zsh
@@ -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-"



reply via email to

[Prev in Thread] Current Thread [Next in Thread]