Подтвердить что ты не робот

Emacs, unicode, xterm escape-последовательности и широкие терминалы

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

Каков виновник и как я могу его обойти?

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

Подробности Gory следуют...

Спасибо!

Emacs xterm-mouse-mode имеет хорошо известную слабость обработки щелчков мыши, начиная с x = 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, потому что Somebody заменяет эти последовательности на \0.

Итак, где бы я ожидал нажатия на строку 1, col 250 для создания

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

Вместо сообщений emacs (для любого col > 223)

ESC [ M SPC [email protected] ! ESC [ M # [email protected] !

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

Некоторые более подробные вопросы:
- Кто это Кто-то, кто перехватывает коды, прежде чем они достигнут буфера потери emacs?

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

Update:

Здесь патч против 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 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, будут путаться этим патчем, потому что escape-последовательности мыши увеличиваются. Тем не менее, эти приложения ломаются ужасно с текущим xterm, потому что позиции мыши с x > 95 выглядят как коды utf-8, но не являются. Я бы создал новый режим мыши для xterm, но некоторые приложения (gnu screen!) Отфильтровывают неизвестные escape-последовательности. Emacs - единственное приложение для мыши-терминала, которое я использую, поэтому считаю патч чистым выигрышем, но YMMV.

4b9b3361

Ответ 1

Хорошо, понял. На самом деле есть две проблемы.

Во-первых, некоторые источники дайвинга показывают, что 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

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

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

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

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

Ответ 3

Я думаю, что проблема, вызвавшая ваше обходное решение (и восходящее исправление, включенное в один из релизов 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, которая работает с щелчками мыши до col 222 (кредит для Ryan для обработки переполнения > 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 до col 222, но не имеет обработки переполнения > 222. Райан предположил:

(defun xterm-mouse-event-read ()
  (let ((c (read-char)))
    (if (> c #x3FFF80)
        (+ 128 (- c #x3FFF80))
      c)))

Ответ 4

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

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