Natuerlich kann man davon ausgehen dass jede halbwegs komplexe Software irgendwelche grösseren oder kleineren Fehler enthält. Dass ich aber innerhalb einer Woche gleich über zwei — ich nenne sie mal Ungereimtheiten — stolpere hätte ich nicht erwartet. Zumindest nicht in altehrwürdigen Programmen wie dem allseits beliebten Editor Vim und dem Mail-Client Mutt.
Der Reihe nach, erstmal der Vim: Mir hat die Tagline sehr gut gefallen, die Frank Terbeck sich gebaut hat. Bis vor einer Woche habe ich mich noch nicht um Tabs im Vim bemüht, mit der FTTablineSet() von Frank wird das alles aber schön übersichtlich. Klappt auch prächtig… im Vim7. Ich habe aber auch noch Rechner mit Debian Woody im Einsatz, da ist noch ein Vim6 drauf. Der kannte noch keine Tabs, da kann das also nichts bringen. Also wie einige andere Funktionen nach der Versionsnummer ausklammern, aber das klappt in diesem Fall nicht.
Ich habe das Problem mal etwas eingedampft. Sobald ich eine Funktion mit einer For-Schleife in der Konfiguration habe kriege ich einen Fehler. Minimal sieht das so aus:
if version >= 700
function FunctionTest()
for tabnum in 1
endfor
return 1
endfunction
endif
Das führt im Vim6 beim Start des Editors zu folgender Ausgabe:
E133: :return außerhalb einer Funktion
Drücken Sie die EINGABETASTE oder geben Sie einen Befehl ein
Täusche ich mich, oder sollte der Vim6 den Teil überhaupt nicht ’sehen‘? Naja, ich denke nicht dass es dafür noch einen Patch gibt der mir auf Woody weiterhelfen wird. Erstmal habe ich mir so beholfen, das funktioniert:
" Zusaetzliche Funktionen fuer Vim ab 7.0.0
if version >= 700
source ~/.vim/features700.vim
endif
Und als ich Gestern nochmal eine Mail ansehen wollte die ich zu dem Thema geschrieben habe ist mir was merkwürdiges im Mutt aufgefallen. Ich persönlich bin nicht abgeneigt, das einen Fehler zu nennen, aber die FAQ sagt dass das so gewollt ist. Ich frage mich nur ob und wenn ja wie ich das elegant lösen kann.
Ich möchte Kopien meiner ausgehenden Mails monatlich sortiert in Ordnern ablegen. Das macht Sinn, und die Ordnerstruktur passt dann auch schön wenn ich mal mit Squirrelmail darauf zugreife. Also steht in der Konfiguration folgendes:
set record="=INBOX.Sent.
date +%Y.%m
"
Mein Mutt läuft dauerhaft in einem Screen, wird also in der Regel nur neu gestartet wenn der Rechner neu gestartet wird, was in diesem Fall nur alle paar Monate mal vorkommt — in der Regel nach Stromausfällen. Und die Backticks werden offenbar nur beim Start evaluiert, so dass ausgehende Mails immer im Ordner des Monats landen in dem das Programm gestartet wurde. In der FAQ bei Fefe steht auf die Frage ob das irgendwie mit Bordmitteln geht „No. And that’s on purpose.“ Ich frage mich ob das so immer noch aktuell ist, ich finde das etwas… befremdlich in einem Programm das ansonsten so fein einstellbar ist.
Und eine Cron-Loesung wäre zwar denkbar, aber nicht schön. Wie würde das aussehen? Die Mail-Ordner direkt auf dem Server umverschieben? Geht. Aber auch nur weil ich da Root bin. Ist also nicht allgemein möglich. Und wenn Mutt immer nur nach „Sent“ schreibt, ein Skript sich am Monatsersten per IMAP mit dem Server verbindet und die Ordner umbenennt? Ginge auch, das wäre dann aber nicht mehr kompatibel zur Squirrel-Ordnerstruktur…
Das mit Vim kann ich grad nicht testen (keinen 6.n parat), aber bei Mutt hatte ich das gleiche Problem. Seitdem archiviere ich meine Mails mit http://archivemail.sourceforge.net/
Ja, vielleicht ist es nicht die ideale Loesung die Mails da einfach rumliegen zu lassen. Aber ich bin wirklich irritiert davon dass das ansonsten so flexible so was einfaches nicht kann. Wie gesagt, ich haette es gerne so dass es zum SquirrelMail kompatibel bleibt, und letzteres ist leider nicht annaehernd so flexibel…
Bei gVim 7.1 habe ich folgenden Fehler entdeckt. Ich habe eine Datei, die mit einem a beginnt, gefolgt von zwei Returns und einem b. Das sieht so aus:
a
b
Mit diesem Ersetzungsbefehl
:s#\(a\{-}\)\(\n\n\)*\(\(.\|\n\)\{-}\)#\1\3
müssten eigentlich die beiden Returns entfernt werden, was aber nicht der Fall ist. Statt dessen wird gar nichts an der Datei verändert. Alternativ müsste auch dieser Ersetzungsbefehl die beiden Returns beseitigen, was aber auch nicht der Fall ist:
:s#\(a\{-}\)\(\n\n\)*\(.\{-}\(\n.\{-}\)\{-}\)#\1\3
Bitte keine Hinweise, wie ich die Ersetzungsbefehle verändern müsste, damit sie funktionieren! Es geht mir hier nur darum, dass diese beiden Ersetzungsbefehle syntaktisch in Ordnung sind und deswegen das gewünschte Ergebnis erzielen müssten.
Zweites ähnliches Beispiel. Die Datei ist diese:
ab
cd
Mit dem Ersetzungsbefehl
:s#a\(.\{-}\)\(\n\n\)*\(\(.\|\n\)\{-}\)d#a\1\3d
oder alternativ mit diesem:
:s#a\(.\{-}\)\(\n\n\)*\(.\{-}\(\n.\{-}\)\{-}\)d#a\1\3d
müssten auch die beiden Returns beseitigt werden, was nicht der Fall ist.
Ein weiterer Fehler bei gVim Version 7.1 ist, dass bei der Angabe der Anzahl des Auftretens der Wert Null falsch interpretiert wird. Anstatt dass Vim davon ausgeht, dass dieser Ausdruck an der jeweiligen Stelle des Suchmusters nicht auftreten darf, wird diese Angabe einfach ignoriert. Wenn ich bspw. nach Autofahrer suche und dabei das Wort Autobahnfahrer ignoriert werden soll, könnte ich bspw. das hier so angeben:
/Auto\(bahn\)\[0}fahrer
Alle Wörter, die zwischen Auto und fahrer das Wort bahn haben, werden ignoriert. Hier funktioniert das, weil so eine Angabe einer Suche Blödsinn wäre. Statt dessen könnte man einfach gleich nach Autofahrer suchen.
Was ist aber, wenn ich nach allen Wörtern suche, die das Wort fahrer enthalten sollen (und auch das Wort fahrer selbst), und dabei aber das Wort Bahnfahrer nicht bei den Suchergebnissen erscheinen sollen? Dann gebe ich das ein:
/\(Bahn\)\{0}fahrer
Bei den Suchergebnissen wird die Angabe, dass das Wort Bahn nicht vor dem gesuchten Wort fahrer erscheinen soll, einfach ignoriert, sodass dadurch auch das Wort Bahnfahrer bei den Suchergebnissen dabei ist.
Suche ich bspw. in einer CSS-Datei nach dem Wort Auto, das sich zwischen einer Auskommentierung befinden soll, die mit /* beginnt und mit */ endet, so würde es nicht reichen, dass man im Suchmuster zuerst /*, dann eine beliebige Anzahl von Zeichen .*, dann das Wort Auto und dann */ angibt, weil es dann passieren kann, dass vom ersten gefundenen /* über zahlreiche weitere /* und*/ markiert wird, bis das Wort Auto erreicht ist und dann bis zum abschließenden */ alles markiert ist:
/\/\*\(.\{-}\|\n\)\{-}Auto\(.\{-}\|\n\)\{-}\*\/
Ich habe hier sogar für eine beliebige Anzahl von Zeichen sogar diejenige Angabe gewählt, die für so wenige Zeichen wie möglich steht: .\{-}
Ich habe mir mal die Mühe gemacht, wie man es angeben müsste, damit nur solche Zeichen gefunden werden, die nicht */ enthalten, und zwar so viele wie möglich, nämlich indem man nach
[^*]*.\=[^/]*\([^*/][^*]*.\=[^/]*\)*
sucht. Bei mehr als 2 Zeichen wäre der Ausdruck übrigens sehr viel komplizierter. Damit auch über Zeilenumbrüche hinweg gesucht wird, muss man danach suchen:
[^*]*.\=[^/]*\([^*/][^*]*.\=[^/]*\)*\(\n[^*]*.\=[^/]*\([^*/][^*]*.\=[^/]*\)*\)*
Damit aber alle Zeichen nach /* markiert werden, die sich jeweils noch vor dem nächsten */ (und nicht dem übernächsten) befinden, muss man demzufolge dem vorangegangenen Ausdruck noch /* voranstellen, natürlich gecancelt: \/\*
Das Problem ist aber, wenn ich diesem etwas komplizierterem Suchmuster noch das Wort Auto anfüge, kann gVim 7.1 überhaupt nichts mehr mit dem ganzen anfangen und erstarrt auf der Stelle. Oder kann jemand einen Fehler darin entdecken?
Alternativ sollte man besser die Zeichenfolge, die den Suchausdruck nicht beinhalten soll, durch ein im Text nicht benutztes Symbol ersetzen. Man kann dann einfach angeben, dass nur Zeichen gefunden werden sollen, die dieses Symbol nicht enthalten sollen: [^§]. (Das Symbol § mal hier als Beispiel.)
Auch macht es oft Probleme, wenn Suchausdrücke zeilenübergreifend angegeben werden. Man umgeht das, indem man vor der Bearbeitung alle Zeilenumbrüche \n durch ein nicht im Text verwendetes Zeichen ersetzt.
Ein weiterer Fehler tritt auf, wenn ein Makro aus mehreren aufeinanderfolgenden Ersetzungsbefehlen der Art :s bzw. :%s besteht. Wird bei einem Ersetzungsbefehl der gesuchte Ausdruck nicht gefunden, erscheint eine Meldung, die augenblicklich die Abarbeitung des Makros beendet; sehr geistreich.
Abhilfe schafft der Trick, dass man zur Sicherheit jeweils einen Befehl voranstellt, der erst mal das Gesuchte einfügt, um sicher zu gehen, dass auf jeden Fall was gefunden wird. Oder man benutzt zum Ersetzen den Befehl :g#Wort1#s#Wort1#Wort2#g, der diesen Makel nicht hat.
Nachteil, wenn man diesen Befehl mit solchen Such- und Ersetzungsmustern arbeiten lässt, die jeweils über mehrere Zeilen hinweg vorhanden sind, werden Suchmuster nicht mehr gefunden, wenn diese jeweils mehrmals auf einer Zeile auftreten. Übrigens findet gVim Zeilenumbrüche mit \n. Das Setzen erfolgt aber mit \r. Auch nervig, dass ziemlich häufig diese Meldung erscheint:
„E363: pattern uses more memory than ‚maxmempattern'“ bzw. auf deutsch:
„E363: Muster benötigt mehr Speicher als ‚maxmempattern'“
Besonders oft tritt dieser Fehler bei zeilenübergreifenden Suchmustern auf, bei besonders komplizierten Suchmustern, wenn in Klammern Oder-Ausdrücke sind und bei besonders großen Dateien; wenn das System nicht sogar einfach ohne Meldung einfriert. Nicht immer ist es aber ein Absturz; oftmals muss man auch einige Minuten warten, bis der Vorgang beendet ist.
Für mich ist der gVim eines der am liederlichsten programmierten Programme überhaupt. Die Entwickler haben anscheinend schon lange den Überblick über ihren Software-Verhau hoffnungslos verloren und eines der am blödesten zu bedienendsten Programme überhaupt. Da arbeitet mein altes Windows 98 SE ja noch vergleichsweise sehr viel zuverlässiger und verlässlicher.
Berichtigung zu meinem letzten Beitrag: Wenn man mit dem Befehl :g#Wort1#s#Wort1#Wort2#g einen zeilenübergreifenden Ausdruck ersetzen will, wird ggf. nur ein zweiter in derselben Zeile vorhandener Ausdruck nicht erkannt.
Wenn man bspw. nach verschiedenen Wörtern sucht, die bspw. mit Auto beginnen und mit bahn enden, aber dazwischen nicht das Wort bahn enthalten sollen, so müsste man das so angeben:
auto.\{-}\(bahn\).\{-}fahrer
Also das Wort Auto gefolgt von irgendwelchen Zeichen, dann das Wort bahn (eingeklammert) mit der Mengenangabe = 0; dann wieder irgendwelche Zeichen und zum Schluss das Wort fahrer. Das funktioniert aber nicht. Frech erscheint bspw. auch das Wort Autobahnfahrer als Treffer.
@peter: Ich habe etwas laenger auf Deine Kommentare geantwortet. Allerdings in Form eines neuen Artikels, vielleicht sieht den ja jemand der sich mit dem Thema auskennt und helfen mag.