From f0af6dea559e000c90873f30c294ae6ce9a5922a Mon Sep 17 00:00:00 2001
From: Philipp Stephani <phst@google.com>
Date: Thu, 9 Apr 2015 22:05:19 +0200
Subject: [PATCH] Implement OSC-52 functionality for getting the X selection

---
 lisp/term/xterm.el | 41 ++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 40 insertions(+), 1 deletion(-)

diff --git a/lisp/term/xterm.el b/lisp/term/xterm.el
index f4d1a84..695091f 100644
--- a/lisp/term/xterm.el
+++ b/lisp/term/xterm.el
@@ -38,7 +38,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
-  setSelection     -- if supported, Xterm saves yanked text to the X selection"
+  getSelection     -- if supported, Xterm yanks text from the X selection
+  setSelection     -- if supported, Xterm saves killed text to the X selection"
   :version "24.1"
   :group 'xterm
   :type '(choice (const :tag "No" nil)
@@ -47,6 +48,7 @@ The relevant features are:
                  ;; `terminal-init-xterm' as well.
                  (set (const :tag "modifyOtherKeys support" modifyOtherKeys)
                       (const :tag "report background" reportBackground)
+                      (const :tag "get X selection" getSelection)
                       (const :tag "set X selection" setSelection))))
 
 (defcustom xterm-max-cut-length 100000
@@ -644,6 +646,7 @@ string bytes that can be copied is 3/4 of this value."
         ;; as well.  gnome-terminal doesn't and is excluded by this
         ;; test.
         (when (>= version 203)
+          (terminal-init-xterm-activate-get-selection)
           (terminal-init-xterm-activate-set-selection))))))
 
 (defun xterm--query (query handlers)
@@ -725,6 +728,8 @@ We run the first FUNCTION whose STRING matches the input events."
     (when (memq 'modifyOtherKeys xterm-extra-capabilities)
       (terminal-init-xterm-modify-other-keys))
 
+    (when (memq 'getSelection xterm-extra-capabilities)
+      (terminal-init-xterm-activate-get-selection))
     (when (memq 'setSelection xterm-extra-capabilities)
       (terminal-init-xterm-activate-set-selection)))
 
@@ -746,6 +751,13 @@ 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-get-selection ()
+  "Terminal initialization for `gui-get-selection'."
+  ;; All text terminals are represented by the nil GUI type.  We need
+  ;; to detect XTerm again in `xterm--get-selection' using the
+  ;; terminal parameters.
+  (gui-method-define gui-get-selection nil #'xterm--get-selection))
+
 (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
@@ -753,6 +765,33 @@ We run the first FUNCTION whose STRING matches the input events."
   ;; terminal parameters.
   (gui-method-define gui-set-selection nil #'xterm--set-selection))
 
+(defun xterm--get-selection (type data-type)
+  (unless (eq data-type 'STRING)
+    (error "Unsupported data type %S" data-type))
+  (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 ((query (concat
+                    "\e]52;"
+                    (cond
+                     ((eq type 'PRIMARY) "p")
+                     ((eq type 'CLIPBOARD) "c")
+                     (t (error "Invalid type %S" type)))
+                    ";")))
+        (with-temp-buffer
+          (xterm--query
+           (concat (when screen "\eP") query "?\a" (when screen "\e\\"))
+           (list (cons query (lambda ()
+                               (while (let ((char (read-char)))
+                                        (unless (eq char ?\a)
+                                          (insert char)
+                                          t)))))))
+          (base64-decode-region (point-min) (point-max))
+          (buffer-substring-no-properties (point-min) (point-max)))))))
+
 (defun xterm--set-selection (type data)
   "Copy DATA to the X selection using the OSC 52 escape sequence.
 
-- 
2.3.5

