Emacs, Unicode, escape-последовательности мыши xterm и широкие терминалы - PullRequest
13 голосов
/ 12 августа 2010

Короткая версия: При использовании emacs 'xterm-mouse-mode, Somebody (emacs? Bash? Xterm?) Перехватывает управляющие последовательности xterm и заменяет их на \ 0.Это боль для широких мониторов, потому что только первые 223 столбца имеют мышь.

В чем виновник, и как я могу обойти это?

Из того, что я могу сказать, это связано с поддержкой Unicode / UTF-8, потому что это не было проблемой5-6 лет назад, когда у меня в последний раз был большой монитор.

Горы следуют подробности ...

Спасибо!

Emacs xterm-mouse-mode хорошо известенслабость обработки щелчков мыши, начиная с х = 95. Обходной путь , принятый в последних версиях emacs, устраняет проблему до x = 223.

Несколько лет назад я понял, что xterm кодирует позиции в 7-битных октетах.Для кодирования данной позиции 'x', с X = x-96, отправьте:

\40+x (x < 96)  
\300+X/64 \200+X%64 (otherwise)  

Мы должны добавить единицу к данной позиции x из emacs, потому что позиции в xterm начинаются с единицы, а не с нуля.Следовательно, появляется магическое число x = 95, потому что оно закодировано как «\ 300 \ 200» - первое экранированное число.Кто-то (emacs? Bash? Xterm?) Рассматривает такие, как управляющие последовательности "C0" из ISO 2022 .Начиная с x = 159, мы изменяем на последовательности "C1" (\ 301 \ 200), которые также являются частью ISO 2022.

Неисправности обращаются с последовательностями \ 302, что соответствует текущему пределу x = 223,Несколько лет назад мне удалось расширить хак до ручного перехвата последовательностей \ 302 и \ 303, что позволило решить проблему.Перенесемся на несколько лет вперед, и сегодня я обнаружил, что застрял на x = 223, потому что кто-то заменяет эти последовательности на \ 0.

Итак, где я ожидал бы щелкнуть строку 1, столбец 250производить

