all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
* Patch for supporting tmux
@ 2016-03-29  9:08 Philipp Stephani
  0 siblings, 0 replies; only message in thread
From: Philipp Stephani @ 2016-03-29  9:08 UTC (permalink / raw
  To: Emacs developers


[-- Attachment #1.1: Type: text/plain, Size: 312 bytes --]

Hi,

currently xterm.el selection access supports GNU screen, but not tmux. I've
attached a patch to refactor the detection code somewhat (so that
multiplexers are always detected) and added support for X selection access
in tmux (rather simple, requires just a different wrapping sequence for the
OSC command).

[-- Attachment #1.2: Type: text/html, Size: 362 bytes --]

[-- Attachment #2: 0001-Add-some-support-for-tmux-in-XTerm.patch --]
[-- Type: application/octet-stream, Size: 21560 bytes --]

From e5636a16f7805552cdd5a76b6ace531c258d6870 Mon Sep 17 00:00:00 2001
From: Philipp Stephani <phst@google.com>
Date: Tue, 29 Mar 2016 10:37:05 +0200
Subject: [PATCH] Add some support for tmux in XTerm
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Have xterm.el identify the terminal so that multiplexers are detected
more reliably.  Allow tmux to access the X selection (requires a
different wrapper than GNU screen).

* term/xterm.el (xterm-screen-extra-capabilities): Moved from
term/screen.el; use setSelection by default.
(xterm-tmux-extra-capabilities): New customization option.
(xterm--extra-capabilities, xterm--identify)
(xterm--identification, xterm--handle-identification)
(xterm--parse-identification, xterm--wrap-selection-query): New
helper functions.
(terminal-init-xterm): Always query terminal emulator/multiplexer
version, store in new terminal parameter ‘xterm-identification.’
(gui-backend-get-selection, gui-backend-set-selection): Use helper
functions and new terminal parameter.
* term/screen.el: Delete file.
* faces.el (term-file-aliases): Treat GNU screen and tmux as alias
of XTerm.
* xterm-tests.el: Add test file.
---
 lisp/faces.el                 |   1 +
 lisp/term/screen.el           |  23 ----
 lisp/term/xterm.el            | 254 ++++++++++++++++++++++++++++++------------
 test/automated/xterm-tests.el |  97 ++++++++++++++++
 4 files changed, 278 insertions(+), 97 deletions(-)
 delete mode 100644 lisp/term/screen.el
 create mode 100644 test/automated/xterm-tests.el

diff --git a/lisp/faces.el b/lisp/faces.el
index 612bd16..adde7e9 100644
--- a/lisp/faces.el
+++ b/lisp/faces.el
@@ -46,6 +46,7 @@ term-file-aliases
     ("vt320" . "vt200")
     ("vt400" . "vt200")
     ("vt420" . "vt200")
+    ("screen" . "xterm")
     )
   "Alist of terminal type aliases.
 Entries are of the form (TYPE . ALIAS), where both elements are strings.
diff --git a/lisp/term/screen.el b/lisp/term/screen.el
deleted file mode 100644
index 7f68115..0000000
--- a/lisp/term/screen.el
+++ /dev/null
@@ -1,23 +0,0 @@
-;;; screen.el --- terminal initialization for screen and tmux  -*- lexical-binding: t -*-
-;; Copyright (C) 1995, 2001-2016 Free Software Foundation, Inc.
-
-(require 'term/xterm)
-
-(defcustom xterm-screen-extra-capabilities '(modifyOtherKeys)
-  "Extra capabilities supported under \"screen\".
-Some features of screen depend on the terminal emulator in which
-it runs, which can change when the screen session is moved to another tty."
-  :version "25.1"
-  :type xterm--extra-capabilities-type
-  :group 'xterm)
-
-(defun terminal-init-screen ()
-  "Terminal initialization function for screen."
-  ;; Treat a screen terminal similar to an xterm, but don't use
-  ;; xterm-extra-capabilities's `check' setting since that doesn't seem
-  ;; to work so well (it depends too much on the surrounding terminal
-  ;; emulator, which can change during the session, bug#20356).
-  (let ((xterm-extra-capabilities xterm-screen-extra-capabilities))
-    (tty-run-terminal-initialization (selected-frame) "xterm")))
-
-;; screen.el ends here
diff --git a/lisp/term/xterm.el b/lisp/term/xterm.el
index e06423c..284855c 100644
--- a/lisp/term/xterm.el
+++ b/lisp/term/xterm.el
@@ -22,8 +22,24 @@
 
 ;;; Commentary:
 
+;; Integration with XTerm and terminal emulators and multiplexers
+;; compatible with XTerm.  This file has some partial knowledge about
+;; the following terminal emulators and multiplexers:
+;;
+;; - XTerm
+;; - Gnome Terminal
+;; - Terminal.app
+;; - HTerm
+;; - GNU screen
+;; - tmux
+;;
+;; XTerm control sequences are documented at
+;; http://invisible-island.net/xterm/ctlseqs/ctlseqs.html.
+
 ;;; Code:
 
+(require 'subr-x)
+
 (defgroup xterm nil
   "XTerm support."
   :version "24.1"
@@ -52,6 +68,23 @@ xterm-extra-capabilities
   :type `(choice (const :tag "Check" check)
                  ,xterm--extra-capabilities-type))
 
+(defcustom xterm-screen-extra-capabilities '(modifyOtherKeys setSelection)
+  "Extra capabilities supported under \"screen\".
+Some features of screen depend on the terminal emulator in which
+it runs, which can change when the screen session is moved to another tty."
+  :version "25.1"
+  :type xterm--extra-capabilities-type
+  :group 'xterm)
+
+(defcustom xterm-tmux-extra-capabilities '(modifyOtherKeys setSelection)
+  "Extra capabilities supported under \"tmux\".
+Some features of tmux depend on the terminal emulator in which it
+runs, which can change when the screen session is moved to
+another tty."
+  :version "25.1"
+  :type xterm--extra-capabilities-type
+  :group 'xterm)
+
 (defcustom xterm-max-cut-length 100000
   "Maximum number of bytes to cut into xterm using the OSC 52 sequence.
 
@@ -639,55 +672,57 @@ xterm--report-background-handler
         (when recompute-faces
           (tty-set-up-initial-frame-faces))))))
 
-(defun xterm--version-handler ()
-  (let ((str "")
-        chr)
-    ;; The reply should be: \e [ > NUMBER1 ; NUMBER2 ; NUMBER3 c
-    ;; If the timeout is completely removed for read-event, this
-    ;; might hang for terminals that pretend to be xterm, but don't
-    ;; respond to this escape sequence.  RMS' opinion was to remove
-    ;; it completely.  That might be right, but let's first try to
-    ;; see if by using a longer timeout we get rid of most issues.
-    (while (and (setq chr (read-event nil nil 2)) (not (equal chr ?c)))
-      (setq str (concat str (string chr))))
-    ;; Since xterm-280, the terminal type (NUMBER1) is now 41 instead of 0.
-    (when (string-match "\\([0-9]+\\);\\([0-9]+\\);0" str)
-      (let ((version (string-to-number (match-string 2 str))))
-        (when (and (> version 2000) (equal (match-string 1 str) "1"))
-          ;; Hack attack!  bug#16988: gnome-terminal reports "1;NNNN;0"
-          ;; with a large NNNN but is based on a rather old xterm code.
-          ;; Gnome terminal 3.6.1 reports 1;3406;0
-          ;; Gnome terminal 2.32.1 reports 1;2802;0
-          (setq version 200))
-        (when (equal (match-string 1 str) "83")
-          ;; `screen' (which returns 83;40003;0) seems to also lack support for
-          ;; some of these (bug#17607, bug#20356).
-          ;; Note: this code path should normally not be used any more
-          ;; since term/screen.el now binds xterm-extra-capabilities
-          ;; to a fixed value, rather than using the dynamic checking.
-          (setq version 200))
-        ;; If version is 242 or higher, assume the xterm supports
-        ;; reporting the background color (TODO: maybe earlier
-        ;; versions do too...)
-        (when (>= version 242)
-          (xterm--query "\e]11;?\e\\"
-                        '(("\e]11;" .  xterm--report-background-handler))))
-
-        ;; If version is 216 (the version when modifyOtherKeys was
-        ;; introduced) or higher, initialize the
-        ;; modifyOtherKeys support.
-        (when (>= version 216)
-          (xterm--init-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)
-          ;; Most xterms seem to have it disabled by default, and if it's
-          ;; disabled, C-y will incur a timeout, so we only use it if the user
-          ;; explicitly requests it.
-          ;;(xterm--init-activate-get-selection)
-          (xterm--init-activate-set-selection))))))
+(defun xterm--extra-capabilities (identification)
+  "Return a list of capabilities for an XTerm-compatible terminal.
+IDENTIFICATION should be an object of type
+‘xterm--identification’."
+  ;; `screen' (which returns 83;40003;0) seems to also lack support for
+  ;; some of these (bug#17607, bug#20356).
+  ;; Note: this code path should normally not be used any more
+  ;; since term/screen.el now binds xterm-extra-capabilities
+  ;; to a fixed value, rather than using the dynamic checking.
+  ;;
+  ;; FIXME: What should actually happen is that if a multiplexer is
+  ;; encountered the underlying emulator should be detected by sending
+  ;; a wrapped “Secondary Device Attributes” query.
+  ;;
+  ;; FIXME: The following should work, but leads to an error during
+  ;; compilation:
+  ;;(cl-check-type identification xterm--identification)
+  (cl-check-type identification (satisfies xterm--identification-p))
+  (cl-ecase (xterm--identification-multiplexer identification)
+    (screen xterm-screen-extra-capabilities)
+    (tmux xterm-tmux-extra-capabilities)
+    ((nil)
+     (if (eq xterm-extra-capabilities 'check)
+         ;; Since xterm-280, the terminal type (NUMBER1) is now 41
+         ;; instead of 0.
+         (when-let ((version (xterm--identification-version identification)))
+           ;; Hack attack!  bug#16988: gnome-terminal reports "1;NNNN;0"
+           ;; with a large NNNN but is based on a rather old xterm code.
+           ;; Gnome terminal 3.6.1 reports 1;3406;0
+           ;; Gnome terminal 2.32.1 reports 1;2802;0
+           (unless (and (> version 2000)
+                        (eq (xterm--identification-terminal identification)
+                            'vt220))
+             (append
+              ;; If version is 242 or higher, assume the xterm
+              ;; supports reporting the background color (TODO: maybe
+              ;; earlier versions do too...)
+              (when (>= version 242) '(reportBackground))
+              ;; If version is 216 (the version when modifyOtherKeys
+              ;; was introduced) or higher, initialize the
+              ;; modifyOtherKeys support.
+              (when (>= version 216) '(modifyOtherKeys))
+              ;; 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.  Most xterms seem to have
+              ;; getSelection disabled by default, and if it's
+              ;; disabled, C-y will incur a timeout, so we only use it
+              ;; if the user explicitly requests it.
+              (when (>= version 203) '(setSelection)))))
+       xterm-extra-capabilities))))
 
 (defvar xterm-query-timeout 2
   "Seconds to wait for an answer from the terminal.
@@ -766,26 +801,17 @@ terminal-init-xterm
   (xterm-register-default-colors xterm-standard-colors)
   (tty-set-up-initial-frame-faces)
 
-  (if (eq xterm-extra-capabilities 'check)
-      ;; Try to find out the type of terminal by sending a "Secondary
-      ;; Device Attributes (DA)" query.
-      (xterm--query "\e[>0c"
-                    ;; Some terminals (like OS X's Terminal.app) respond to
-                    ;; this query as if it were a "Primary Device Attributes"
-                    ;; query instead, so we should handle that too.
-                    '(("\e[?" . xterm--version-handler)
-                      ("\e[>" . xterm--version-handler)))
-
-    (when (memq 'reportBackground xterm-extra-capabilities)
+  (let ((capabilities (xterm--extra-capabilities (xterm--identify))))
+    (when (memq 'reportBackground capabilities)
       (xterm--query "\e]11;?\e\\"
                     '(("\e]11;" .  xterm--report-background-handler))))
 
-    (when (memq 'modifyOtherKeys xterm-extra-capabilities)
+    (when (memq 'modifyOtherKeys capabilities)
       (xterm--init-modify-other-keys))
 
-    (when (memq 'getSelection xterm-extra-capabilities)
+    (when (memq 'getSelection capabilities)
       (xterm--init-activate-get-selection))
-    (when (memq 'setSelection xterm-extra-capabilities)
+    (when (memq 'setSelection capabilities)
       (xterm--init-activate-set-selection)))
 
   ;; Unconditionally enable bracketed paste mode: terminals that don't
@@ -794,6 +820,73 @@ terminal-init-xterm
 
   (run-hooks 'terminal-init-xterm-hook))
 
+(defun xterm--identify ()
+  "Try to find out the type of terminal.
+Send a “Secondary Device Attributes (DA)” query.  Store the
+result as a value of the ‘xterm--identification’ structure in the
+‘xterm-identification’ terminal parameter, and return it."
+  (xterm--query "\e[>0c"
+                ;; Some terminals (like OS X's Terminal.app) respond to
+                ;; this query as if it were a "Primary Device Attributes"
+                ;; query instead, so we should handle that too.
+                '(("\e[?" . xterm--handle-identification)
+                  ("\e[>" . xterm--handle-identification)))
+  (terminal-parameter nil 'xterm-identification))
+
+(cl-defstruct xterm--identification
+  terminal multiplexer version)
+
+(defun xterm--handle-identification ()
+  "Parse the result of a “Secondary Device Attribute” query.
+Store the result as an ‘xterm--identification’ object in the
+‘xterm-identification’ terminal parameter."
+  (set-terminal-parameter
+   nil 'xterm-identification
+   (xterm--parse-identification (xterm--read-until ?c))))
+
+(defun xterm--parse-identification (string)
+  "Parse an XTerm identification STRING.
+STRING is returned by the terminal responding to a “Secondary
+Device Attribute” query.  Return an ‘xterm--identification’
+object."
+  (save-match-data
+    ;; The reply should be: \e [ > NUMBER1 ; NUMBER2 ; NUMBER3 c
+    ;; If the timeout is completely removed for read-event, this
+    ;; might hang for terminals that pretend to be xterm, but don't
+    ;; respond to this escape sequence.  RMS' opinion was to remove
+    ;; it completely.  That might be right, but let's first try to
+    ;; see if by using a longer timeout we get rid of most issues.
+    (if (string-match
+         (rx bos (group (+ digit)) ?\; (group (+ digit)) ";0" eos)
+         string)
+        (cl-destructuring-bind
+            (terminal multiplexer)
+            (cl-ecase (string-to-number (match-string 1 string))
+              (0 '(vt100 nil))
+              (1 '(vt220 nil))
+              (2 '(vt240 nil))
+              (18 '(vt330 nil))
+              (19 '(vt340 nil))
+              (24 '(vt320 nil))
+              (41 '(vt420 nil))
+              (61 '(vt510 nil))
+              (64 '(vt520 nil))
+              (65 '(vt525 nil))
+              (83 '(nil screen))
+              (84 '(nil tmux)))
+          (make-xterm--identification
+           :terminal terminal
+           :multiplexer multiplexer
+           :version (string-to-number (match-string 2 string))))
+      (make-xterm--identification))))
+
+(defun xterm--read-until (char)
+  "Read characters from the current terminal until CHAR is encountered.
+Return the characters read (excluding CHAR) as a string."
+  (cl-loop for ch = (read-char nil nil 0.1)
+           until (or (null ch) (= ch char))
+           concat (char-to-string ch)))
+
 (defun xterm--init-modify-other-keys ()
   "Terminal initialization for xterm's modifyOtherKeys support."
   (send-string-to-terminal "\e[>4;1m")
@@ -827,13 +920,14 @@ xterm--selection-char
               ((terminal-parameter nil 'xterm--get-selection) (eql t)))
   (unless (eq data-type 'STRING)
     (error "Unsupported data type %S" data-type))
-  (let* ((screen (eq (terminal-parameter nil 'terminal-initted)
-                     'terminal-init-screen))
-         (query (concat "\e]52;" (xterm--selection-char type) ";")))
+  (let ((query (concat "\e]52;" (xterm--selection-char type) ";")))
     (with-temp-buffer
       (set-buffer-multibyte nil)
       (xterm--query
-       (concat (when screen "\eP") query "?\a" (when screen "\e\\"))
+       (xterm--wrap-selection-query
+        query
+        (xterm--identification-multiplexer
+         (terminal-parameter nil 'xterm-multiplexer)))
        (list (cons query (lambda ()
                            (while (let ((char (read-char)))
                                     (unless (eq char ?\a)
@@ -867,10 +961,10 @@ xterm--selection-char
 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* ((screen (eq (terminal-parameter nil 'terminal-initted)
-                     'terminal-init-screen))
+  (let* ((multiplexer (xterm--identification-multiplexer
+                       (terminal-parameter nil 'xterm-identification)))
          (bytes (encode-coding-string data 'utf-8-unix))
-         (base-64 (if screen
+         (base-64 (if multiplexer
                       (replace-regexp-in-string
                        "\n" "\e\\\eP"
                        (base64-encode-string bytes)
@@ -882,10 +976,22 @@ xterm--selection-char
           (warn "Selection too long to send to terminal: %d bytes" length)
           (sit-for 2))
       (send-string-to-terminal
-       (concat
-        (when screen "\eP")
-        "\e]52;" (xterm--selection-char type) ";" base-64 "\a"
-        (when screen "\e\\"))))))
+       (xterm--wrap-selection-query
+        (concat "\e]52;" (xterm--selection-char type) ";" base-64 "\a")
+        multiplexer)))))
+
+(defun xterm--wrap-selection-query (query multiplexer)
+  "Return a wrapped version of QUERY for the terminal MULTIPLEXER.
+QUERY should be an XTerm-compatible escape sequence to access the
+X selection.  If the current terminal is in a multiplexer, return
+a wrapped version of QUERY to circumvent interpretation by the
+multiplexer."
+  (concat
+   (cl-case multiplexer
+     (screen "\eP")
+     (tmux "\ePtmux;\e"))
+   query
+   (when multiplexer "\e\\")))
 
 (defun xterm-rgb-convert-to-16bit (prim)
   "Convert an 8-bit primary color value PRIM to a corresponding 16-bit value."
diff --git a/test/automated/xterm-tests.el b/test/automated/xterm-tests.el
new file mode 100644
index 0000000..0224213
--- /dev/null
+++ b/test/automated/xterm-tests.el
@@ -0,0 +1,97 @@
+;;; xterm-tests.el --- unit tests for term/xterm.el  -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2016  Free Software Foundation, Inc.
+
+;; Author: Philipp Stephani <phst@google.com>
+;; Keywords: terminals
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published
+;; by the Free Software Foundation, either version 3 of the License,
+;; or (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;; General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Unit tests for lisp/term/xterm.el.
+
+;;; Code:
+
+(require 'term/xterm)
+(require 'seq)
+
+(defconst xterm-tests--HTerm
+  (make-xterm--identification :terminal 'vt100 :multiplexer nil :version 256))
+
+(defconst xterm-tests--Terminal.app
+  (make-xterm--identification :terminal 'vt220 :multiplexer nil :version 95))
+
+(defconst xterm-tests--XTerm
+  (make-xterm--identification :terminal 'vt420 :multiplexer nil :version 314))
+
+(defconst xterm-tests--gnome-terminal
+  (make-xterm--identification :terminal 'vt220 :multiplexer nil :version 3406))
+
+(defconst xterm-tests--screen
+  (make-xterm--identification :terminal nil :multiplexer 'screen :version 400003))
+
+(defconst xterm-tests--tmux
+  (make-xterm--identification :terminal nil :multiplexer 'tmux :version 0))
+
+(ert-deftest xterm--parse-identification--HTerm ()
+  (should (equal (xterm--parse-identification "0;256;0")
+                 xterm-tests--HTerm)))
+
+(ert-deftest xterm--parse-identification--Terminal.app ()
+  (should (equal (xterm--parse-identification "1;95;0")
+                 xterm-tests--Terminal.app)))
+
+(ert-deftest xterm--parse-identification--XTerm ()
+  (should (equal (xterm--parse-identification "41;314;0")
+                 xterm-tests--XTerm)))
+
+(ert-deftest xterm--parse-identification--gnome-terminal ()
+  (should (equal (xterm--parse-identification "1;3406;0")
+                 xterm-tests--gnome-terminal)))
+
+(ert-deftest xterm--parse-identification--screen ()
+  (should (equal (xterm--parse-identification "83;400003;0")
+                 xterm-tests--screen)))
+
+(ert-deftest xterm--parse-identification--tmux ()
+  (should (equal (xterm--parse-identification "84;0;0")
+                 xterm-tests--tmux)))
+
+(ert-deftest xterm--extra-capabilities--HTerm ()
+  (should (equal (xterm--extra-capabilities xterm-tests--HTerm)
+                 '(reportBackground modifyOtherKeys setSelection))))
+
+(ert-deftest xterm--extra-capabilities--Terminal.app ()
+  (should-not (xterm--extra-capabilities xterm-tests--Terminal.app)))
+
+(ert-deftest xterm--extra-capabilities--XTerm ()
+  (should (equal (xterm--extra-capabilities xterm-tests--XTerm)
+                 '(reportBackground modifyOtherKeys setSelection))))
+
+(ert-deftest xterm--extra-capabilities--gnome-terminal ()
+  (should-not (xterm--extra-capabilities xterm-tests--gnome-terminal)))
+
+(ert-deftest xterm--extra-capabilities--screen ()
+  (should (equal (xterm--extra-capabilities xterm-tests--screen)
+                 '(modifyOtherKeys setSelection))))
+
+(ert-deftest xterm--extra-capabilities--tmux ()
+  (should (equal (xterm--extra-capabilities xterm-tests--tmux)
+                 '(modifyOtherKeys setSelection))))
+
+(provide 'xterm-tests)
+;;; xterm-tests.el ends here
-- 
2.7.4


^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2016-03-29  9:08 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-03-29  9:08 Patch for supporting tmux Philipp Stephani

Code repositories for project(s) associated with this external index

	https://git.savannah.gnu.org/cgit/emacs.git
	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.