diff options
| author | Philipp Stephani | 2015-05-25 17:03:50 -0400 |
|---|---|---|
| committer | Stefan Monnier | 2015-05-25 17:03:50 -0400 |
| commit | 816a2b369d0490e67fd5a57c9f18bb2c533e80e4 (patch) | |
| tree | 72c6dfa080468e1edcbf8b169577ee8136764a30 | |
| parent | 49c8458d7b7194a7b6f347bf4a730391df74df2b (diff) | |
| download | emacs-816a2b369d0490e67fd5a57c9f18bb2c533e80e4.tar.gz emacs-816a2b369d0490e67fd5a57c9f18bb2c533e80e4.zip | |
* lisp/term/xterm.el: Add gui-get-selection support via OSC-52
(xterm--extra-capabilities-type): Add `getSelection'.
(xterm--query): Add `no-async' argument.
(xterm--init-activate-get-selection): New function.
(terminal-init-xterm): Use it.
(xterm--init-modify-other-keys): Rename from
terminal-init-xterm-modify-other-keys.
(xterm--init-bracketed-paste-mode): Rename from
terminal-init-xterm-bracketed-paste-mode.
(xterm--init-activate-set-selection): Rename from
terminal-init-xterm-activate-set-selection.
(xterm--selection-char): New function.
(gui-backend-set-selection): Use it. Use the &context to only apply
this method in terminals where we enabled the feature.
(gui-backend-get-selection): New method.
| -rw-r--r-- | etc/NEWS | 4 | ||||
| -rw-r--r-- | lisp/term/xterm.el | 117 |
2 files changed, 79 insertions, 42 deletions
| @@ -271,6 +271,10 @@ in the surrounding GUI (using the OSC-52 escape sequence). This only works | |||
| 271 | if your xterm supports it and enables the `allowWindowOps' options (disabled | 271 | if your xterm supports it and enables the `allowWindowOps' options (disabled |
| 272 | by default at least in Debian, for security reasons). | 272 | by default at least in Debian, for security reasons). |
| 273 | 273 | ||
| 274 | Similarly, you can yank the CLIPBOARD/PRIMARY selection (using the OSC-52 | ||
| 275 | escape sequence) if your xterm has the feature enabled but for that you | ||
| 276 | additionally need to add `getSelection' to `xterm-extra-capabilities'. | ||
| 277 | |||
| 274 | ** xterm-mouse-mode now supports mouse-tracking (if your xterm supports it). | 278 | ** xterm-mouse-mode now supports mouse-tracking (if your xterm supports it). |
| 275 | 279 | ||
| 276 | ** package.el | 280 | ** package.el |
diff --git a/lisp/term/xterm.el b/lisp/term/xterm.el index 4e48e80e4e9..f7f80073cd7 100644 --- a/lisp/term/xterm.el +++ b/lisp/term/xterm.el | |||
| @@ -34,6 +34,7 @@ | |||
| 34 | ;; `terminal-init-xterm' as well. | 34 | ;; `terminal-init-xterm' as well. |
| 35 | '(set (const :tag "modifyOtherKeys support" modifyOtherKeys) | 35 | '(set (const :tag "modifyOtherKeys support" modifyOtherKeys) |
| 36 | (const :tag "report background" reportBackground) | 36 | (const :tag "report background" reportBackground) |
| 37 | (const :tag "get X selection" getSelection) | ||
| 37 | (const :tag "set X selection" setSelection))) | 38 | (const :tag "set X selection" setSelection))) |
| 38 | 39 | ||
| 39 | (defcustom xterm-extra-capabilities 'check | 40 | (defcustom xterm-extra-capabilities 'check |
| @@ -45,7 +46,8 @@ If a list, assume that the listed features are supported, without checking. | |||
| 45 | The relevant features are: | 46 | The relevant features are: |
| 46 | modifyOtherKeys -- if supported, more key bindings work (e.g., \"\\C-,\") | 47 | modifyOtherKeys -- if supported, more key bindings work (e.g., \"\\C-,\") |
| 47 | reportBackground -- if supported, Xterm reports its background color | 48 | reportBackground -- if supported, Xterm reports its background color |
| 48 | setSelection -- if supported, Xterm saves yanked text to the X selection" | 49 | getSelection -- if supported, Xterm yanks text from the X selection |
| 50 | setSelection -- if supported, Xterm saves killed text to the X selection" | ||
| 49 | :version "24.1" | 51 | :version "24.1" |
| 50 | :type `(choice (const :tag "Check" check) | 52 | :type `(choice (const :tag "Check" check) |
| 51 | ,xterm--extra-capabilities-type)) | 53 | ,xterm--extra-capabilities-type)) |
| @@ -674,15 +676,19 @@ string bytes that can be copied is 3/4 of this value." | |||
| 674 | ;; introduced) or higher, initialize the | 676 | ;; introduced) or higher, initialize the |
| 675 | ;; modifyOtherKeys support. | 677 | ;; modifyOtherKeys support. |
| 676 | (when (>= version 216) | 678 | (when (>= version 216) |
| 677 | (terminal-init-xterm-modify-other-keys)) | 679 | (xterm--init-modify-other-keys)) |
| 678 | ;; In version 203 support for accessing the X selection was | 680 | ;; In version 203 support for accessing the X selection was |
| 679 | ;; added. Hterm reports itself as version 256 and supports it | 681 | ;; added. Hterm reports itself as version 256 and supports it |
| 680 | ;; as well. gnome-terminal doesn't and is excluded by this | 682 | ;; as well. gnome-terminal doesn't and is excluded by this |
| 681 | ;; test. | 683 | ;; test. |
| 682 | (when (>= version 203) | 684 | (when (>= version 203) |
| 683 | (terminal-init-xterm-activate-set-selection)))))) | 685 | ;; Most xterms seem to have it disabled by default, and if it's |
| 686 | ;; disabled, C-y will incur a timeout, so we only use it if the user | ||
| 687 | ;; explicitly requests it. | ||
| 688 | ;;(xterm--init-activate-get-selection) | ||
| 689 | (xterm--init-activate-set-selection)))))) | ||
| 684 | 690 | ||
| 685 | (defun xterm--query (query handlers) | 691 | (defun xterm--query (query handlers &optional no-async) |
| 686 | "Send QUERY string to the terminal and watch for a response. | 692 | "Send QUERY string to the terminal and watch for a response. |
| 687 | HANDLERS is an alist with elements of the form (STRING . FUNCTION). | 693 | HANDLERS is an alist with elements of the form (STRING . FUNCTION). |
| 688 | We run the first FUNCTION whose STRING matches the input events." | 694 | We run the first FUNCTION whose STRING matches the input events." |
| @@ -690,7 +696,7 @@ We run the first FUNCTION whose STRING matches the input events." | |||
| 690 | ;; rather annoying (bug#6758). Maybe we could always use the asynchronous | 696 | ;; rather annoying (bug#6758). Maybe we could always use the asynchronous |
| 691 | ;; approach, but it's less tested. | 697 | ;; approach, but it's less tested. |
| 692 | ;; FIXME: Merge the two branches. | 698 | ;; FIXME: Merge the two branches. |
| 693 | (if (input-pending-p) | 699 | (if (and (input-pending-p) (not no-async)) |
| 694 | (progn | 700 | (progn |
| 695 | (dolist (handler handlers) | 701 | (dolist (handler handlers) |
| 696 | (define-key input-decode-map (car handler) | 702 | (define-key input-decode-map (car handler) |
| @@ -758,36 +764,73 @@ We run the first FUNCTION whose STRING matches the input events." | |||
| 758 | '(("\e]11;" . xterm--report-background-handler)))) | 764 | '(("\e]11;" . xterm--report-background-handler)))) |
| 759 | 765 | ||
| 760 | (when (memq 'modifyOtherKeys xterm-extra-capabilities) | 766 | (when (memq 'modifyOtherKeys xterm-extra-capabilities) |
| 761 | (terminal-init-xterm-modify-other-keys)) | 767 | (xterm--init-modify-other-keys)) |
| 762 | 768 | ||
| 769 | (when (memq 'getSelection xterm-extra-capabilities) | ||
| 770 | (xterm--init-activate-get-selection)) | ||
| 763 | (when (memq 'setSelection xterm-extra-capabilities) | 771 | (when (memq 'setSelection xterm-extra-capabilities) |
| 764 | (terminal-init-xterm-activate-set-selection))) | 772 | (xterm--init-activate-set-selection))) |
| 765 | 773 | ||
| 766 | ;; Unconditionally enable bracketed paste mode: terminals that don't | 774 | ;; Unconditionally enable bracketed paste mode: terminals that don't |
| 767 | ;; support it just ignore the sequence. | 775 | ;; support it just ignore the sequence. |
| 768 | (terminal-init-xterm-bracketed-paste-mode) | 776 | (xterm--init-bracketed-paste-mode) |
| 769 | 777 | ||
| 770 | (run-hooks 'terminal-init-xterm-hook)) | 778 | (run-hooks 'terminal-init-xterm-hook)) |
| 771 | 779 | ||
| 772 | (defun terminal-init-xterm-modify-other-keys () | 780 | (defun xterm--init-modify-other-keys () |
| 773 | "Terminal initialization for xterm's modifyOtherKeys support." | 781 | "Terminal initialization for xterm's modifyOtherKeys support." |
| 774 | (send-string-to-terminal "\e[>4;1m") | 782 | (send-string-to-terminal "\e[>4;1m") |
| 775 | (push "\e[>4m" (terminal-parameter nil 'tty-mode-reset-strings)) | 783 | (push "\e[>4m" (terminal-parameter nil 'tty-mode-reset-strings)) |
| 776 | (push "\e[>4;1m" (terminal-parameter nil 'tty-mode-set-strings))) | 784 | (push "\e[>4;1m" (terminal-parameter nil 'tty-mode-set-strings))) |
| 777 | 785 | ||
| 778 | (defun terminal-init-xterm-bracketed-paste-mode () | 786 | (defun xterm--init-bracketed-paste-mode () |
| 779 | "Terminal initialization for bracketed paste mode." | 787 | "Terminal initialization for bracketed paste mode." |
| 780 | (send-string-to-terminal "\e[?2004h") | 788 | (send-string-to-terminal "\e[?2004h") |
| 781 | (push "\e[?2004l" (terminal-parameter nil 'tty-mode-reset-strings)) | 789 | (push "\e[?2004l" (terminal-parameter nil 'tty-mode-reset-strings)) |
| 782 | (push "\e[?2004h" (terminal-parameter nil 'tty-mode-set-strings))) | 790 | (push "\e[?2004h" (terminal-parameter nil 'tty-mode-set-strings))) |
| 783 | 791 | ||
| 784 | (defun terminal-init-xterm-activate-set-selection () | 792 | (defun xterm--init-activate-get-selection () |
| 793 | "Terminal initialization for `gui-get-selection'." | ||
| 794 | (set-terminal-parameter nil 'xterm--get-selection t)) | ||
| 795 | |||
| 796 | (defun xterm--init-activate-set-selection () | ||
| 785 | "Terminal initialization for `gui-set-selection'." | 797 | "Terminal initialization for `gui-set-selection'." |
| 786 | (set-terminal-parameter nil 'xterm--set-selection t)) | 798 | (set-terminal-parameter nil 'xterm--set-selection t)) |
| 787 | 799 | ||
| 788 | ;; FIXME: This defines the gui method for all terminals, even tho it only | 800 | (defun xterm--selection-char (type) |
| 789 | ;; supports a subset of them. | 801 | (pcase type |
| 790 | (cl-defmethod gui-backend-set-selection (type data &context (window-system (eql nil))) | 802 | ('PRIMARY "p") |
| 803 | ('CLIPBOARD "c") | ||
| 804 | (_ (error "Invalid selection type: %S" type)))) | ||
| 805 | |||
| 806 | (cl-defmethod gui-backend-get-selection | ||
| 807 | (type data-type | ||
| 808 | &context (window-system (eql nil)) | ||
| 809 | ;; Only applies to terminals which have it enabled. | ||
| 810 | ((terminal-parameter nil 'xterm--get-selection) (eql t))) | ||
| 811 | (unless (eq data-type 'STRING) | ||
| 812 | (error "Unsupported data type %S" data-type)) | ||
| 813 | (let* ((screen (eq (terminal-parameter nil 'terminal-initted) | ||
| 814 | 'terminal-init-screen)) | ||
| 815 | (query (concat "\e]52;" (xterm--selection-char type) ";"))) | ||
| 816 | (with-temp-buffer | ||
| 817 | (set-buffer-multibyte nil) | ||
| 818 | (xterm--query | ||
| 819 | (concat (when screen "\eP") query "?\a" (when screen "\e\\")) | ||
| 820 | (list (cons query (lambda () | ||
| 821 | (while (let ((char (read-char))) | ||
| 822 | (unless (eq char ?\a) | ||
| 823 | (insert char) | ||
| 824 | t)))))) | ||
| 825 | 'no-async) | ||
| 826 | (base64-decode-region (point-min) (point-max)) | ||
| 827 | (decode-coding-region (point-min) (point-max) 'utf-8-unix t)))) | ||
| 828 | |||
| 829 | (cl-defmethod gui-backend-set-selection | ||
| 830 | (type data | ||
| 831 | &context (window-system (eql nil)) | ||
| 832 | ;; Only applies to terminals which have it enabled. | ||
| 833 | ((terminal-parameter nil 'xterm--set-selection) (eql t))) | ||
| 791 | "Copy DATA to the X selection using the OSC 52 escape sequence. | 834 | "Copy DATA to the X selection using the OSC 52 escape sequence. |
| 792 | 835 | ||
| 793 | TYPE specifies which selection to set; it must be either | 836 | TYPE specifies which selection to set; it must be either |
| @@ -808,34 +851,24 @@ program. When inside the screen program, this function also | |||
| 808 | chops long DCS sequences into multiple smaller ones to avoid | 851 | chops long DCS sequences into multiple smaller ones to avoid |
| 809 | hitting screen's max DCS length." | 852 | hitting screen's max DCS length." |
| 810 | (let* ((screen (eq (terminal-parameter nil 'terminal-initted) | 853 | (let* ((screen (eq (terminal-parameter nil 'terminal-initted) |
| 811 | 'terminal-init-screen))) | 854 | 'terminal-init-screen)) |
| 812 | ;; Only do something if the current terminal is actually an XTerm | 855 | (bytes (encode-coding-string data 'utf-8-unix)) |
| 813 | ;; or screen. | 856 | (base-64 (if screen |
| 814 | (when (terminal-parameter nil 'xterm--set-selection) | 857 | (replace-regexp-in-string |
| 815 | (let* ((bytes (encode-coding-string data 'utf-8-unix)) | 858 | "\n" "\e\\\eP" |
| 816 | (base-64 (if screen | 859 | (base64-encode-string bytes) |
| 817 | (replace-regexp-in-string | 860 | :fixedcase :literal) |
| 818 | "\n" "\e\\\eP" | 861 | (base64-encode-string bytes :no-line-break))) |
| 819 | (base64-encode-string bytes) | 862 | (length (length base-64))) |
| 820 | :fixedcase :literal) | 863 | (if (> length xterm-max-cut-length) |
| 821 | (base64-encode-string bytes :no-line-break))) | 864 | (progn |
| 822 | (length (length base-64))) | 865 | (warn "Selection too long to send to terminal: %d bytes" length) |
| 823 | (if (> length xterm-max-cut-length) | 866 | (sit-for 2)) |
| 824 | (progn | 867 | (send-string-to-terminal |
| 825 | (warn "Selection too long to send to terminal: %d bytes" length) | 868 | (concat |
| 826 | (sit-for 2)) | 869 | (when screen "\eP") |
| 827 | (send-string-to-terminal | 870 | "\e]52;" (xterm--selection-char type) ";" base-64 "\a" |
| 828 | (concat | 871 | (when screen "\e\\")))))) |
| 829 | (when screen "\eP") | ||
| 830 | "\e]52;" | ||
| 831 | (pcase type | ||
| 832 | ('PRIMARY "p") | ||
| 833 | ('CLIPBOARD "c") | ||
| 834 | (_ (error "Invalid selection type: %S" type))) | ||
| 835 | ";" | ||
| 836 | base-64 | ||
| 837 | "\a" | ||
| 838 | (when screen "\e\\")))))))) | ||
| 839 | 872 | ||
| 840 | (defun xterm-rgb-convert-to-16bit (prim) | 873 | (defun xterm-rgb-convert-to-16bit (prim) |
| 841 | "Convert an 8-bit primary color value PRIM to a corresponding 16-bit value." | 874 | "Convert an 8-bit primary color value PRIM to a corresponding 16-bit value." |