12 Januar 2014 17:18

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.

Kommentare

Powered by BetaBlog
Login | RSS Beiträge RSS Kommentare Impressum