Add support for OSC escape codes in comint
* doc/emacs/misc.texi (Shell Mode): Document it. * lisp/comint.el (comint-osc-handlers, comint-osc--marker): New variables. (comint-osc-process-output): New function. (comint-osc-hyperlink-map): New map. (comint-osc-hyperlink-handler): New function.
This commit is contained in:
parent
64b4c85637
commit
630a13ac46
4 changed files with 114 additions and 4 deletions
|
@ -1113,6 +1113,19 @@ subshell:
|
|||
@end example
|
||||
@end table
|
||||
|
||||
By default, Shell mode handles common @acronym{ANSI} escape codes (for
|
||||
instance, for changing the color of text). Emacs also optionally
|
||||
supports some extend escape codes, like some of the @acronym{OSC}
|
||||
(Operating System Codes) if you put the following in your init file:
|
||||
|
||||
@lisp
|
||||
(add-hook 'comint-output-filter-functions 'comint-osc-process-output)
|
||||
@end lisp
|
||||
|
||||
With this enabled, the output from, for instance, @code{ls
|
||||
--hyperlink} will be made into clickable buttons in the Shell mode
|
||||
buffer.
|
||||
|
||||
@cindex Comint mode
|
||||
@cindex mode, Comint
|
||||
Shell mode is a derivative of Comint mode, a general-purpose mode for
|
||||
|
|
19
etc/NEWS
19
etc/NEWS
|
@ -1561,10 +1561,6 @@ If non-nil, 'shell-mode' handles implicit "cd" commands, changing the
|
|||
directory if the command is a directory. Useful for shells like "zsh"
|
||||
that has this feature.
|
||||
|
||||
+++
|
||||
*** 'comint-delete-output' can now save deleted text in the kill-ring.
|
||||
Interactively, 'C-u C-c C-o' triggers this new optional behavior.
|
||||
|
||||
** Eshell
|
||||
|
||||
---
|
||||
|
@ -3026,6 +3022,21 @@ 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
|
||||
("Operating System Command") 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.
|
||||
|
||||
+++
|
||||
*** 'comint-delete-output' can now save deleted text in the kill-ring.
|
||||
Interactively, 'C-u C-c C-o' triggers this new optional behavior.
|
||||
|
||||
|
||||
* New Modes and Packages in Emacs 28.1
|
||||
|
||||
|
|
|
@ -3887,6 +3887,91 @@ REGEXP-GROUP is the regular expression group in REGEXP to use."
|
|||
;; don't advance, so ensure forward progress.
|
||||
(forward-line 1)))
|
||||
(nreverse results))))
|
||||
|
||||
|
||||
;;; 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)
|
||||
|
||||
(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)))))
|
||||
|
||||
|
||||
;;; Converting process modes to use comint mode
|
||||
;;============================================================================
|
||||
|
|
|
@ -1780,6 +1780,7 @@ clickable and will use `browse-url' to open the URLs in question."
|
|||
category browse-url
|
||||
browse-url-data ,(match-string 0)))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun browse-url-button-open (&optional external mouse-event)
|
||||
"Follow the link under point using `browse-url'.
|
||||
If EXTERNAL (the prefix if used interactively), open with the
|
||||
|
|
Loading…
Add table
Reference in a new issue