Im Editor vim
(VI IMproved) stecken eine Unzahl von Tricks,
die im Programmieralltag die Tipparbeit reduzieren. Der
heutige Snapshot zeigt eine Auswahl der effektivsten
Sparmaßnahmen für Perl-Hacker.
Keine Wahl, die ein Programmierer im Leben trifft, ist so entscheidend und so unwiderrufbar wie die Wahl eines Editors. Wer sich einmal für vi oder Emacs entschieden hat, bleibt üblicherweise dabei und setzt alles daran, auch noch den letzten Trick aus dem permanent genutzten Werkzeug herauszufieseln. Wer effektiver mit dem Editor arbeitet, reduziert nicht nur die Gefahr, am Carpal-Tunnel-Syndrom zu erkranken, sondern programmiert erheblich schneller und mit weniger Tippfehlern.
Der Editor vim
ist seinem altersschwachen Kollegen vi
um
einiges voraus. vim wurde über die Jahre für Vieltipper
hochgezüchtet, lässt sich bis ins Detail konfigurieren, mit
Plugins erweitern und so ganz nach Geschmack an den
persönlichen Arbeitsstil anpassen. In der Konfigurationsdatei
.vimrc
im Home-Verzeichnis lassen sich alle heute vorgestellten
Tricks dann permanent abgelegen.
Da Linux-Distributionen nicht immer der neueste vim
beiliegt,
prüft man am Besten mit
vim --version
nach, welche Version vorliegt. Bei weniger als 6.1 empfiehlt sich ein Upgrade.
Farblich unterlegte Schlüsselworte erleichtern das Verstehen von
komplexeren Code-Gebilden erheblich. vim
beherrscht das
Syntax-Highlighting von allerlei Programmiersprachen ganz
hervorragend und produziert selbst für das schwer zu parsende Perl
erstaunlich präzise Ergebnisse. Abbildung 1 und 2 zeigen, wie viel
einfacher farblich herausgestellte Code-Konstrukte erkennbar sind.
Vorraussetzung ist lediglich, dass das benutzte xterm
Farben
unterstützt. Falls nicht schon von Anfang an eingestellt, stellt das Kommando
:syntax on
das Syntax-Highlighting an. Falls vim
an der
Datei-Endung (.pl oder .pm) oder auch am Inhalt (Shebang-Zeile
enthält etwas wie #!/usr/bin/perl
) erkennt, dass es sich um
Perl-Code handelt, kommen die Konstrukte schön zum Vorschein.
Falls eine neue Datei editiert wird, deren Name keine spezifische
Perl-Endung hat und die zum Zeitpunkt des vim
-Aufrufs
noch keine Shebang-Zeile aufwies, lässt sich der Dateityp
nachträglich mit
:set filetype=perl
auf Perl einstellen.
Abbildung 1: vim ohne ... |
Abbildung 2: ... und mit Syntax-Highlighting. |
Wer ständig in der gleichen Sprache programmiert, wiederholt laufend die gleichen Tippmuster. Als Log::Log4perl-Advokat kann ich zum Beispiel schon nicht mehr zählen, wie oft ich
use Log::Log4perl qw(:easy);
getippt habe. Zum Glück hat das jetzt ein Ende, denn das Kommando
:abbreviate ul4p use Log::Log4perl qw(:easy);<RETURN>
definiert die Abkürzung ul4p
. Sobald im Texteingabe-Modus die Zeichenfolge
ul4p
getippt und mit einem Wortbegrenzer wie der Leer- oder Enter-Taste
abgeschlossen wird, expandiert vim
die Folge automatisch zum vordefinierten
Ausdruck. Ein wörtlich eingetipptes <RETURN>
am Ende der Definition
simuliert das Drücken der Enter-Taste.
Wer nach der Expansion nicht im Eingabemodus bleiben, sondern
in den Kommandomodus wechseln möchte, hängt einfach ein
(ebenfalls ausgeschriebenes) <ESC>
hintenan.
Eine weitere Möglichkeit, mit einer Abkürzung ein längeres Textstück
in den Text zu holen, ist, vim
eine Datei hereinholen zu lassen:
:abb ul4p <BACKSPACE><ESC>:r ~/.tmpl_l4p<RETURN>
Sobald nun ul4p
im Text getippt wird und anschließend ein Wortbegrenzer,
ersetzt vim
die Abkürzung nahtlos mit dem Inhalt der angegebenen Datei.
Wiederkehrende Editierschritte, die Modifikationen mehrerer, unzusammenhängender Bereiche erfordern, lassen sich elegant mit Makros duplizieren. Abbildung 3 zeigt drei Funktionsköpfe, die es jeweils in Kommentare einzuranken gilt, wie in Abbildung zwei gezeigt.
Dazu sind
folgende Kommandos nötig: Erst mit /sub
nach sub
suchen, dann den
Makro-Recorder einschalten, den ersten Funktionskopf einranken,
den Makro-Recorder ausschalten. Dann mit n
nach dem nächsten
sub
suchen und mit @a
wieder das Makro abspielen lassen.
Hier sind die Kommandos zusammengefasst:
# Nach 'sub' suchen /sub # Makro-Rekorder # für Makro a einschalten qa # Zeile darüber einfügen, # zurück in Kommandomodus O<ESC> # 20 '#'-Zeichen einfügen 20i#<ESC> # Zeile kopieren yy # Eine Zeile nach unten fahren, kopierte Zeile # unterhalb einfügen. jp # Makro-Rekorder beenden q
# Nach dem nächsten 'sub' suchen /sub # Macro 'a' abspielen @a # ... wiederholen.
Abbildung 3: Der Macro-Editor während der Aufnahme ... |
Abbildung 4: ... und der Nutzer spielt das Macro danach einfach zweimal ab. |
Wer gleich von Anfang an neue Funktionen mit Kommentaren einranken möchte, definiert sich ein neues Kommando auf die Taste ``F'':
:map F o<ESC>43i#<ESC>yyosub {<ENTER><ESC>Pk$i
Drückt der Benutzer dann ``F'' im Kommandomodus,
fügt vim
den Funktionskopf ein und positioniert
den Cursor gleich im Eingabemodus an die richtige Stelle:
########################################### sub { ^ (Cursormarkierung) ###########################################
Der Buchstabensalat in der map
-Definition besteht auch wieder
aus den vi-typischen
Ein-Tasten-Kommandos im Kommandomodus, die jeder vi-Enthusiast auswendig
kennt. Die Anzahl der Hashmarks ist Geschmackssache, in der Definition oben
wurden 43 gewählt.
Bei sich ständig wiederholenden Sequenzen wie Funktionsköpfen
sparen map-Kommandos enorm Zeit und Nerven. Wer möchte, kann
das Kommando noch an die privaten Bedürfnisse anpassen, oft
genutzte Parameterübergaben der Art
my(...) = @_;
bieten sich an.
Eine weitere, sich häufig wiederholende Aufgabe ist das Sichern eines
gerade bearbeiteten Skripts mit :w
und der Aufruf
perl -c skript.pl
um festzustellen, ob sich in das Skript soweit Fehler eingeschlichen haben. Der folgende Befehl legt die Aktionen ``sichern'' und ``perl -c ausführen'' einfach auf die Taste ``X'' (großes X) im Kommandomodus:
:nnoremap X :w<Enter>:!perl -c %<Enter>
Wird statt :map
der Befehl :noremap
verwendet, wird das ``X''
niemals auf der rechten Seite eines anderen map-Ausdrucks evaluiert.
Und :nnoremap
führt die Definition nur im Normal- (also im Kommando-)
Modus durch. Der Platzhalter %
wird durch den Namen der aktuell
editierten Datei ersetzt.
Bei längeren Texten wie POD-Dokumentation stellt sich locker fließender Erzählstil erst beim siebten oder achten Umschreiben ein. Wer dabei fleißig einfügt und wieder ausstreicht, erzeugt zerfledderte Absätze, die schwer korrekturzulesen sind. Textverarbeiter wie Word arbeiten ständig im Hintergrund, um die Absätze umzuformatieren, echte Hacker müssen die Ecken selbst ausbügeln.
Mit vim
geht das mit nur vier Tastendrücken im Kommandomodus:
{-g-q-}
. Zuerst fährt {
an den Anfang des gegenwärtigen Absatzes,
das Kommando gq
(wohl abgeleitet vom englischsprachigen Magazin GQ)
bricht die Zeilen im Flattersatz um, und das abschließende }
bestimmt die Reichweite des Kommandos: Bis zum Ende des Absatzes.
Noch eleganter geht es mit dem Perl-Modul Text::Autoformat
von
Großmeister Damian Conway. Neben Flattersatz kennt es auch noch allerlei
intelligente Umbrüche: So kann es mit Aufzählungen umgehen
(nachfolgende Zeilen eines Aufzählungspunktes
werden entsprechend eingerückt) und auch
mit >
oder >>
oder mehr Eckchen eingerückte
Email-Zitate behandelt es, wie ein Mensch das tun würde.
Wer sich das Kommando
:map f !Gperl -MText::Autoformat -e'autoformat'<RETURN>
definiert, drückt im Kommandomodus einfach die Taste f
, während
der Cursor irgendwo in einem Textabsatz steht, und schon wird
dieser automatisch und sachgemäß formatiert.
Abbildung 5: Eine Auflistung und ein Abschnitt aus einer Email vor ... |
Abbildung 6: ... und nach dem Formatieren mit Text::Autoformat |
Wer die standardmäßig eingestellte Zeilenlänge von 72
Zeichen als zu breit (oder zu schmal) empfindet, kann sie mit
der option right
variieren:
:map f !Gperl -MText::Autoformat -e'autoformat {right=>65}'<RETURN>
Erfahrene vim
-Nutzer merken natürlich sofort, dass f
im Kommandomodus
schon vorbelegt ist: Der Cursor springt bis zum nächsten eingegebenen
Zeichen vor, fe
springt so bis zum nächsten e
im Text. Wer diese
Funktion tatsächlich nutzt, sollte einen anderen Buchstaben wählen
oder auch gerne eine Zweierkombination
einstellen:
:map !f ...
reagiert im Kommandomodus erst, wenn zuerst !
und dann f
eingegeben wird.
Über die Formatierung von Programmcode ist schon viel gestritten worden.
Wo kommen die geschweiften Klammern hin? Wie tief wird verschachtelter
Code eingerückt? Mit Leerzeichen oder mit Tabs? Da jeder Programmierer
seinen eigenen Geschmack hat, bietet vim
genug Optionen.
Beim Einrücken mit Tabs scheiden sich die Geister, viele lehnen sie völlig
ab. Ist die Option
:set expandtab
gesetzt, wandelt vim alle Tabs in Leerzeichen um.
Die Anzahl der Leerzeichen pro Tab bestimmt die Option
:set shiftwidth=4
Wer allerdings expandtab
blindlings setzt, läuft böse auf, wenn ein
Makefile editiert wird: Dort sind Tabs vor den Kommandos für eine Target
tatsächlich notwendig. Werden sie durch Leerzeichen ersetzt, ist dies
ein Syntaxfehler. Die Lösung ist, vim per autocmd
den Dateityp feststellen
zu lassen, und nur bei erkanntem Perl-Programm die Option
expandtab
zu setzen:
:filetype on :autocmd FileType perl :set expandtab
Eine nützliche Option, um sonst unsichtbare Zeichen sichtbar
zu machen, ist :set list
. Alle Tabs erscheinen als ^I und
das Zeilenende ist mit einem blauen '$' mariert.
:set nolist
schaltet wieder zurück in den Normalmodus.
Die oben vorgestellte Option shiftwidth
hat noch eine weitere
Funktion: Zusammen mit der Option cindent
lässt sich so
ordentlich Tipparbeit sparen, denn sobald ein Konstrukt wie
if($really) { _
eingetippt und die Return-Taste gedrückt wird, rückt vim die nächste
Zeile entsprechend shiftwidth
und expandtabs
bereits ein. Tippt
der Benutzer allerdings }
und ein Return, schiebt vim
die schließende
Klammer ebenfalls automatisch wieder an den Zeilenanfang zurück.
Da dieses Verhalten ebenfalls nicht für alle Dateiarten geignet ist,
empfiehlt sich gleichermaßen ein Auto-Kommando, das erst den File-Typ prüft,
bevor die Option gesetzt wird:
:autocmd FileType perl :set cindent
Manchmal stellt sich allerdings erst dann heraus, dass ein Code-Stück
in einen Block muss, wenn es schon getippt wurde. Dann setzt man, wie
in Abbildung 7 gezeigt, einfach geschweifte Klammern darum und tippt
im Kommandomodus die Tastenfolge >i{
, um den 'inneren' Block eine
shiftwidth
-Breite nach rechts einzurücken, wie Abbildung 8 zeigt.
Abbildung 7: Ein Block mit geschweiften Klammern, Cursor auf dem Blockstart ... |
Abbildung 8: und das Kommando >i{ rückt den inneren Block ein. |
Die Option :set smarttab
setzt bei gesetzter expandtab
-Option noch eins
drauf: Ein Backspace im Eingabemodus auf dem ersten Zeichen
einer eingerückten Zeile rückt die
Zeile wieder aus, und ein Druck auf die Tab-Taste rückt sie wieder ein,
ohne dass richtige ``Tabs'' im Spiel sind.
Noch ein Tipp:
Um von einer geschweiften Klammer zur korrespondierenden zu springen,
genügt es, den Cursor auf eine Klammer zu positionieren, und dann
die Prozenttaste (%) im Kommandomodus zu drücken.
So lässt sich leicht feststellen, wo eine geschweifte Klammer fehlt, wenn
perl
einen Syntaxfehler anzeigt.
Wer einmal an einem Computer mit amerikanischer Tastatur sitzt, und
mit vi
einen Umlaut wie Ä eintippen möchte, der kann dies mit der Sequenz
Ctrl-K A :
im Eingabemodus tun. Das scharfe ß kommt mit
Ctrl-K s s
zustande. Die vollständige Tabelle aller so verfügbaren
Umlaute bringt das Kommando :digraphs
zum Vorschein.
Ein neues Perl-Skript startet man recht einfach mit dem tmpl
-Tool
von [4]: Der Aufruf
$ tmpl -p cooltool
legt eine neue Datei cooltool
an. Wie Abbildung 9 zeigt, besteht das
Skript-Skelett aus einigen Kopfzeilen, einigen typischen
Modulen für Skript-Optionen und Manualseitenanzeige. tmpl
bezieht
einige konfigurierbare Parameter aus der Datei .tmpl
im Home-Verzeichnis
des Benutzers:
# ~/.tmpl AUTHOR Mike Schilli YEAR 2005 EMAIL cpan@perlmeister.com
Das Skelett cooltool
kann schon zwei Dinge:
$ cooltool -v
zeigt die gegenwärtige Skriptversion an, die in der Variablen
$CVSVERSION liegt und mittels CVS automatisch aufgefrischt wird.
Weiter hilft Pod::Usage
, dass die Option -h eine kurze Bedienungsanleitung
ausgibt:
$ cooltool -h Usage: cooltool -xyz
Den Rest muss ein zukünftiger Skriptautor dann selbst ausfüllen, aber mit dieser Grundlage ist schon viel erreicht: Ein Grundgerüst, und auch ein Rahmen für Dokumentation, ohne die jedes Skript bekanntermaßen wertlos ist. Pod::Usage sorgt dafür, dass das Skript seine eigene Dokumentation ausgibt, falls etwas schief geht.
Abbildung 9: Ein Template für eine neues Skript 'cooltool'. |
vim
behält geschriebene Wörter automatisch im Kopf und komplettiert
später angefangene Wörter mit der Tastenkombination CTRL-n im Textmodus.
Wer also irgendwo Variablen wie in
our $GLOBAL_SUPER_VARIABLE; our $GLOBAL_OTHER_VARIABLE;
definiert und sie später wieder verwendet, muss nicht den ellenlangen Namen wieder abtippen, sondern schreibt lediglich die ersten paar Buchstaben und drückt dann CTRL-n:
sub foo { print $GL CTRL-n
und schon betätigt sich vim als Gedankenleser:
sub foo { print $GLOBAL_SUPER_VARIABLE
Falls, wie oben, mehrere Möglichkeiten zur Komplettierung führen, kann man mit weiteren CTRL-n vorwärts und mit CTRL-p rückwärts durch die Vorschläge fahren. Ein beinahe triviales Feature, das aber im Lauf der Zeit enorm viel Zeit und Tipparbeit spart.
C-Programmierer kennen das Programm ctags
, das eine tags-Datei
für vim
erzeugt. Wird diese eingelesen, muss der Entwickler
eines Programmes einfach den Cursor irgendwo auf einen Funktionsaufruf
positionieren, und CTRL-]
im Kommandomodus drücken, schon springt
vim
zur zugehörigen Funktionsdefinition.
Um vim
zu veranlassen, zur Source-Datei von LWP::UserAgent zu springen,
falls der Cursor irgendwo auf LWP::UserAgent
in
my $ua = LWP::UserAgent->new();
steht, müssen zwei Dinge erledigt werden: vim
muss verstehen, dass
in Perl ein Schlüsselwort auch Doppelpunkte enthalten kann:
:set iskeyword+=:
und die tags-Datei, die alle installierten Packages indiziert hat, muss eingelesen werden:
:set tags=/home/mschilli/.ptags.txt
Dann springt CTRL-]
in die Modul-Source, wenn der Cursor auf einem
Modulnamen steht. Alternativ kann man den Modulnamen auch
im Kommando :tag LWP::UserAgent
angeben.
Einmal in der Bibliotheksdatei angelangt, genügt ein CTRL-T
,
um wieder zurück zum Ausgangspunkt zu navigieren.
Wenn der Cursor auf einem Modulnamen wie LWP::UserAgent
steht, springt CTRL-]
zur Zeile package LWP::UserAgent;
in /usr/lib/perl5/site_perl/5.8.5/LWP/UserAgent.pm
. Falls
LWP::Debug::trace
unter dem Cursor liegt, springt vim
statt dessen die Zeile sub trace { ...
in
/usr/lib/perl5/site_perl/5.8.5/LWP.pm
an. Die ganze Magie steckt
in der Tags-Datei .ptags.txt
, die das weiter
unten vorgestellte Listing ppitags
erzeugen wird.
Trotz Window-Manager ist es manchmal sinnvoll, zwei Dateien gleichzeitig
in einem Fenster zu sehen. Welcher vim
-User greift schon freiwillig
auf die Maus zurück, wenn die Hände auf der Tastatur bleiben können?
Wer statt CTRL-]
die Kombination CTRL-W-]
tippt, während
der Cursor auf einem Schlüsselwort steht, dessen Fenster
teilt sich in zwei Hälften: In der unteren bleibt der Code der editierten
Datei sichtbar, in der oberen erscheint der Code des referenzierten
Moduls. Zwischen den Fensterhälften springt man mit CTRL-WW
hin
und her. Das Kommando :quit
im oberen Fenster schließt letzteres und das
Hauptfenster gehört wieder ganz der ursprünglich editierten Datei.
Alternativ schließt der Befehl :only
im unteren Fenster das Obere.
Die vim-Session in Abbildung 10 zeigt unten ein editiertes Testskript, dass das Modul LWP::UserAgent verwendet, und oben die new()-Methode im Sourcecode des Moduls.
Abbildung 10: vim mit gespaltenem Fenster: Unten ein Testskript, oben der Sourcecode des verwendeten Moduls LWP::UserAgent. |
Weiss man den Namen eines gesuchten Moduls nicht genau, reicht es,
einen regulären Ausdruck anzugeben. Das Kommando tselect
sucht
nach allen passenden Tags und bietet eine Liste zur Auswahl an:
:tselect /^LWP
Abbildung 11: Tagsuche per regulärem Ausdruck nach C^LWP> bringt ein Menü mit numerierten Treffern. |
In Abbildung 11 muss der Benutzer dann nur den passenden Treffer per Nummernmenü auswählen.
Wie kommt ~/.ptags.txt
zustande? Hierzu müssen regelmäßig sämtliche
Module der lokalen Perl-Installation durchforstet werden. Das Skript
in Listing ppitags
klappert alle @INC
-Pfade ab, merkt sich in
@dirs
, wo es schon mal war und wird auch bei überlappenden Pfaden
nicht zweimal denselben durchforsten.
Um Perl-Source zu analysieren, braucht man eigentlich perl
, denn
Perl ist extrem schwierig zu parsen. Allerdings hat Adam Kennedy vor
kurzem das Unmögliche gewagt und einen ``Good-enough''-Parser für Perl
geschrieben, der wirklich erstaunlich gut ist. Das PPI
-Modul vom
CPAN enthält PPI::Document
, dessen Methode load()
ein Perl-Modul
einliest, in Tokens zerlegt und in einer Baumstruktur ablegt.
ppitags
nutzt File::Find
, um alle Verzeichnisse in Perls globalem
Array @INC
zu durchlaufen. Nur der ebenfalls in @INC
enthaltene Pfad "."
wird ausgelassen.
Für jeden gefundenen Eintrag springt
File::Find
die Funktion file_wanted
an. Falls der gefundene
Eintrag ein Verzeichnis und keine Datei ist, frischt Zeile 28 den
Hash %dirs
auf, um festzustellen, ob der Pfad schon durchlaufen wurde.
Falls ja, setzt Zeile 27 die Variable $File::Find::prune
auf 1, um
File::Find
mitzuteilen, dass es sich den Rest des Verzeichnisses
und alle Unterverzeichnisse
sparen kann. Zeile 31 weist alles außer Perl-Modulen mit der Endung
.pm
zurück.
Zeile 33 parst das aktuell gefundene Perl-Modul. Falls irgendwelche Fehler auftreten, fängt Zeile 35 diese ab (PPI ist noch nicht perfekt), spuckt eine Warnung aus und lässt das problemhafte Modul sausen.
Konnte das Modul erfolgreich eingelesen werden, ruft Zeile 41 die
find()
-Methode des PPI::Document
-Objekts auf, das die
Tokens der Perl-Source durchschreitet und für jeden gefundenen
die ab Zeile 45 definierte Funktion document_wanted
aufruft.
Diese prüft, ob es sich beim gefundenen Token um ein
Objekt vom Typ PPI::Statement::Package
oder PPI::Statement::Sub
handelt, also eine package
oder sub
Definition im Perl-Code.
Eine package
-Definition besteht aus einer Zeile wie
package LWP::UserAgent;
und das sind in der PPI-Welt vier Tokens: package
, Leerzeichen,
der Modulname und der abschließende Strichpunkt. Für die Belange von
ppitags
interessiert nur der Modulname, also das dritte Kind
des Knotens, der in $_[1]
übergeben wurde. Die Methode child()
mit dem ab 0 gezählten Kinderindex fördert den String "LWP::UserAgent"
zutage: $_[1]->child(2)
.
Wird eine package
-Definition durchlaufen, speichert ppitags
dessen
Package-Namen
als aktuelles Package, was zwar durch package-Definitionen in Blocks
leicht ausgehebelt würde, aber das spielt in 99.9% aller Fälle keine
Rolle. ``Good enough'' auch hier.
Zeile 55 stöbert Funktionsdefinitionen der Form sub func {
auf
und extrahiert den Funktions- oder Methodennamen,
damit der Tag-Mechanismus Konstrukte wie LWP::Debug::trace
erkennt und später zu der Stelle springt, an dem die Funktion
trace
im Modul LWP::Debug
definiert ist.
Der push
-Befehl in Zeile 64 schiebt einen neuen String ans
Ende des Arrays @found
, der aus dem gesuchten Tag (Package-
oder voll qualifizierter Funktionsname), dem absoluten
Source-Dateinamen und einem regulären Ausdruck besteht, der
die package
- oder Funktionsdefinition in der Source-Datei
findet. Hierzu bildet die ab Zeile 72 definierte Funktion
regex_from_node
einen regulären Ausdruck, der aus
allen Zeichen der Trefferzeile, vom Zeilenanfang bis zum
gesuchten Token, besteht. Bei einer Subroutine liefert
$node->content()
sowohl Funktionskopf als auch den Rumpf.
Deswegen schneidet Zeile 78 alle Zeilen außer der ersten ab
und die Zeilen 80/81 gehen solange im Token-Baum zurück, bis der
Zeilenanfang erreicht ist. Nach dem Ende der while
-Schleife
steht in $regex
der Inhalt der Source-Zeile, vom Zeilenanfang
bis zum Token. Daraus baut Zeile 88 einen regulären Ausdruck
der Form /^.../
mit einem Anker für den Zeilenanfang.
Die Ersetzung eine Zeile vorher stellt sicher, dass enthaltene
Sonderzeichen nicht mit vim-spezifischen Regex-Metazeichen kollidieren,
indem sie sie allesamt mit einem Backslash maskiert.
ppitags
erzeugt eine Liste von dreispaltigen
Einträgen in ~/.ptags.txt
im Format
Package/Subroutine [tab] Dateiname [tab] Regex
die vim
mit :set tags=
wie oben beschrieben einliest und
damit elegant von Schlüsselworten zum entsprechenden Sourcecode
springt.
ppitags
sollte einmal pro Tag per Cronjob aufgerufen werden, damit
~/.ptags.txt
immer auf dem neuesten Stand ist. Wer möchte, kann
das Skript noch dahingehend
erweitern, dass vim
voll qualifizierte our
-Variablen
(wie zum Beispiel
$Text::Wrap::columns
) erkennt und zu deren Definition in der
Modul-Source springt.
01 #!/usr/bin/perl -w 02 use strict; 03 04 use PPI::Document; 05 use File::Find; 06 use Sysadm::Install qw(:all); 07 use Log::Log4perl qw(:easy); 08 09 my $outfile = "$ENV{HOME}/.ptags.txt"; 10 my %dirs = (); 11 my @found = (); 12 13 find \&file_wanted, grep {$_ ne "."} @INC; 14 15 blurt join("\n", sort @found), $outfile; 16 17 ########################################### 18 sub file_wanted { 19 ########################################### 20 my $abs = $File::Find::name; 21 22 # Avoid dupe dirs 23 $File::Find::prune = 1 if -d and 24 $dirs{$abs}++; 25 26 # Only Perl modules 27 return unless /\.pm$/; 28 29 my $d = PPI::Document->load($abs); 30 31 unless($d) { 32 WARN "Cannot load $abs ($! $@)"; 33 return; 34 } 35 # Find packages and 36 # all named subroutines 37 $d->find(\&document_wanted); 38 } 39 40 ########################################### 41 sub document_wanted { 42 ########################################### 43 our $package; 44 my $tag; 45 46 if(ref($_[1]) eq 47 'PPI::Statement::Package') { 48 $tag = $_[1]->child(2)->content(); 49 $package = $tag; 50 51 } elsif(ref($_[1]) eq 52 'PPI::Statement::Sub' and 53 $_[1]->name()) { 54 $tag = "$package\::" . 55 $_[1]->name(); 56 } 57 58 return 1 unless defined $tag; 59 60 push @found, $tag . "\t" . 61 $File::Find::name . "\t" . 62 regex_from_node($_[1]); 63 64 return 1; 65 } 66 67 ########################################### 68 sub regex_from_node { 69 ########################################### 70 my($node) = @_; 71 72 my $regex = $node->content(); 73 74 $regex =~ s/\n.*//gs; 75 76 while(my $prev = 77 $node->previous_sibling()) { 78 last if $prev =~ /\n/; 79 $regex = $prev->content() . 80 $regex; 81 $node = $prev; 82 } 83 84 $regex =~ s#[/.*[\]^\$]#\\$&#g; 85 return "/^$regex/"; 86 }
Die Datei .vimrc
im Home-Verzeichnis wird von vim
beim
Programmstart eingelesen und erlaubt es, eine ganze Litanei von
Kommandos auszuführen, bevor vim
die eigentliche Arbeit beginnt.
Wer die Standardeinstellungen interaktiv verschraubt hat, möchte diese
wahrscheinlich permanent festhalten. Statt die eingegebenen Kommandos
nochmals manuell in .vimrc einzutragen, genügt ein einfaches
:mkvimrc
, mit dem vim alle zur Zeit gültigen Einstellungen in
~/.vimrc
ablegt.
Unter [1] liegt eine Beispielkonfiguration mit allen heute vorgestellten Einstellungen. Wer Tipparbeit spart, hat mehr Zeit zum Denken!
01 version 6.0 02 :map !L iuse Log::Log4perl qw(:easy);<RETURN>Log::Log4perl->easy_init($DEBUG);<RETURN><ESC> 03 :map F o<ESC>43i#<ESC>yyosub {<ENTER><ESC>Pk$i 04 map f !Gperl -MText::Autoformat -e'autoformat{right=>70}' 05 set backspace=2 06 set fileencodings=utf-8,latin1 07 set formatoptions=tcql 08 set helplang=en 09 set history=50 10 set hlsearch 11 set ruler 12 set shiftwidth=4 13 :autocmd FileType perl :set cindent 14 :autocmd FileType perl :set expandtab 15 :autocmd Filetype perl :set smarttab 16 :nnoremap X :w<Enter>:!perl -c %<Enter> 17 :set tags=/home/mschilli/.ptags.txt 18 :set iskeyword+=:
tmpl
Skript: http://perlmeister.com/scripts/tmpl
Michael Schilliarbeitet als Software-Engineer bei Yahoo! in Sunnyvale, Kalifornien. Er hat "Goto Perl 5" (deutsch) und "Perl Power" (englisch) für Addison-Wesley geschrieben und ist unter mschilli@perlmeister.com zu erreichen. Seine Homepage: http://perlmeister.com. |