all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
* OSC control sequences in comint
@ 2021-08-22 17:31 Augusto Stoffel
  2021-08-22 22:38 ` Lars Ingebrigtsen
  0 siblings, 1 reply; 9+ messages in thread
From: Augusto Stoffel @ 2021-08-22 17:31 UTC (permalink / raw)
  To: emacs-devel

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

I would like to suggest adding some (optional) support for "Operating
System Commands" [1] to comint.  (This is unrelated to having Emacs
talk OSC codes with the terminal inside of which its running.)

This class of control sequences serves various random purposes, for
instance adding clickable hyperlinks in terminal applications.  As an
example, compare `ls --hyperlink' in the Emacs shell versus some other
"modern" terminal emulator.

Now, I don't particularly care about those hyperlinks or any other
established use of OSC sequences, and I guess a well-made program will
avoid outputting them to Emacs, since it advertises itself as a dumb
terminal.  But OSCs seem to be good a way to create ad-hoc communication
protocols between Emacs and other programs, say to display images in a
REPL buffer (see [3] for a precedent).

Thus, concretely, the suggestion is to add the
`comint-osc-process-output' function attached below to comint.el or some
other appropriate place.  It would not be added to
`comint-output-filter-functions' by default.  The hyperlink handler is
added as an example, it might be kept or removed.

Anyway, as an illustration, after evaluating the attached file and calling

  (add-hook 'comint-output-filter-functions 'comint-osc-process-output nil t)

in a shell buffer, `ls --hyperlink' should produce clickable
hyperlinks, as it does in other capable terminals.

What do you think?


[-- Attachment #2: comint-osc.el --]
[-- Type: text/plain, Size: 2322 bytes --]

;; -*- lexical-binding: t -*-

(defvar-local comint-osc-handlers '(("8" . comint-osc-8-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 control sequences in comint output.

This function is intended to be added to
`comint-output-filter-functions' and interprets control sequences
of the forms

    `\\e]<name>;<text>\\a'
    `\\e]<name>;<text>\\e\\'

Specifically, every occurrence of such control sequences is
removed from the buffer.  Then, if the alist
`comint-osc-handlers' contains an entry <name>, the corresponding
value, which should be a function, is called with <name> 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

(defvar-local comint-osc-8--state nil)

(defun comint-osc-8-handler (_ text)
  (when comint-osc-8--state
    (let ((start (car comint-osc-8--state))
          (uri (cdr comint-osc-8--state)))
      (require 'shr)
      (shr-urlify start uri)))
  (setq comint-osc-8--state
        (and (string-match ";\\(.+\\)" text)
             (cons (point-marker) (match-string-no-properties 1 text)))))

[-- Attachment #3: Type: text/plain, Size: 213 bytes --]


[1]: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands
[2]: https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda
[3]: https://iterm2.com/documentation-images.html

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2021-08-29 18:56 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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
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

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.