aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--etc/NEWS4
-rw-r--r--lisp/ansi-osc.el (renamed from lisp/osc.el)105
-rw-r--r--lisp/comint.el14
-rw-r--r--test/lisp/ansi-osc-tests.el (renamed from test/lisp/osc-tests.el)12
4 files changed, 68 insertions, 67 deletions
diff --git a/etc/NEWS b/etc/NEWS
index b9c4ef62ceb..ec23f10b1fe 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -2577,12 +2577,12 @@ Enabling this minor mode turns on hiding header material, like
2577'elide-head' does; disabling it shows the header. The commands 2577'elide-head' does; disabling it shows the header. The commands
2578'elide-head' and 'elide-head-show' are now obsolete. 2578'elide-head' and 'elide-head-show' are now obsolete.
2579 2579
2580*** New package osc.el. 2580*** New package ansi-osc.el.
2581Support for OSC ("Operating System Command") escape sequences has been 2581Support for OSC ("Operating System Command") escape sequences has been
2582extracted from comint.el in order to provide interpretation of OSC 2582extracted from comint.el in order to provide interpretation of OSC
2583sequences in compilation buffers. 2583sequences in compilation buffers.
2584 2584
2585Adding the new function 'osc-compilation-filter' to 2585Adding the new function 'ansi-osc-compilation-filter' to
2586'compilation-filter-hook' enables interpretation of OSC escape 2586'compilation-filter-hook' enables interpretation of OSC escape
2587sequences in compilation buffers. By default, all sequences are 2587sequences in compilation buffers. By default, all sequences are
2588filtered out. 2588filtered out.
diff --git a/lisp/osc.el b/lisp/ansi-osc.el
index 14f7fe6a4f3..67a85516281 100644
--- a/lisp/osc.el
+++ b/lisp/ansi-osc.el
@@ -1,4 +1,4 @@
1;;; osc.el --- Support for OSC escape sequences -*- lexical-binding: t; -*- 1;;; ansi-osc.el --- Support for OSC escape sequences -*- lexical-binding: t; -*-
2 2
3;; Copyright (C) 2022 Free Software Foundation, Inc. 3;; Copyright (C) 2022 Free Software Foundation, Inc.
4 4
@@ -26,37 +26,37 @@
26;; Handlers for OSC 2, 7 and 8 (for window title, current directory 26;; Handlers for OSC 2, 7 and 8 (for window title, current directory
27;; and hyperlinks respectively) are provided. 27;; and hyperlinks respectively) are provided.
28 28
29;; The function `osc-compilation-filter' can be added to 29;; The function `ansi-osc-compilation-filter' can be added to
30;; `compilation-filter-hook' to collect OSC sequences in compilation 30;; `compilation-filter-hook' to collect OSC sequences in compilation
31;; buffers. The variable `osc-for-compilation-buffer' tells what to 31;; buffers. The variable `ansi-osc-for-compilation-buffer' tells what
32;; do with collected sequences. 32;; to do with collected sequences.
33 33
34;;; Code: 34;;; Code:
35 35
36(defconst osc-control-seq-regexp 36(defconst ansi-osc-control-seq-regexp
37 ;; See ECMA 48, section 8.3.89 "OSC - OPERATING SYSTEM COMMAND". 37 ;; See ECMA 48, section 8.3.89 "OSC - OPERATING SYSTEM COMMAND".
38 "\e\\][\x08-\x0D]*[\x20-\x7E]*\\(\a\\|\e\\\\\\)" 38 "\e\\][\x08-\x0D]*[\x20-\x7E]*\\(\a\\|\e\\\\\\)"
39 "Regexp matching an OSC control sequence.") 39 "Regexp matching an OSC control sequence.")
40 40
41(defun osc-filter-region (begin end) 41(defun ansi-osc-filter-region (begin end)
42 "Filter out all OSC control sequences from region between BEGIN and END." 42 "Filter out all OSC control sequences from region between BEGIN and END."
43 (save-excursion 43 (save-excursion
44 (goto-char begin) 44 (goto-char begin)
45 ;; Delete escape sequences. 45 ;; Delete escape sequences.
46 (while (re-search-forward osc-control-seq-regexp end t) 46 (while (re-search-forward ansi-osc-control-seq-regexp end t)
47 (delete-region (match-beginning 0) (match-end 0))))) 47 (delete-region (match-beginning 0) (match-end 0)))))
48 48
49(defvar-local osc-handlers '(("2" . osc-window-title-handler) 49(defvar-local ansi-osc-handlers '(("2" . ansi-osc-window-title-handler)
50 ("7" . osc-directory-tracker) 50 ("7" . ansi-osc-directory-tracker)
51 ("8" . osc-hyperlink-handler)) 51 ("8" . ansi-osc-hyperlink-handler))
52 "Alist of handlers for OSC escape sequences. 52 "Alist of handlers for OSC escape sequences.
53See `osc-apply-on-region' for details.") 53See `ansi-osc-apply-on-region' for details.")
54 54
55(defvar-local osc--marker nil) 55(defvar-local ansi-osc--marker nil)
56;; The function `osc-apply-on-region' can set `osc--marker' to the start 56;; The function `ansi-osc-apply-on-region' can set `ansi-osc--marker'
57;; position of an escape sequence without termination. 57;; to the start position of an escape sequence without termination.
58 58
59(defun osc-apply-on-region (begin end) 59(defun ansi-osc-apply-on-region (begin end)
60 "Interpret OSC escape sequences in region between BEGIN and END. 60 "Interpret OSC escape sequences in region between BEGIN and END.
61This function searches for escape sequences of the forms 61This function searches for escape sequences of the forms
62 62
@@ -64,12 +64,13 @@ This function searches for escape sequences of the forms
64 ESC ] command ; text ESC \\ 64 ESC ] command ; text ESC \\
65 65
66Every occurrence of such escape sequences is removed from the 66Every occurrence of such escape sequences is removed from the
67buffer. Then, if `command' is a key in the alist that is the value 67buffer. Then, if `command' is a key in the alist that is the
68of the local variable `osc-handlers', that key's value, which should 68value of the local variable `ansi-osc-handlers', that key's
69be a function, is called with `command' and `text' as arguments, with 69value, which should be a function, is called with `command' and
70point where the escape sequence was located." 70`text' as arguments, with point where the escape sequence was
71located."
71 (save-excursion 72 (save-excursion
72 (goto-char (or osc--marker begin)) 73 (goto-char (or ansi-osc--marker begin))
73 (when (eq (char-before) ?\e) (backward-char)) 74 (when (eq (char-before) ?\e) (backward-char))
74 (while (re-search-forward "\e]" end t) 75 (while (re-search-forward "\e]" end t)
75 (let ((pos0 (match-beginning 0)) 76 (let ((pos0 (match-beginning 0))
@@ -79,35 +80,35 @@ point where the escape sequence was located."
79 (if (re-search-forward "\a\\|\e\\\\" end t) 80 (if (re-search-forward "\a\\|\e\\\\" end t)
80 (let ((text (buffer-substring-no-properties 81 (let ((text (buffer-substring-no-properties
81 pos1 (match-beginning 0)))) 82 pos1 (match-beginning 0))))
82 (setq osc--marker nil) 83 (setq ansi-osc--marker nil)
83 (delete-region pos0 (point)) 84 (delete-region pos0 (point))
84 (when-let ((fun (cdr (assoc-string code osc-handlers)))) 85 (when-let ((fun (cdr (assoc-string code ansi-osc-handlers))))
85 (funcall fun code text))) 86 (funcall fun code text)))
86 (put-text-property pos0 end 'invisible t) 87 (put-text-property pos0 end 'invisible t)
87 (setq osc--marker (copy-marker pos0))))))) 88 (setq ansi-osc--marker (copy-marker pos0)))))))
88 89
89;; Window title handling (OSC 2) 90;; Window title handling (OSC 2)
90 91
91(defvar-local osc-window-title nil) 92(defvar-local ansi-osc-window-title nil)
92(defun osc-window-title-handler (_ text) 93(defun ansi-osc-window-title-handler (_ text)
93 "Set value of `osc-window-title' from an OSC 2 escape sequence. 94 "Set value of `ansi-osc-window-title' from an OSC 2 escape sequence.
94The variable `osc-window-title' can then be referenced in 95The variable `ansi-osc-window-title' can then be referenced in
95`frame-title-format' to dynamically set the frame title. 96`frame-title-format' to dynamically set the frame title.
96 97
97This function is intended to be included as an element of the 98This function is intended to be included as an element of the
98list that is the value of `osc-handlers'." 99list that is the value of `ansi-osc-handlers'."
99 (setq osc-window-title text)) 100 (setq ansi-osc-window-title text))
100 101
101;; Current directory tracking (OSC 7) 102;; Current directory tracking (OSC 7)
102 103
103(declare-function url-host "url/url-parse.el") 104(declare-function url-host "url/url-parse.el")
104(declare-function url-type "url/url-parse.el") 105(declare-function url-type "url/url-parse.el")
105(declare-function url-filename "url/url-parse.el") 106(declare-function url-filename "url/url-parse.el")
106(defun osc-directory-tracker (_ text) 107(defun ansi-osc-directory-tracker (_ text)
107 "Update `default-directory' from OSC 7 escape sequences. 108 "Update `default-directory' from OSC 7 escape sequences.
108 109
109This function is intended to be included as an element of the 110This function is intended to be included as an element of the
110the list that is the value of `osc-handlers'. You should arrange 111the list that is the value of `ansi-osc-handlers'. You should arrange
111for your shell to print the appropriate escape sequence at each prompt, 112for your shell to print the appropriate escape sequence at each prompt,
112such as with the following command: 113such as with the following command:
113 114
@@ -124,7 +125,7 @@ and `shell-dirtrack-mode'."
124 125
125;; Hyperlink handling (OSC 8) 126;; Hyperlink handling (OSC 8)
126 127
127(defvar osc-hyperlink-map 128(defvar ansi-osc-hyperlink-map
128 (let ((map (make-sparse-keymap))) 129 (let ((map (make-sparse-keymap)))
129 (define-key map "\C-c\r" 'browse-url-button-open) 130 (define-key map "\C-c\r" 'browse-url-button-open)
130 (define-key map [mouse-2] 'browse-url-button-open) 131 (define-key map [mouse-2] 'browse-url-button-open)
@@ -132,29 +133,29 @@ and `shell-dirtrack-mode'."
132 map) 133 map)
133 "Keymap used by OSC 8 hyperlink buttons.") 134 "Keymap used by OSC 8 hyperlink buttons.")
134 135
135(define-button-type 'osc-hyperlink 136(define-button-type 'ansi-osc-hyperlink
136 'keymap osc-hyperlink-map 137 'keymap ansi-osc-hyperlink-map
137 'help-echo (lambda (_ buffer pos) 138 'help-echo (lambda (_ buffer pos)
138 (when-let ((url (get-text-property pos 'browse-url-data buffer))) 139 (when-let ((url (get-text-property pos 'browse-url-data buffer)))
139 (format "mouse-2, C-c RET: Open %s" url)))) 140 (format "mouse-2, C-c RET: Open %s" url))))
140 141
141(defvar-local osc-hyperlink--state nil) 142(defvar-local ansi-osc-hyperlink--state nil)
142 143
143(defun osc-hyperlink-handler (_ text) 144(defun ansi-osc-hyperlink-handler (_ text)
144 "Create a hyperlink from an OSC 8 escape sequence. 145 "Create a hyperlink from an OSC 8 escape sequence.
145This function is intended to be included as an elemnt of the list 146This function is intended to be included as an elemnt of the list
146that is the value of `osc-handlers'." 147that is the value of `ansi-osc-handlers'."
147 (when osc-hyperlink--state 148 (when ansi-osc-hyperlink--state
148 (let ((start (car osc-hyperlink--state)) 149 (let ((start (car ansi-osc-hyperlink--state))
149 (url (cdr osc-hyperlink--state))) 150 (url (cdr ansi-osc-hyperlink--state)))
150 (make-text-button start (point) 151 (make-text-button start (point)
151 'type 'osc-hyperlink 152 'type 'ansi-osc-hyperlink
152 'browse-url-data url))) 153 'browse-url-data url)))
153 (setq osc-hyperlink--state 154 (setq ansi-osc-hyperlink--state
154 (and (string-match ";\\(.+\\)" text) 155 (and (string-match ";\\(.+\\)" text)
155 (cons (point-marker) (match-string-no-properties 1 text))))) 156 (cons (point-marker) (match-string-no-properties 1 text)))))
156 157
157(defcustom osc-for-compilation-buffer 'filter 158(defcustom ansi-osc-for-compilation-buffer 'filter
158 "What to do with OSC escape sequences in compilation output. 159 "What to do with OSC escape sequences in compilation output.
159 160
160If nil, do nothing. 161If nil, do nothing.
@@ -162,9 +163,9 @@ If nil, do nothing.
162If the symbol `filter', then filter out all OSC control sequences. 163If the symbol `filter', then filter out all OSC control sequences.
163 164
164If any other non-nil value, then collect OSC control sequences 165If any other non-nil value, then collect OSC control sequences
165and call the appropriate handlers as described in `osc-handlers'. 166and call the appropriate handlers as described in `ansi-osc-handlers'.
166 167
167In order for this to have any effect, `osc-compilation-filter' 168In order for this to have any effect, `ansi-osc-compilation-filter'
168must be in `compilation-filter-hook'." 169must be in `compilation-filter-hook'."
169 :type '(choice (const :tag "Do nothing" nil) 170 :type '(choice (const :tag "Do nothing" nil)
170 (const :tag "Filter out OSC" filter) 171 (const :tag "Filter out OSC" filter)
@@ -175,17 +176,17 @@ must be in `compilation-filter-hook'."
175(defvar compilation-filter-start) 176(defvar compilation-filter-start)
176 177
177;;;###autoload 178;;;###autoload
178(defun osc-compilation-filter () 179(defun ansi-osc-compilation-filter ()
179 "Maybe collect OSC control sequences. 180 "Maybe collect OSC control sequences.
180This function depends on the variable `osc-for-compilation-buffer', 181This function depends on the variable `ansi-osc-for-compilation-buffer',
181and is meant to be used in `compilation-filter-hook'." 182and is meant to be used in `compilation-filter-hook'."
182 (let ((inhibit-read-only t)) 183 (let ((inhibit-read-only t))
183 (pcase osc-for-compilation-buffer 184 (pcase ansi-osc-for-compilation-buffer
184 ('nil nil) 185 ('nil nil)
185 ('filter 186 ('filter
186 (osc-filter-region compilation-filter-start (point))) 187 (ansi-osc-filter-region compilation-filter-start (point)))
187 (_ 188 (_
188 (osc-apply-on-region compilation-filter-start (point)))))) 189 (ansi-osc-apply-on-region compilation-filter-start (point))))))
189 190
190(provide 'osc) 191(provide 'ansi-osc)
191;;; osc.el ends here 192;;; ansi-osc.el ends here
diff --git a/lisp/comint.el b/lisp/comint.el
index a70a75c6487..b1f3ad8259d 100644
--- a/lisp/comint.el
+++ b/lisp/comint.el
@@ -103,7 +103,7 @@
103 103
104(require 'ring) 104(require 'ring)
105(require 'ansi-color) 105(require 'ansi-color)
106(require 'osc) 106(require 'ansi-osc)
107(require 'regexp-opt) ;For regexp-opt-charset. 107(require 'regexp-opt) ;For regexp-opt-charset.
108(eval-when-compile (require 'subr-x)) 108(eval-when-compile (require 'subr-x))
109 109
@@ -3918,11 +3918,11 @@ REGEXP-GROUP is the regular expression group in REGEXP to use."
3918;; sequences. 3918;; sequences.
3919 3919
3920;; Aliases defined for reverse compatibility 3920;; Aliases defined for reverse compatibility
3921(defvaralias 'comint-osc-handlers 'osc-handlers) 3921(defvaralias 'comint-osc-handlers 'ansi-osc-handlers)
3922(defalias 'comint-osc-directory-tracker 'osc-directory-tracker) 3922(defalias 'comint-osc-directory-tracker 'ansi-osc-directory-tracker)
3923(defalias 'comint-osc-hyperlink-handler 'osc-hyperlink-handler) 3923(defalias 'comint-osc-hyperlink-handler 'ansi-osc-hyperlink-handler)
3924(defalias 'comint-osc-hyperlink 'osc-hyperlink) 3924(defalias 'comint-osc-hyperlink 'ansi-osc-hyperlink)
3925(defvaralias 'comint-osc-hyperlink-map 'osc-hyperlink-map) 3925(defvaralias 'comint-osc-hyperlink-map 'ansi-osc-hyperlink-map)
3926 3926
3927(defun comint-osc-process-output (_) 3927(defun comint-osc-process-output (_)
3928 "Interpret OSC escape sequences in comint output. 3928 "Interpret OSC escape sequences in comint output.
@@ -3941,7 +3941,7 @@ arguments, with point where the escape sequence was located."
3941 (let ((start (1- comint-last-output-start)) 3941 (let ((start (1- comint-last-output-start))
3942 ;; Start one char before last output to catch a possibly stray ESC 3942 ;; Start one char before last output to catch a possibly stray ESC
3943 (bound (process-mark (get-buffer-process (current-buffer))))) 3943 (bound (process-mark (get-buffer-process (current-buffer)))))
3944 (osc-apply-on-region start bound))) 3944 (ansi-osc-apply-on-region start bound)))
3945 3945
3946 3946
3947;;; Input fontification and indentation through an indirect buffer 3947;;; Input fontification and indentation through an indirect buffer
diff --git a/test/lisp/osc-tests.el b/test/lisp/ansi-osc-tests.el
index d53bab08d3d..b3d66fb036c 100644
--- a/test/lisp/osc-tests.el
+++ b/test/lisp/ansi-osc-tests.el
@@ -26,10 +26,10 @@
26 26
27;;; Code: 27;;; Code:
28 28
29(require 'osc) 29(require 'ansi-osc)
30(require 'ert) 30(require 'ert)
31 31
32(defvar osc-tests--strings 32(defvar ansi-osc-tests--strings
33 `( 33 `(
34 ("Hello World" "Hello World") 34 ("Hello World" "Hello World")
35 35
@@ -48,10 +48,10 @@
48;; Don't output those strings to stdout since they may have 48;; Don't output those strings to stdout since they may have
49;; side-effects on the environment 49;; side-effects on the environment
50 50
51(ert-deftest osc-tests-apply-region-no-handlers () 51(ert-deftest ansi-osc-tests-apply-region-no-handlers ()
52 (let ((osc-handlers nil)) 52 (let ((ansi-osc-handlers nil))
53 (pcase-dolist (`(,input ,text) osc-tests--strings) 53 (pcase-dolist (`(,input ,text) ansi-osc-tests--strings)
54 (with-temp-buffer 54 (with-temp-buffer
55 (insert input) 55 (insert input)
56 (osc-apply-on-region (point-min) (point-max)) 56 (ansi-osc-apply-on-region (point-min) (point-max))
57 (should (equal (buffer-string) text)))))) 57 (should (equal (buffer-string) text))))))