all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
From: Augusto Stoffel <arstoffel@gmail.com>
To: Lars Ingebrigtsen <larsi@gnus.org>
Cc: emacs-devel@gnu.org
Subject: Re: OSC control sequences in comint
Date: Mon, 23 Aug 2021 18:46:58 +0200	[thread overview]
Message-ID: <87o89oqfb1.fsf@gmail.com> (raw)
In-Reply-To: <87tujhumuk.fsf@gnus.org> (Lars Ingebrigtsen's message of "Mon, 23 Aug 2021 00:38:11 +0200")

[-- Attachment #1: Type: text/plain, Size: 1246 bytes --]

On Mon, 23 Aug 2021 at 00:38, Lars Ingebrigtsen <larsi@gnus.org> wrote:

> I think it sounds like a good idea.  Could you format it up as a patch?

All right, I have attached a patch.  Since a comint buffer is editable,
I chose an unobtrusive but less convenient keymap to the hyperlink
buttons, based on bug-reference.el: 'C-c RET' opens the links.

Note that there's a call to

    (autoload 'browse-url-button-open "browse-url.el")

in the patch, which is probably not the best procedure.  Should that
function be autoloaded in browse-url.el?

Finally, in case anyone wants to test or play around, a handler for the
OSC 1337 escape (for inline images) could look like this:

    (defun comint-osc-1337-handler (_ text)
      (when (string-match ":" text)
        (insert-image
         (create-image (base64-decode-string (substring text (match-end 0))) nil t))))

Then one can say

    (add-hook 'comint-output-filter-functions 'comint-osc-process-output nil t)
    (push '("1337" . comint-osc-1337-handler) comint-osc-handlers)

and use https://iterm2.com/utilities/imgcat to show (small...) images in
the shell.

However, I don't think it makes sense to provide this handler in Emacs
itself, since it is rather nonstandard.

Best,
Augusto


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Add-support-for-OSC-escape-sequences-in-comint.patch --]
[-- Type: text/x-patch, Size: 5466 bytes --]

From 290107a10b638e41a73509d346336566791e6525 Mon Sep 17 00:00:00 2001
From: Augusto Stoffel <arstoffel@gmail.com>
Date: Mon, 23 Aug 2021 18:03:39 +0200
Subject: [PATCH] Add support for OSC escape sequences in comint

* lisp/comint.el (comint-osc-handlers, comint-osc--marker,
comint-osc-process-output): New general infrastructure to handle OSC
escape sequences.
(comint-osc-hyperlink-map, comint-osc-hyperlink--state,
comint-osc-hyperlink-handler): New functions and variables to handle
OSC 8 (hyperlinks).
---
 etc/NEWS       | 10 ++++++
 lisp/comint.el | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 97 insertions(+)

diff --git a/etc/NEWS b/etc/NEWS
index b008c46291..ac8bec244d 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -3019,6 +3019,16 @@ default are unaffected.)
 states to be maintained if 'so-long-mode' replaces the original major
 mode.  By default, these new options support 'view-mode'.
 
+** Comint
+
+*** Support for OSC escape sequences
+Adding the new 'comint-osc-process-output' to
+'comint-output-filter-functions' enables the interpretation of OSC
+escape sequences in comint buffers.  By default, only OSC 8, for
+hyperlinks, is acted upon.  Adding more entries to
+`comint-osc-handlers' allows a customized treatment of further escape
+sequences.
+
 \f
 * New Modes and Packages in Emacs 28.1
 
diff --git a/lisp/comint.el b/lisp/comint.el
index 7af8e8fd2a..b924029a3b 100644
--- a/lisp/comint.el
+++ b/lisp/comint.el
@@ -3887,6 +3887,93 @@ comint-redirect-results-list-from-process
           ;; don't advance, so ensure forward progress.
 	  (forward-line 1)))
       (nreverse results))))
+
+\f
+;;; OSC escape sequences (operating system commands)
+;;============================================================================
+;; Adding `comint-osc-process-output' to `comint-output-filter-functions'
+;; enables the interpretation of OSC escape sequences.  By default, only
+;; OSC 8, for hyperlinks, is acted upon.  Adding more entries to
+;; `comint-osc-handlers' allows a customized treatment of further sequences.
+
+(defvar-local comint-osc-handlers '(("8" . comint-osc-hyperlink-handler))
+  "Alist of handlers for OSC escape sequences.
+See `comint-osc-process-output' for details.")
+
+(defvar-local comint-osc--marker nil)
+
+(defun comint-osc-process-output (_)
+  "Interpret OSC escape sequences in comint output.
+
+This function is intended to be added to
+`comint-output-filter-functions' in order to interpret escape
+sequences of the forms
+
+    ESC ] command ; text BEL
+    ESC ] command ; text ESC \\
+
+Specifically, every occurrence of such escape sequences is
+removed from the buffer.  Then, if `command' is a key of the
+`comint-osc-handlers' alist, the corresponding value, which
+should be a function, is called with `command' and `text' as
+arguments, with point where the escape sequence was located."
+  (let ((bound (process-mark (get-buffer-process (current-buffer)))))
+    (save-excursion
+      (goto-char (or comint-osc--marker
+                     (and (markerp comint-last-output-start)
+			  (eq (marker-buffer comint-last-output-start)
+			      (current-buffer))
+			  comint-last-output-start)
+                     (point-min)))
+      (when (eq (char-before) ?\e) (backward-char))
+      (while (re-search-forward "\e]" bound t)
+        (let ((pos0 (match-beginning 0))
+              (code (and (re-search-forward "\\=\\([0-9A-Za-z]*\\);" bound t)
+                         (match-string 1)))
+              (pos1 (point)))
+          (if (re-search-forward "\a\\|\e\\\\" bound t)
+              (let ((text (buffer-substring-no-properties pos1 (match-beginning 0))))
+                (setq comint-osc--marker nil)
+                (delete-region pos0 (point))
+                (when-let ((fun (cdr (assoc-string code comint-osc-handlers))))
+                  (funcall fun code text)))
+            (put-text-property pos0 bound 'invisible t)
+            (setq comint-osc--marker (copy-marker pos0))))))))
+
+;; Hyperlink handling (OSC 8)
+
+(autoload 'browse-url-button-open "browse-url.el")
+
+(defvar comint-osc-hyperlink-map
+  (let ((map (make-sparse-keymap)))
+    (define-key map "\C-c\r" 'browse-url-button-open)
+    (define-key map [mouse-2] 'browse-url-button-open)
+    (define-key map [follow-link] 'mouse-face)
+    map)
+  "Keymap used by OSC 8 hyperlink buttons.")
+
+(define-button-type 'comint-osc-hyperlink
+  'keymap comint-osc-hyperlink-map
+  'help-echo (lambda (_ buffer pos)
+               (when-let ((url (get-text-property pos 'browse-url-data buffer)))
+                 (format "mouse-2, C-c RET: Open %s" url))))
+
+(defvar-local comint-osc-hyperlink--state nil)
+
+(defun comint-osc-hyperlink-handler (_ text)
+  "Create a hyperlink from an OSC 8 escape sequence.
+This function is intended to be included as an entry of
+`comint-osc-handlers'."
+  (when comint-osc-hyperlink--state
+    (let ((start (car comint-osc-hyperlink--state))
+          (url (cdr comint-osc-hyperlink--state)))
+      (make-text-button start (point)
+                        'type 'comint-osc-hyperlink
+                        'browse-url-data url)))
+  (setq comint-osc-hyperlink--state
+        (and (string-match ";\\(.+\\)" text)
+             (cons (point-marker) (match-string-no-properties 1 text)))))
+
 \f
 ;;; Converting process modes to use comint mode
 ;;============================================================================
-- 
2.31.1


  reply	other threads:[~2021-08-23 16:46 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-08-22 17:31 OSC control sequences in comint Augusto Stoffel
2021-08-22 22:38 ` Lars Ingebrigtsen
2021-08-23 16:46   ` Augusto Stoffel [this message]
2021-08-25 10:32     ` Lars Ingebrigtsen
2021-08-26  7:44       ` Augusto Stoffel
2021-08-26 14:06         ` Lars Ingebrigtsen
2021-08-28 15:15           ` [PATCH] OSC 7 handler (alternative to shell-dirtrack-mode) Augusto Stoffel
2021-08-29  8:06             ` Michael Albinus
2021-08-29 18:56             ` Lars Ingebrigtsen

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87o89oqfb1.fsf@gmail.com \
    --to=arstoffel@gmail.com \
    --cc=emacs-devel@gnu.org \
    --cc=larsi@gnus.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this external index

	https://git.savannah.gnu.org/cgit/emacs.git
	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.