ESC [ M SPC \303\207 ! ESC [ M # \303\207 !

Вместо отчетов Emacs (для любого столбца> 223)

ESC [ M SPC C-@ ! ESC [ M # C-@ !

Я подозреваю, что поддержка Unicode / UTF-8 является виновником.Некоторые раскопки показывают, что стандарт Unicode допускал последовательности C0 и C1 как часть UTF-8 до ноября 2000 , и я предполагаю, что кто-то не получил памятку (к счастью).Однако, \ 302 \ 200 - \ 302 \ 237 - это Юникод управляющих последовательностей , так что Кто-то их хлюпает (делает кто-то-что с ними!) И возвращает \ 0 вместо этого.

Несколько более подробных вопросов:
- Кто это? Кто-нибудь, кто перехватывает коды до того, как они достигают буфера потерь emacs?
- Если это действительно просто управляющие последовательности, как получаются символы после \ 302 \237, которые являются UTF-8-кодировками печатаемого Unicode, также возвращаются как \ 0?
- Что заставляет emacs решить, отображать ли потери в виде символов Unicode или восьмеричных escape-последовательностей, и почему они не совпадают?Например, мой собственный сборщик cygwin emacs 23.2.1 (xterm 229) сообщает \ 301 \ 202 для столбца 161, а мой emacs 22.3.1 (xterm 215), предоставленный rhel5.5, сообщает "Â" (латинский A с дифракционным дифрагмом)что на самом деле \ 303 \ 202 в UTF-8!

Обновление:

Вот патч против xterm-261, который заставляет его генерировать позиции мыши в формате utf-8:

diff -r button.c button.utf-8-fix.c
--- a/button.c  Sat Aug 14 08:23:00 2010 +0200
+++ b/button.c  Thu Aug 26 16:16:48 2010 +0200
@@ -3994,1 +3994,27 @@
-#define MOUSE_LIMIT (255 - 32)
+#define MOUSE_LIMIT (2047 - 32)
+#define MOUSE_UTF_8_START (127 - 32)
+
+static unsigned
+EmitMousePosition(Char line[], unsigned count, int value)
+{
+    /* Add pointer position to key sequence
+     * 
+     * Encode large positions as two-byte UTF-8 
+     *
+     * NOTE: historically, it was possible to emit 256, which became
+     * zero by truncation to 8 bits. While this was arguably a bug,
+     * it's also somewhat useful as a past-end marker so we keep it.
+     */
+    if(value == MOUSE_LIMIT) {
+       line[count++] = CharOf(0);
+    }
+    else if(value < MOUSE_UTF_8_START) {
+       line[count++] = CharOf(' ' + value + 1);
+    }
+    else {
+       value += ' ' + 1;
+       line[count++] = CharOf(0xC0 + (value >> 6));
+       line[count++] = CharOf(0x80 + (value & 0x3F));
+    }
+    return count;
+}
@@ -4001,1 +4027,1 @@
-    Char line[6];
+    Char line[9]; /* \e [ > M Pb Pxh Pxl Pyh Pyl */
@@ -4021,2 +4047,0 @@
-    else if (row > MOUSE_LIMIT)
-       row = MOUSE_LIMIT;
@@ -4028,1 +4052,5 @@
-    else if (col > MOUSE_LIMIT)
+
+    /* Limit to representable mouse dimensions */
+    if (row > MOUSE_LIMIT)
+       row = MOUSE_LIMIT;
+    if (col > MOUSE_LIMIT)
@@ -4090,2 +4118,2 @@
-       line[count++] = CharOf(' ' + col + 1);
-       line[count++] = CharOf(' ' + row + 1);
+       count = EmitMousePosition(line, count, col);
+       count = EmitMousePosition(line, count, row);

Надеюсь, это(или что-то подобное) появится в будущей версии xterm ... патч заставляет xterm работать из коробки с emacs-23 (который предполагает ввод utf-8) и также исправляет существующие проблемы с xt-mouse.el,Чтобы использовать его с emacs-22, требуется переопределить функцию, которую он использует для декодирования позиций мыши (новое определение также отлично работает с emacs-23):

(defadvice xterm-mouse-event-read (around utf-8 compile activate)
  (setq ad-return-value
        (let ((c (read-char)))
          (cond
           ;; mouse clicks outside the encodable range produce 0
           ((= c 0) #x800)
           ;; must convert UTF-8 to unicode ourselves
           ((and (>= c #xC2) (< emacs-major-version 23))
            (logior (lsh (logand c #x1F) 6) (logand (read-char) #x3F)))
           ;; normal case
           (c) ) )))

Распределить defun как часть .emacsна всех машинах, в которые вы входите, и исправляйте xterm на любых машинах, с которых вы работаете.Вуаля!

ПРЕДУПРЕЖДЕНИЕ: Приложения, которые используют режимы мыши xterm, но не обрабатывают их ввод как utf-8, запутаются этим патчем, потому что экранирующие последовательности мыши становятся длиннее.Тем не менее, эти приложения ужасно ломаются с текущим xterm, потому что позиции мыши с x> 95 выглядят как коды utf-8, но это не так.Я бы создал новый режим мыши для xterm, но некоторые приложения (экран gnu!) Отфильтровывают неизвестные escape-последовательности.Emacs - единственное приложение для терминальной мыши, которое я использую, поэтому я считаю, что патч - чистая победа, но YMMV.

Ответы [ 4 ]

6 голосов
/ 08 ноября 2011

xterm-262 добавляет патч, указанный выше, однако, этот патч по своей сути совершенно не работает.Разработчики Rxvt-unicode поняли это и добавили еще одно, гораздо лучшее расширение для сообщения о координатах мыши.

Сейчас я работаю над получением широкой поддержки для этого.Rxvt-unicode и iTerm2 уже поддерживают оба расширения.Я создал патчи для xterm (для поддержки расширения urxvt) и для gnome-terminal, konsole и putty для поддержки обоих новых расширений.Что касается приложений, я добавил поддержку urxvt расширения для Midnight Commander.

Пожалуйста, присоединитесь ко мне в моих усилиях и постарайтесь убедить больше разработчиков терминалов и приложений для реализации этих расширений (по крайней мере,urxvt один, потому что другой не может быть автоматически распознан приложениями).

См. http://www.midnight -commander.org / ticket / 2662 для технических деталей и дальнейших указателей.

4 голосов
/ 16 августа 2010

ОК, разобрался. На самом деле есть две проблемы.

Во-первых, некоторые исходные погружения показывают, что xterm обрезает область окна с включенной мышью до 223x223 символов и отправляет 0x0 для всех остальных позиций.

Во-вторых, emacs-23 осведомлен о UTF-8 и запутывается событиями мыши, имеющими x> 160 и y> 94; в этих случаях кодировка xterm для x и y выглядит как двухбайтовый символ UTF-8 (например, 0xC2 0x80), и в результате последовательность мыши кажется на один символ короткой.

Я работаю над патчем для xterm, который заставляет события мыши испускать UTF-8 (который не будет смешивать emacs-23 и разрешать терминалы размером до 2047x2047), но я пока не уверен, как это получится

2 голосов
/ 12 августа 2010

Я думаю, что проблема, которая привела к тому, что ваш обходной путь (и вышестоящее исправление, которое было включено в один из выпусков v22) перестали работать в 23.2, находится внутри самого Emacs.23.1 может обрабатывать щелчки мыши после столбца 95 с помощью urxvt, gnu screen, putty или iTerm, но 23.2 не может.Установка всего на латиницу-1 не имеет значения.23.1 имеет такой же код в xt-mouse.el.Однако src / lread.c и src / character.h изменились, и я сразу понял, что где-то здесь есть ошибка.Что касается того, что происходит после 223 столбца, я понятия не имею.

Для всех, кого раздражает регрессия xt-mouse в 23.2, вот модифицированная версия xterm-mouse-event-read, котораяработает с щелчками мыши до столбца 222 (благодарность Райану за обработку переполнения> 222, которой не хватало в моем исходном исправлении).Это, вероятно, не будет работать в 23.1 или раньше.

(defun xterm-mouse-event-read ()
  (let ((c (read-char)))
    (cond ((= c 0) #x100)  
       ; for positions past col 222 emacs just delivers
       ; 0x0, best we can do is stay at eol 
      ((= 0 (logand c (- #x100))) c) 
      ((logand c #xff))))) 

... Редактировать: Вот версия из Emacs 24 (глава bzr).Он снова работает с 23,2 до 222, но ему не хватает обработки переполнения> 222, которую предложил Райан:

(defun xterm-mouse-event-read ()
  (let ((c (read-char)))
    (if (> c #x3FFF80)
        (+ 128 (- c #x3FFF80))
      c)))
1 голос
/ 25 ноября 2010

Хотя xterm теперь работает в режиме utf-8 с патчем, этот хак utf-8 сломается наихудшим образом в любой другой локали, так как символы юникода будут просто отброшены, если они не представимы.

rxvt-unicode имеет (в выпусках после 9.09) режим 1015, который отправляет ответы в форме "ESC [code; x; y M", используя десятичные числа.Преимущество этого заключается в том, что вам не нужно проверять приложения, а также работать в локалях, отличных от utf-8.

...