Vim auf breiten Bildschirmen
Bislang habe ich es immer auf einen Zufall geschoben, wenn die Maus in meinem Vim manchmal nicht so funktioniert hat, wie sie es soll. Der Cursor sprang dann nicht dort hin, wo ich hingeklickt hatte.
Doch heute fiel mir ein gewisses System dabei auf: Es passiert immer dann, wenn die Zeile sehr lang ist und man an deren Ende klickt – und wenn der Bildschirm (bzw. das Terminal) breit ist.
Das Problem
Man braucht ein breites Terminal, um dies zu bemerken. Genau genommen muss es mehr als 223 Zeichen breit sein. Dann startet man Vim und schreibt eine (oder mehrere) lange Zeilen, sodass sie bis zum rechten Rand gehen. Natürlich muss die Mausunterstützung aktiviert sein (:set mouse=a
). Nun klickt man in der Nähe des rechten Rands auf den Text. Entweder springt der Cursor ganz wo anders hin oder es werden anscheinend zufällige Eingaben gemacht (was natürlich gemein ist, wenn es den gesamten Text löscht und dann speichert).
Die Erklärung
Man muss sich anschauen, wie die Mausposition an das Programm (in diesem Fall Vim) übermittelt wird. Steuerzeichen werden üblicherweise als ein Escape-Zeichen gefolgt von einem Code für die Art und dann dem Wert gesendet. Das uralte Protokoll DECSET 1000 ist so aufgebaut:
\e[M<action+32><x+32><y+32>
Das Problem ist die Begrenzung auf ein Byte. Denn 255 - 32 = 223, genau der Wert, bis zu dem die Maus noch funktioniert. Es gibt nun eine Erweiterung, die im Anschluss die Koordinaten noch in einem anderen Format überträgt: DECSET 1005. Zusammengefasst werden dort zwei Bytes für jede Koordinate übertragen, was das Problem aber nur verschiebt (auch, wenn man nicht mehr so schnell darüber stolpern dürfte, denn wer hat schon so breite Bildschirme).
urxvt (rxvt-unicode) hat dann eine weitere Erweiterung eingeführt, DECSET 1015. Hier werden die Koordianten mit Zahlen im Dezimalformat ausgedrückt, wodurch es keine Beschränkung mehr gibt. Ich nutze urxvt, aber Vim spinnt trotzdem, warum? Weil es zuerst DECSET 1000 interpretiert und mit DECSET 1015 nichts anfangen kann und es fehlerhaft interpretiert.
Zusammenfassung der Implementierungen: http://www.midnight-commander.org/ticket/2662
Die Lösung
Vim bietet eine Option, mit der genau dieses Problem behoben werden kann:
'ttymouse' 'ttym' string (default depends on 'term')
global
{not in Vi}
{only in Unix and VMS, doesn't work in the GUI; not
available when compiled without |+mouse|}
Name of the terminal type for which mouse codes are to be recognized.
Currently these strings are valid:
*xterm-mouse*
xterm xterm-like mouse handling. The mouse generates
"<Esc>[Mscr", where "scr" is three bytes:
"s" = button state
"c" = column plus 33
"r" = row plus 33
This only works up to 223 columns! See "dec" for a
solution.
xterm2 Works like "xterm", but with the xterm reporting the
mouse position while the mouse is dragged. This works
much faster and more precise. Your xterm must at
least at patchlevel 88 / XFree 3.3.3 for this to
work. See below for how Vim detects this
automatically.
*netterm-mouse*
netterm NetTerm mouse handling. The mouse generates
"<Esc>}r,c<CR>", where "r,c" are two decimal numbers
for the row and column.
*dec-mouse*
dec DEC terminal mouse handling. The mouse generates a
rather complex sequence, starting with "<Esc>[".
This is also available for an Xterm, if it was
configured with "--enable-dec-locator".
*jsbterm-mouse*
jsbterm JSB term mouse handling.
*pterm-mouse*
pterm QNX pterm mouse handling.
*urxvt-mouse*
urxvt Mouse handling for the urxvt (rxvt-unicode) terminal.
*sgr-mouse*
sgr Mouse handling for the terminal that emits SGR-styled
mouse reporting. Works with xterm version 277 or
later.
Generell hilft bei vielen Problemen das richtige Setzen der TERM
-Umgebungsvariable. Lustig wird das, wenn zu dem Terminal-Emulator auch noch screen und ssh dazukommen. Dann ist man nämlich am überlegen, was der Server kann (ich nutze zur Zeit alias ssh='TERM=rxvt-unicode ssh'
), was der Terminal-Emulator kann und was screen wie weiterleitet. Aber so kompliziert mache ich es im Moment gar nicht, es läuft alles lokal.
$ echo $TERM
rxvt-unicode-256color
Leider hilft es in diesem Fall nicht, denn Vim kann mit diesem TERM nichts Sinnvolles anfangen. Deshalb habe ich folgendes in meine ~/.vimrc eingefügt:
if &term =~# 'rxvt-unicode'
set ttymouse=urxvt
endif
Und siehe da, es geht! Es wäre natürlich schön, wenn Vim das selbst erkennen würde. Momentan setzt er ttymouse=xterm2
. Bei Gelegenheit kann ich ja mal nach einem Bugreport suchen oder einen erstellen.