| 1 |
=head1 Rxvt-Unicode: jetzt mit Mega-Perl! |
| 2 |
|
| 3 |
=head2 Zusammenfassung |
| 4 |
|
| 5 |
Seit Anfang des Jahres besitzt der X11 Terminal-Emulator "Rxvt-Unicode" |
| 6 |
einen eingebetteten Perl-Interpreter. |
| 7 |
|
| 8 |
Dieser wird jetzt schon benutzt, um z.B. die Selection intelligenter zu |
| 9 |
gestalten, um mehrere Terminals durch Reiter zu kombinieren, Popup-Menüs |
| 10 |
zu implementieren, Text zu formatieren, den Scrollback-Puffer durchsuchbar |
| 11 |
zu machen, OnTheSpot-Editing für Eingabemethoden (XIM, X Input Methods) zu |
| 12 |
implementieren und vieles, vieles mehr. |
| 13 |
|
| 14 |
Dies erfüllt meinen lang gehegten Traum, meine Hauptschnittstelle |
| 15 |
zum Rechner noch besser anpassen zu können. |
| 16 |
|
| 17 |
=head1 Einführung |
| 18 |
|
| 19 |
Rxvt-Unicode ist Ende 2003 aus dem Frust heraus entstanden, daß es keine |
| 20 |
guten und Unicode-fähigen Terminals gab. Mlterm war der beste Kandidat |
| 21 |
(sehr schlank, sehr gute Rendering-Fähigkeiten, gutes internes Design), |
| 22 |
aber mein Problem der gleichzeitigen Darstellung von Umlauten und Kanji |
| 23 |
hat es leider nicht gelöst: Dafür braucht man zwei Schriftarten, und |
| 24 |
mlterm konnte dies nur für die Kombination ASCII/sonstiges. |
| 25 |
|
| 26 |
Aber philosophische Gedanken beiseite: Als erstes wurde rxvt in C++ |
| 27 |
"übersetzt" und die richtige Interpretation von Locales beigebracht: Das |
| 28 |
"Unicode" bezieht sich auf die interne Speicherung der Zeichen, nicht |
| 29 |
auf die Festlegung von z.B. UTF-8 als Ein-/Ausgabeencoding, da hält |
| 30 |
sich Rxvt-Unicode an die vom Benutzer eingestellte Locale (wie auch bei |
| 31 |
Dingen wie die Breite der Zeichen, aber das geht schon wieder in Richtung |
| 32 |
Philosophie). |
| 33 |
|
| 34 |
Lange Jahre hindurch wünschte ich mir aber mehr |
| 35 |
Eingriffsmöglichkeiten: Ich dachte immer, wie schön es wäre, wenn man |
| 36 |
z.B. durch einen externen Prozess intelligentere Steuerungen oder |
| 37 |
Feedback-Möglichkeiten hätte. Erst Anfang des Jahres kam mir die Idee, |
| 38 |
nicht eine aufwendige sprachenunabhängige Schnittstelle zu implementieren, |
| 39 |
sondern einfach Perl einzubetten, womit ich mehr Erfahrung hatte und was |
| 40 |
auch eine einfachere Implementierung zuließ. |
| 41 |
|
| 42 |
Ein wichtiger Punkt ist der erhöhte Speicherbedarf, da Rxvt-Unicode |
| 43 |
den Ruf hat, sehr ressourcenschonend zu sein: Statt 3MB |
| 44 |
für ein full-featured Terminal sind es nun eher 7MB, dank |
| 45 |
Perl-Speicherverbrauchstechnologie. Aber da I<ein> Rxvt-Unicode Prozess |
| 46 |
beliebig viele Fenster öffnen kann (wobei die Kosten von Perl auf diese |
| 47 |
verteilt werden), ein Xft-Font mit 10MB+ und gängige Terminals wie KDEs |
| 48 |
Konsole durchaus mal mit 60MB+ zuschlagen können, dachte ich "no big |
| 49 |
deal", und es war eine gute Entscheidung :). |
| 50 |
|
| 51 |
=head1 Das "Wie" der Perl-Erweiterungen |
| 52 |
|
| 53 |
Rxvt-Unicode kommt von Hause aus mit einer Menge Perl-Erweiterugen. Hat |
| 54 |
man das Paket heruntergeladen, kann man sich diese in F<src/perl> |
| 55 |
anschauen (sie sind zur Zeit alle in der urxvtperl(7)-Manpage |
| 56 |
beschrieben). Ist das Paket schon installiert, muss man im |
| 57 |
F<../lib/urxvt/perl>-Verzeichnis nachschauen. |
| 58 |
|
| 59 |
Eigene Erweiterungen kann man ganz einfach erstellen und benutzen: |
| 60 |
|
| 61 |
mkdir extensions |
| 62 |
vi extentions/myext |
| 63 |
urxvt --perl-lib $PWD/extensions -pe myext |
| 64 |
|
| 65 |
Die Perl-Erweiterung (Methode etc.) ist I<komplett> in der |
| 66 |
urxvtperl(7)-Manpage dokumentiert. |
| 67 |
|
| 68 |
=head1 Beispiele, Beispiele... Beispiele! |
| 69 |
|
| 70 |
=head2 Pseudo-Transparenz (C<-pe automove-background>) |
| 71 |
|
| 72 |
Viele Leute wünschen sich pseudotransparente Terminals. Ich nicht. Daher |
| 73 |
hatte ich keinen Bock, eine häufig gewünschte Erweiterung zu |
| 74 |
implementieren (schon garnicht in C++): da es stets Probleme macht, das |
| 75 |
aktuelle Hintergrundbild zu identifizieren, könnte man da nicht ein |
| 76 |
normales Terminal-Hintergrundbild angeben, dieses aber je nach Position |
| 77 |
des Fensters auf dme Schirm verschieben? Das hätte sogar den Vorteil, |
| 78 |
viel schneller zu sein, da man Effekte wie Schatten u.ä. vorher in seinem |
| 79 |
Malprogramm erreichen kann. |
| 80 |
|
| 81 |
Der erste Versuch in Perl war schnell geschreiben: |
| 82 |
|
| 83 |
sub on_configure_notify { |
| 84 |
my ($self, $event) = @_; |
| 85 |
|
| 86 |
$self->cmd_parse ("\033]20;;=+$event->{x}+$event->{y}\007"); |
| 87 |
} |
| 88 |
|
| 89 |
Ja, das ist die komplette Erweiterung: Jede Erweiterung ist (intern) |
| 90 |
eine Perl-Klasse, und für jedes Terminal-Fenster wird ein neues Objekt |
| 91 |
für jede daran gebundene Erweiterung erzeugt, das C<$self> ist also ein |
| 92 |
echtes Erweiterungs-"Objekt", daß von der C<urxvt::term>-Klasse (indirekt) |
| 93 |
abgeleitet ist. |
| 94 |
|
| 95 |
Rxvt-Unicode selbst ruft nur Methoden mit Namen auf, die mit C<on_> |
| 96 |
beginnen, und das immer bei bestimmten Ereignissen. Im obigen Beispiel, |
| 97 |
wenn ein B<ConfigureNotify>-Event eintrifft, der bei Größenänderungen und |
| 98 |
Verschiebungen des Fensters aufgerufen wird. |
| 99 |
|
| 100 |
Danach wird eine Escape-Sequenz generiert, die das Hintergrundbild |
| 101 |
verschiebt (alle Escape-Sequenzen sind in der urxvt(7)-Manpage |
| 102 |
dokumentiert) und dem Terminal per C<cmd_parse> eingegeben, wodurch sie |
| 103 |
so interpretiert werden, als ob das im Terminal laufende Programm sie |
| 104 |
ausgegeben hätte. |
| 105 |
|
| 106 |
Das klappte schon so halb, leider stimmen die Koordinaten im |
| 107 |
ConfigureNotify-event nicht immer, daher muss man explizit den server |
| 108 |
fragen, wo das Fenster denn nun gerade ist: |
| 109 |
|
| 110 |
sub on_configure_notify { |
| 111 |
my ($self, $event) = @_; |
| 112 |
|
| 113 |
my ($x, $y) = $self->XTranslateCoordinates ( |
| 114 |
$self->vt, $self->DefaultRootWindow, |
| 115 |
0, 0 |
| 116 |
); |
| 117 |
|
| 118 |
$self->cmd_parse ("\033]20;;=+$x+$y\007"); |
| 119 |
} |
| 120 |
|
| 121 |
Das klappt in allen Fällen. |
| 122 |
|
| 123 |
=head2 Eine Digitaluhr im Terminal (C<-pe digital-clock>) |
| 124 |
|
| 125 |
Klar, braucht jeder. Umso erstaunlicher ist es, daß dies die erste |
| 126 |
Erweiterung war, die existierte, weil sie recht viel Funktionalität |
| 127 |
testet. Tatsächlich soll es Leute geben, die sie benutzen. |
| 128 |
|
| 129 |
Hier ist sie: |
| 130 |
|
| 131 |
sub on_start { |
| 132 |
my ($self) = @_; |
| 133 |
|
| 134 |
$self->{overlay} = $self->overlay (-1, 0, 8, 1, urxvt::OVERLAY_RSTYLE, 0); |
| 135 |
$self->{timer} = urxvt::timer |
| 136 |
->new |
| 137 |
->start (1 + int urxvt::NOW) # make sure we update "on" the second |
| 138 |
->interval (1) |
| 139 |
->cb (sub { |
| 140 |
$self->{overlay}->set (0, 0, |
| 141 |
sprintf "%2d:%02d:%02d", (localtime urxvt::NOW)[2,1,0]); |
| 142 |
}); |
| 143 |
|
| 144 |
() |
| 145 |
} |
| 146 |
|
| 147 |
Die C<on_start>-Methode wird aufgerufen, nachdem das Terminal komplett |
| 148 |
initialisiert wurde und daher komplett funktionsfähig ist. |
| 149 |
|
| 150 |
Die obige C<on_start>-Methode erzeugt zuerst ein I<Overlay>. Das ist ein |
| 151 |
rechteckiger Kasten, der "über" dem normalen Terminal-Inhalt liegt und |
| 152 |
für Menüs und andere Dinge genutzt werden kann. Die Position ist C<-1, 0> |
| 153 |
(rechts, oben), die Größe ist C<8, 1> (8 Spalten, eine Zeile), und die |
| 154 |
initiale Farbgebung ist C<urxvt::OVERLAY_RSTYLE>, schwarz auf grellgelb. |
| 155 |
|
| 156 |
Danach wird ein Timer erzeugt, der einmal pro Sekunde am Sekundenanfang |
| 157 |
feuert. Der Callback ersetzt den Text im Overlay durch eine einfache |
| 158 |
Digitalanzeige. |
| 159 |
|
| 160 |
Wichtig ist, daß Overlays, Timer usw. direkt in C<%$self> gespeichert |
| 161 |
werden. Der Grund ist nicht sofort ersichtlich: Solange noch irgendwelche |
| 162 |
Event-Watcher (Zeitgeber, Datei-Watcher, Prozess-Watcher usf.) aktiv sind, |
| 163 |
endet der Prozess nicht. |
| 164 |
|
| 165 |
Merkt man sich den Timer in einer C<my>-Variable, wird er beim Löschen des |
| 166 |
Fensters vielleicht nicht freigegeben und läuft weiter, und er Benutzer |
| 167 |
wundert sich, warum Rxvt-Unicode weiterläuft, obwohl er das Fenster geschlossen |
| 168 |
hat. |
| 169 |
|
| 170 |
C<%$self> wird dagegen automatisch geleert, was Timer und andere Objekte |
| 171 |
automatisch zerstört. |
| 172 |
|
| 173 |
Im Prinzip kann man Rxvt-Unicode als Perl-Daemon betrachten, der I<auch> |
| 174 |
Terminal-Fenster aufmachen kann. Ach ja, er unterstützt natürlich |
| 175 |
auch C<AnyEvent>, allerdings nur non-blocking (wäre doof, wenn das |
| 176 |
Terminal Minuten oder auch nur Sekunden "steht"). Näheres im Beitrag |
| 177 |
"Ereignisgesteuerte Programmierung". |
| 178 |
|
| 179 |
=head2 URLs markieren und anklickbar gestalten (C<-pe mark-urls>) |
| 180 |
|
| 181 |
Noch ein Feature, daß nur existiert weil es so simpel zu implementieren |
| 182 |
war, ist die C<mark-urls> Erweiterung: Sie unterstreicht alle URLs (naja, |
| 183 |
zumindest viele) im Terminal-Fenster. Wenn man draufklickt, startet sie |
| 184 |
einen Browser. |
| 185 |
|
| 186 |
Zuerst zu dem Teil, der die Sache mit der Unterstreichung regelt: |
| 187 |
|
| 188 |
my $url = |
| 189 |
qr{( |
| 190 |
(?:https?|ftp|news|mailto|file)://[ab-zA-Z0-9\-\@;\/?:&=%\$_.+!*\x27(),~]+ |
| 191 |
[ab-zA-Z0-9\-\@;\/?:&=%\$_+!*\x27()~] # exclude some trailing characters (heuristic) |
| 192 |
)}x; |
| 193 |
|
| 194 |
Diese horrende Regex versucht, "übliche" URLs zu matchen. Muss man nicht |
| 195 |
lesen können, klappt aber gut. |
| 196 |
|
| 197 |
sub on_line_update { |
| 198 |
my ($self, $row) = @_; |
| 199 |
|
| 200 |
Die C<on_line_update>-Methode wird (meistens) aufgerufen, wenn eine Zeile |
| 201 |
dargestellt wird, die bisher noch nicht durch Perl gefiltert wurde. Das |
| 202 |
bedeutet schlicht, daß man jeden angezeigten Text filtern kann. Wird |
| 203 |
eine Zeile verändert, wird die Methode nochmals aufgerufen. Man muss |
| 204 |
nur aufpassen, daß die Zeile eventuell schon Änderungen von vorherigen |
| 205 |
Aufrufen enthält, so daß man zwar Unterstreichung gefahrlos anschalten, |
| 206 |
aber nicht Togglen darf. |
| 207 |
|
| 208 |
Das "langsame" Perl behindert übrigens nicht das Scrolling: Obwohl Perl so |
| 209 |
"langsam" ist, hat es erstaunlich wenig Einfluß auf die Geschwindigkeit, |
| 210 |
obwohl es pro Bildschirmrefresh 30 mal oder mehr aufgerufen wird (je |
| 211 |
nach Zeilenzahl). Außerdem ruft Rxvt-Unicode Perl nicht auf, wenn es an |
| 212 |
der Grenze des technisch Möglichen (Last!) scrollt. Anders als andere |
| 213 |
Terminals (die kleinen Wichtel, äh Gnome, kommen mir da in den Sinn) |
| 214 |
gibt es im Normalfall aber auch keine Zeitverzögerung, d.h. die URLs |
| 215 |
erscheinen, sofern die Last es zuläßt, sofort unterstrichen und nicht erst |
| 216 |
nach kurzer Verzögerung. |
| 217 |
|
| 218 |
Eine "kleine" Bemerkung zum Begriff "Zeile" (line): Ein Terminal ist |
| 219 |
ein rechteckiges Raster aus vielen, immer gleich großen, "Zellen", |
| 220 |
die einzelne Zeichen (oder Teile derselben) enthalten können. Diese |
| 221 |
werden in "Reihen" (eigentlich Zeilen) ("rows") und Spalten ("columns") |
| 222 |
eingeteilt. Darüberhinaus gibt es aber Absätze, die aus langen Zeilen |
| 223 |
bestehen, die in mehrere "Reihen" aufgespalten wurden. Diese Absätze |
| 224 |
werden "Zeilen" (lines) genannt, wobei die Unterscheidung von Zeilen |
| 225 |
vs. Reihen (lines vs. rows) im Deutschen etwas künstlich ist: korrekt |
| 226 |
wäre es, von Absätzen zu sprechen, wenn man potentiell lange, mehrzeilige |
| 227 |
"Zeilen" meint, aber ich werfe das immer durcheinander: Zeilen kann also |
| 228 |
mal Absatz, mal Einzelzeile/Reihe bedeutet. |
| 229 |
|
| 230 |
C<on_line_update> wirds jedenfalls pro Absatz, nicht pro Terminal-Zeile |
| 231 |
aufgerufen. Zurück zum Quelltext, der als allererstes die entsprechende |
| 232 |
Zeile ausliest: |
| 233 |
|
| 234 |
# fetch the line that has changed |
| 235 |
my $line = $self->line ($row); |
| 236 |
my $text = $line->t; |
| 237 |
|
| 238 |
C<$row> ist immer die oberste Zeile, und C<< $self->line >> erzeugt ein |
| 239 |
"Absatz-Objekt", daß man manipulieren kann. |
| 240 |
|
| 241 |
Nun müssen noch alle URLs in der Zeile gefunden werden: |
| 242 |
|
| 243 |
# find all urls (if any) |
| 244 |
while ($text =~ /$url/g) { |
| 245 |
|
| 246 |
Und unterstrichen werden: |
| 247 |
|
| 248 |
my $rend = $line->r; |
| 249 |
|
| 250 |
$_ |= urxvt::RS_Uline |
| 251 |
for @{$rend}[ $-[1] .. $+[1] - 1]; |
| 252 |
|
| 253 |
$line->r ($rend); |
| 254 |
} |
| 255 |
|
| 256 |
Zum Unterstreichen werden die Zeichenattribute ("rendition") |
| 257 |
der Zeile gelesen, für die entsprechenden Zeichen wird das |
| 258 |
C<urxvt::RS_Uline>-Attribut (naja, "Bit") gesetzt, und wieder |
| 259 |
geschrieben. Ergebnis: URL wird unterstrichen. Fertig: |
| 260 |
|
| 261 |
() |
| 262 |
} |
| 263 |
|
| 264 |
Das C<()> sorgt dafür, daß nicht aus Versehen etwas zurückgegeben wird, |
| 265 |
was nicht zurückgegeben werden soll: Alle C<on_>*-Methoden sollten nichts |
| 266 |
zurückliefern, sofern sie nicht das Ereignis "fressen": Wenn z.B. ein |
| 267 |
Mausklick verarbeitet wird, entscheidet der Rückgabewert darüber, ob |
| 268 |
Rxvt-Unicode ihn Intern weiterverarbeitet (C<()>) oder ignoriert (C<1>). |
| 269 |
|
| 270 |
Die URL zusätzlich anklickbar zu machen, erfordert einen gedanklichen |
| 271 |
Spagat und etwas Vorsicht, ist aber prinzipiell der gleiche Vorgang: |
| 272 |
|
| 273 |
sub on_start { |
| 274 |
my ($self) = @_; |
| 275 |
|
| 276 |
$self->{browser} = $self->x_resource ("urlLauncher") || "x-www-browser"; |
| 277 |
|
| 278 |
() |
| 279 |
} |
| 280 |
|
| 281 |
Zuerst schaut die Erweiterung nach der C<urlLauncher>-Resource. Auf diese |
| 282 |
Weise kann man konfigurieren, welchen "Browser" man denn gerne hätte: |
| 283 |
|
| 284 |
URxvt.urlLauncher: links -g |
| 285 |
|
| 286 |
Dies sollte man unbedingt in C<on_start> machen, da es nur eine |
| 287 |
Resourcedatenbank für alle Terminals gibt und diese nur beim Start |
| 288 |
aktuell ist. Keinsfalls sollte man globale Variablen verwenden, da es |
| 289 |
durchaus Benutzer gibt, die verschiedene Terminal-Fenster verschieden |
| 290 |
konfigurieren, und globale Variablen sind für alle Terminal-Fenster eines |
| 291 |
Prozesses gleich. |
| 292 |
|
| 293 |
Für den "Klick" muss man noch die C<on_button_release>-Methode implementieren: |
| 294 |
|
| 295 |
sub on_button_release { |
| 296 |
my ($self, $event) = @_; |
| 297 |
|
| 298 |
my $mask = $self->ModLevel3Mask | $self->ModMetaMask |
| 299 |
| urxvt::ShiftMask | urxvt::ControlMask; |
| 300 |
|
| 301 |
if ($event->{button} == 2 && ($event->{state} & $mask) == 0) { |
| 302 |
|
| 303 |
Das C<if> sorgt dafür, daß nur bei "normalen" Klicks (keine wichtigen |
| 304 |
Modifer-Tasten wie Ctrl gedrückt), und nur mit der mittleren Maustaste |
| 305 |
angeklickt werden kann (ich finde das nicht intuitiv mit der mittleren |
| 306 |
Taste, aber mir wurde gesagt, gnome-terminal würde es ebenfalls so machen, |
| 307 |
und gnome-terminal hat bei solchen Features per Definition recht, solange |
| 308 |
es sich an das hält, was KDEs Konsole auch tut und es I<nicht> hilfreich |
| 309 |
beim Arbeiten ist. Hmmja). |
| 310 |
|
| 311 |
In C<($row,$col)> steht die Koordinate des Klicks. Doch welche URL |
| 312 |
befindet sich darunter? Da man (noch) keine Daten mit Zeilen verknüpfen |
| 313 |
kann, muss man - wie beim Markieren - auch alle URLs suchen und diejenige |
| 314 |
finden, die sich unterhalb des Maus-Cursors befindet: |
| 315 |
|
| 316 |
my $row = $event->{row}; |
| 317 |
my $col = $event->{col}; |
| 318 |
|
| 319 |
my $line = $self->line ($row); |
| 320 |
my $text = $line->t; |
| 321 |
|
| 322 |
while ($text =~ /$url/g) { |
| 323 |
if ($-[1] <= $col && $+[1] >= $col) { |
| 324 |
$self->exec_async ($self->{browser}, $1); |
| 325 |
return 1; |
| 326 |
} |
| 327 |
} |
| 328 |
} |
| 329 |
|
| 330 |
() |
| 331 |
} |
| 332 |
|
| 333 |
Die C<exec_async>-Methode startet ein externes Programm, hier den |
| 334 |
Browser. Sie ist besser als ein einfaches C<system>, daß sie das richtige |
| 335 |
%ENV setzt (wie schon bemerkt, kann ein einzelner Prozess viele Fenster |
| 336 |
mit unterschiedlichen Environment-Variablen haben). |
| 337 |
|
| 338 |
=head2 Blockgrafik-nach-ASCII (C<-pe block-graphics-to-ascii>) |
| 339 |
|
| 340 |
Dies ist ein einfacher Filter, um alle Blockgrafikzeichen durch |
| 341 |
ASCII-Zeichen zu ersetzen: |
| 342 |
|
| 343 |
sub on_add_lines { |
| 344 |
my ($self, $str) = @_; |
| 345 |
|
| 346 |
$str =~ s/([\x{2500}-\x{259f}])/substr $rep_unicode, (ord $1) - 0x2500, 1/ge; |
| 347 |
|
| 348 |
$self->scr_add_lines ($str); |
| 349 |
|
| 350 |
1 |
| 351 |
} |
| 352 |
|
| 353 |
(In Wahrheit etwas komplexer, da es in Vor-Unicode-Zeichen etwas anders |
| 354 |
gemacht wurde). Eine Erklärung ist fast nicht notwendig: C<on_add_lines> |
| 355 |
wird aufgerufen, wenn Text ausgegeben werden soll. In diesem werden |
| 356 |
Unicode-Blockgrafikzeichen durch ASCII-Äquivalente in C<$rep_unicode> |
| 357 |
(Definition steht nur in der Quelldatei, da der Perlworkshop noch nicht |
| 358 |
Unicode-fähig ist) ersetzt und ausgegeben. Die C<1> am Ende sorgt dafür, |
| 359 |
daß Rxvt-Unicode den Text nicht mehr ausgibt. |
| 360 |
|
| 361 |
=head1 Weitere Erweiterungen |
| 362 |
|
| 363 |
Es gibt noch eine Menge weiterer Erweiterungen, die z.B. asynchrone |
| 364 |
Kommunikation mit Pipes benutzen, um eine Art Distributed Shared Clipboard |
| 365 |
zu implementieren (C<-pe remote-clipboard>), Popups implementieren (C<-pe |
| 366 |
selection-popup>), die übrigens nichts anderes als kleine Terminal-Fenster |
| 367 |
sind, inkrementelles Suchen im Scrollback-Buffer ermöglichen (C<-pe |
| 368 |
scrollback-search>), "Tabbed Terminals" (C<-pe tabbed>), Cursor-Movement |
| 369 |
per Mausklick (C<-pe readline>) und einiges andere mehr. |
| 370 |
|
| 371 |
Natürlich gibt es auch einfach nur "Nützliches", wie die intelligentere |
| 372 |
Selection, die auch bei hartnäckigen Fällen korrekt Shell-Argumente |
| 373 |
parsed... |
| 374 |
|
| 375 |
cerebro ~/src/rxvt-unicode/src# ls da"t ei"\ .txt |
| 376 |
^^^^^^^^^^^^^^ |
| 377 |
|
| 378 |
oder eine vom Benutzer getätige Selection sofort transformiert: |
| 379 |
|
| 380 |
syntax error at /opt/rxvt/lib/urxvt/urxvt.pm line 957, near "_exit 255" |
| 381 |
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| 382 |
|
| 383 |
Selektiert man das Unterstrichene, landet bei mir folgendes in der |
| 384 |
Selection: |
| 385 |
|
| 386 |
:e \/opt\/rxvt\/lib\/urxvt\/urxvt\.pm |
| 387 |
:957 |
| 388 |
|
| 389 |
Das muss ich nur noch in meinen VI[M] pasten und bin sofort an der richtigen |
| 390 |
Stelle. |
| 391 |
|
| 392 |
Ich hoffe, dem Ein- oder Anderen habe ich etwas Lust gemacht, sein |
| 393 |
bevorzugtes Man-Machine-Interface an die eigenen Bedürfnisse anzupassen |
| 394 |
und noch intelligenter zu gestalten. |
| 395 |
|
| 396 |
=head1 Danke... |
| 397 |
|
| 398 |
... an Ralf Valerien für seine Kommentare und Korrekturen. |
| 399 |
|
| 400 |
|
| 401 |
|