blog · git · desktop · images · contact & privacy · gopher


Änderungen in xiate

In den letzten zwei Jahren war es um xiate eher ruhig. Das Programm hat funktioniert und sich nur sehr wenig verändert. Es gab aber durchaus ein paar Dinge, die mich die ganze Zeit über gestört haben, und um die will ich mich jetzt kümmern.

Clients warten, bis das Fenster geschlossen wird

xiate hat ein Client-Server-Modell, es gibt also einen Daemon, der die ganze Zeit im Hintergrund läuft, und dann braucht man einen kleinen Client, um tatsächlich ein Fenster durch den Daemon öffnen zu lassen. Die beiden reden dafür über ein UNIX-Domain-Socket. Um den Code einfach(er) zu halten, hat der alte Client einfach eine Nachricht an den Server geschickt und sich dann beendet. Das wird sich jetzt ändern.

xiatec blockiert nun, bis das zugehörige Terminalfenster geschlossen wurde. So verhalten sich auch andere Terminals wie zum Beispiel XTerm und ich glaube auch, dass sich ein vernünftiges Terminal eigentlich so zu verhalten hat.

Das eröffnet dann neue Skripting-Möglichkeiten. Oder sagen wir mal, diese Dinge sind nun wieder möglich. Jetzt geht sowas:

#!/bin/sh

xiatec -e vim /some/file
do_more_work_on /some/file

Der zweite Befehl wird erst ausgeführt, wenn der erste vollständig zu Ende ist – also dann, wenn das Terminalfenster mit dem Vim darin geschlossen wurde. Diese Eigenschaft habe ich tatsächlich kürzlich benötigt.

Der Client ist jetzt ein C-Programm

Vor knapp einem Jahr hat ccrusius auf GitHub schon einen PR hierfür erstellt gehabt. Damals habe ich aber noch keinen Bedarf dafür gesehen. Der ursprüngliche Client war nämlich ein sehr kurzes und einfaches Shell-Skript, das über socat mit dem Server redet. Das wollte ich nicht ohne Not durch ein C-Programm ersetzen.

Soll jetzt aber die Socket-Verbindung offengehalten werden, bis das zugehörige Fenster geschlossen ist, dann sieht die Sache schon nicht mehr so einfach aus. Ja, das kann man auch mit socat machen, aber schön ist das nicht. Außerdem muss socat dann ja so lange weiterlaufen. Das schlägt sich im Speicherverbrauch nieder.

Der Shell-Client ist jetzt also weg und es gibt ein kleines C-Programm.

Warum überhaupt noch das Client-Server-Modell umsetzen?

Im originalen Blogpost zu xiate habe ich schon erzählt gehabt, dass es diese Modell aus Gründen der Performance gibt. Als ich damals angefangen habe, xiate zu schreiben, hat selbst der Start eines Minimalprogramms mit VTE ungefähr eine Sekunde gebraucht. Das geht gar nicht. Das Client-Server-Modell war dann ein Workaround dafür.

In der Zwischenzeit habe ich bemerkt, dass weder VTE noch Gtk etwas mit diesem Verhalten zu tun haben. Der Übeltäter war UIM. Dieses Framework muss beim Start einen großen Haufen Dateien durchforsten und verarbeiten und das braucht Zeit. Hat man aber kein UIM installiert, ist alles gut.

Es ist jetzt nicht so, dass ich UIM zwingend brauche. Ich hatte es installiert, weil ich mich mit Fremdsprachen beschäftigt hatte, die nicht das lateinische Alphabet benutzen. Hätte das Ding auch einfach entfernen können.

Habe ich dann auch gemacht und gleich den Servermodus aus xiate in einem Dev-Branch entfernt. Siehe da, das Terminal war immer noch schnell. (Auch alle anderen VTE-Terminals und ich habe mir schon fast überlegt, einfach sakura zu verwenden. Da fehlte mir dann aber doch hier und da was.) Aber: Der Speicherverbrauch schnellte in die Höhe. Jedes Terminalfenster hat mindestens 30-40 MB RAM geschluckt, manchmal sogar noch mehr, wenn da viele Daten im Scrollback-Buffer waren.

Der ursprüngliche Server hat aber nur 40-50 MB RAM für etliche Fenster gebraucht.

Wir schreiben jetzt zwar das Jahr 2018 und alle unsere Rechner haben unfassbar viel Arbeitsspeicher, aber so ganz bin ich trotzdem noch nicht bereit, für ein einziges Terminalfenster so viel RAM auszugeben. Vielleicht ändert sich da meine Meinung im Laufe der Zeit noch. (Oder ich verliere den Verstand, schmeiße alle CPUs mit spekulativer Ausführung aus dem Fenster und verwende nur noch eine winzige Kiste mit winziger aber dafür exotischer CPU. Wird sich zeigen.)

Exit-Codes

Das ist etwas, was ansonsten nur st kann (zumindest habe ich das Feature in keinem anderen bekannten Terminalemulator gefunden):

$ xiatec -e /bin/true; echo $?
0

$ xiatec -e /bin/false; echo $?
1

Man kann jetzt im Elternprozess von xiatec den Exit-Code desjenigen Prozesses auswerten, der im Terminal lief. Genau wie bei st gibt xiatec aber nur entweder 0 oder 1 zurück:

$ xiatec -e sh -c 'exit 42'; echo $?
1

$ st -e sh -c 'exit 42'; echo $?
child finished with error '10752'
1

Der ursprüngliche Fehlercode ist verloren, weil es anders keinen Sinn ergibt: Wenn es einen internen Fehler in xiate gibt, dann ist dieser nicht von einem Fehler im Kindprozess zu unterscheiden. Ein Exit-Code von „42“ wäre also nichtssagend – der kann vom Kind oder von xiate selbst gekommen sein. Weiß keiner.

History-Dump

Viele moderne Terminalemulatoren haben mittlerweile eine Suchfunktion. xiate hat jetzt etwas, das – so denke ich – noch etwas mächtiger ist. Mit Strg+Shift+F kann man den gesamten sichtbaren Inhalt des Terminals inklusive History in eine temporäre Datei schreiben und mit einem Tool seiner Wahl öffnen lassen.

Dieses Tool sieht bei mir so aus:

#!/bin/sh

trap 'rm -f "$1"' EXIT
xiatec -name term-floating -e vim -R "$1"

Mit Strg+Shift+F bekomme ich jetzt also ein zweites Terminalfenster, in dem ein Vim läuft, der den Inhalt des ersten Fensters geöffnet hat. Darin kann ich jetzt suchen, das editieren, Teile davon speichern oder was auch immer.

Noch mehr Änderungen

Eigentlich hoffe ich, dass es in Zukunft gar nicht mehr so viele Änderungen geben wird. Ich werde jetzt erstmal einen Feature-Freeze machen und die Bugs ausbügeln, die ich möglicherweise mit diesen neuen Änderungen eingebaut habe.

Vielleicht werden die Binaries dann demnächst umbenannt. Mir erscheint nämlich eigentlich xiated ein besserer Name für den Daemon zu sein. Der Client bliebe xiatec. So ist dann jeweils auf den ersten Blick klar, womit man es zu tun hat.