Commit 2b2fd396 authored by Philipp Stephani's avatar Philipp Stephani Committed by Stefan Monnier
Browse files

xterm.el: Implement OSC-52 functionality for setting the X selection

* lisp/term/xterm.el (xterm-max-cut-length): New var.
(xterm--set-selection, terminal-init-xterm-activate-set-selection): New funs.
(terminal-init-xterm, xterm--version-handler): Use them.
parent a2f9da45
......@@ -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
setSelection -- 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 "set X selection" setSelection))))
(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)
;; 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)
(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)
(when (memq 'setSelection xterm-extra-capabilities)
;; Unconditionally enable bracketed paste mode: terminals that don't
;; support it just ignore the sequence.
......@@ -719,6 +746,64 @@ 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-set-selection ()
"Terminal initialization for `gui-set-selection'."
;; All text terminals are represented by the nil GUI type. We need
;; to detect XTerm again in `xterm--set-selection' using the
;; terminal parameters.
(gui-method-define gui-set-selection nil #'xterm--set-selection))
(defun xterm--set-selection (type data)
"Copy DATA to the X selection using the OSC 52 escape sequence.
TYPE specifies which selection to set; it must be either
`PRIMARY' or `CLIPBOARD'. DATA must be a string.
This can be used as a `gui-set-selection' method for
xterm-compatible terminal emulators. Then 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
This function either sends a raw OSC 52 sequence or wraps the OSC
52 in a Device Control String sequence. This way, it will work
on a bare terminal emulators as well as inside the screen
program. When inside the screen program, this function also
chops long DCS sequences into multiple smaller ones to avoid
hitting screen's max DCS length."
(let* ((init-function (terminal-parameter nil 'terminal-initted))
(xterm (eq init-function 'terminal-init-xterm))
(screen (eq init-function 'terminal-init-screen)))
;; Only do something if the current terminal is actually an XTerm
;; or screen.
(when (or xterm screen)
(let* ((bytes (encode-coding-string data 'utf-8-unix))
(base-64 (if screen
"\n" "\e\\\eP"
(base64-encode-string bytes)
:fixedcase :literal)
(base64-encode-string bytes :no-line-break)))
(length (string-bytes base-64)))
(if (> length xterm-max-cut-length)
(warn "Selection too long to send to terminal: %d bytes" length)
(sit-for 2))
(when screen "\eP")
((eq type 'PRIMARY) "p")
((eq type 'CLIPBOARD) "c")
(t (error "Invalid type %S" type)))
(when screen "\e\\"))))))))
;; Set up colors, for those versions of xterm that support it.
(defvar xterm-standard-colors
;; The names in the comments taken from in the xterm
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment