From 06019ced7d34dade2d40d97605f6b2c1962fe67a Mon Sep 17 00:00:00 2001 From: Philipp Stephani Date: Fri, 27 Feb 2015 19:51:01 +0100 Subject: [PATCH] Add support for OSC 52. This is an xterm escape sequence to save text to the X clipboard. Taken from https://github.com/chromium/hterm/blob/64b3819692526f41eb960f6c9444c2c58e658f79/etc/osc52.el. --- lisp/term/xterm.el | 95 +++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 91 insertions(+), 4 deletions(-) diff --git a/lisp/term/xterm.el b/lisp/term/xterm.el index 519f691..2cfc36d 100644 --- a/lisp/term/xterm.el +++ b/lisp/term/xterm.el @@ -37,7 +37,8 @@ If a list, assume that the listed features are supported, without checking. The relevant features are: modifyOtherKeys -- if supported, more key bindings work (e.g., \"\\C-,\") - reportBackground -- if supported, Xterm reports its background color" + reportBackground -- if supported, Xterm reports its background color + interprogramCut -- if supported, Xterm saves yanked text to the X selection" :version "24.1" :group 'xterm :type '(choice (const :tag "No" nil) @@ -45,7 +46,24 @@ The relevant features are: ;; NOTE: If you add entries here, make sure to update ;; `terminal-init-xterm' as well. (set (const :tag "modifyOtherKeys support" modifyOtherKeys) - (const :tag "report background" reportBackground)))) + (const :tag "report background" reportBackground) + (const :tag "X selection cut" interprogramCut)))) + +(defcustom xterm-max-cut-length 100000 + "Maximum number of bytes to cut into xterm using the OSC 52 sequence. + +The OSC 52 sequence requires a terminator byte. Some terminals will ignore or +mistreat a terminated sequence that is longer than a certain size, usually to +protect users from runaway sequences. + +This variable allows you to tweak the maximum number of bytes that will be sent +using the OSC 52 sequence. + +If you select a region larger than this size, it won't be copied to your system +clipboard. Since clipboard data is base 64 encoded, the actual number of +string bytes that can be copied is 3/4 of this value." + :group 'xterm + :type 'integer) (defconst xterm-paste-ending-sequence "\e[201~" "Characters send by the terminal to end a bracketed paste.") @@ -620,7 +638,13 @@ The relevant features are: ;; introduced) or higher, initialize the ;; modifyOtherKeys support. (when (>= version 216) - (terminal-init-xterm-modify-other-keys)))))) + (terminal-init-xterm-modify-other-keys)) + ;; In version 203 support for accessing the X selection was + ;; added. Hterm reports itself as version 256 and supports it + ;; as well. gnome-terminal doesn't and is excluded by this + ;; test. + (when (>= version 203) + (terminal-init-xterm-activate-interprogram-cut)))))) (defun xterm--query (query handlers) "Send QUERY string to the terminal and watch for a response. @@ -699,7 +723,10 @@ We run the first FUNCTION whose STRING matches the input events." '(("\e]11;" . xterm--report-background-handler)))) (when (memq 'modifyOtherKeys xterm-extra-capabilities) - (terminal-init-xterm-modify-other-keys))) + (terminal-init-xterm-modify-other-keys)) + + (when (memq 'interprogramCut xterm-extra-capabilities) + (terminal-init-xterm-activate-interprogram-cut))) ;; Unconditionally enable bracketed paste mode: terminals that don't ;; support it just ignore the sequence. @@ -719,6 +746,66 @@ We run the first FUNCTION whose STRING matches the input events." (push "\e[?2004l" (terminal-parameter nil 'tty-mode-reset-strings)) (push "\e[?2004h" (terminal-parameter nil 'tty-mode-set-strings))) +(defun terminal-init-xterm-activate-interprogram-cut () + "Terminal initialization for interprogram cut." + (setq interprogram-cut-function + (if (string-prefix-p "screen" (getenv "TERM")) + #'xterm--screen-interprogram-cut + #'xterm--interprogram-cut))) + +(defun xterm--interprogram-cut (text) + "Copy TEXT to the X selection using the OSC 52 escape sequence. + +Set `interprogram-cut-function' to this when using a compatible terminal, and +your system clipboard will be updated whenever you copy a region of text in +Emacs. + +If the resulting OSC 52 sequence would be longer than +`xterm-max-cut-length', then the TEXT is not sent to the system +clipboard. + +This function sends a raw OSC 52 sequence and will work on a bare terminal +emulators. It does not work on screen or tmux terminals, since they don't +natively support OSC 52; use `xterm--screen-interprogram-cut' for that." + (xterm--interprogram-cut-bytes + (base64-encode-string text :no-line-break))) + +(defun xterm--screen-interprogram-cut (text) + "Copy TEXT to the X selection using the OSC 52 escape sequence, for screen users. + +Set `interprogram-cut-function' to this when using the screen program, and your +system clipboard will be updated whenever you copy a region of text in Emacs. + +If the resulting OSC 52 sequence would be longer than +`xterm-max-cut-length', then the STRING is not sent to the system +clipboard. + +This function wraps the OSC 52 in a Device Control String sequence. This causes +screen to pass the wrapped OSC 52 sequence along to the host terminal. This +function also chops long DCS sequences into multiple smaller ones to avoid +hitting screen's max DCS length." + (xterm--interprogram-cut-bytes + (replace-regexp-in-string + "\n" "\e\\\eP" (base64-encode-string text) :fixedcase :literal) + "\eP" "\e\\")) + +(defun xterm--interprogram-cut-bytes (bytes &optional dcs-start dcs-end) + (let ((length (string-bytes bytes))) + (if (> length xterm-max-cut-length) + (progn + (warn "Selection too long to send to terminal: %d bytes" length) + (sit-for 2)) + (send-string-to-terminal + (concat + dcs-start + "\e]52;" + (when select-enable-clipboard "c") + (when select-enable-primary "p") + ";" + bytes + "\a" + dcs-end))))) + ;; Set up colors, for those versions of xterm that support it. (defvar xterm-standard-colors ;; The names in the comments taken from XTerm-col.ad in the xterm -- 2.2.0.rc0.207.ga3a616c