Zwischenspeicher (Linux-Magazin, März 2012)

Simple Perl-Skripts statten das profane Cut-and-Paste des Linux-Desktops mit zusätzlichen Puffern zum zeitsparenden Editieren aus.

Text auf dem Desktop mit der Maus abgreifen und mittels Cut-and-Paste wieder ablegen gehört zum Standardrepertoire selbst der engstirnigsten Kommandozeilenliebhaber. Genaugenommen unterstützt der Windows-Manager auf dem Linux-Desktop dabei sogar zwei verschiedene Puffermechanismen: Die sogenannte primäre Selektion und das Clipboard ([2]).

Wer mit der Maus eine Textzeile selektiert, kann den Inhalt dieser primären Selektion durch Drücken der mittleren Maustaste irgendwo anders wieder herauspurzeln lassen. Das Clipboard hingegen erfordert, dass der User nach dem Selektieren den Copy-Mechanismus in Gang setzt (üblicherweise mit der Tastenkombination CTRL-C oder dem Menüpunkt Edit->Copy einer grafischen Applikation) und am Zielpunkt die Paste-Funktion aufruft (CTRL-V oder Edit->Paste).

Verwirrte User

Applikationen steht es frei, eines oder beide Verfahren zu implementieren und deshalb kommt es in freier Wildbahn oft zu Verwirrung und frustrierten Anwendern: Während zum Beispiel ein einfaches xterm nur die primäre Selektion kennt, bietet der Adobe-Flashplayer nur den Clipboard-Mechanismus an. Wer Text aus einem xterm in ein in Flashplayer dargestelltes Formular übertragen möchte, schaut mit dem Ofenrohr ins Gebirge. Der Google-Chrome-Browser beherrscht sowohl die primäre als auch die Clipboard-Selektion, läuft auf Chrome allerdings die Web-Applikation von evernote.com, funktioniert die primäre Selektion nicht mehr. Die User raufen sich die Haare.

Wer einen URL aus einem Textfenster kopiert und ihn zum Einholen und Anzeigen einem Browser überreichen möchte, steht oft vor dem Problem, dass der URL im Text umgebrochen wurde und der Browser dann nur den ersten Teil aufschnappt. Ich bin ein bekennendes Unix-Urgestein und lese meine Email in pine in einem screen-Fenster, und damit die Übertragung derartiger URLs klappt, habe ich mir in Firefox unter about:config die Option editor.singleLine.pasteNewlines auf den Wert 3 gesetzt.

Nachhilfe für Chrome

Chrome beherrscht dies allerdings nicht, und deswegen befindet sich in meinem Gnome-Panel am oberen Bildschirmrand ein Propellerhut, hinter dem das Skript in Listing 1 Dienst tut. Es schnappt sich den URL in der primären Selektion, entfernt etwaige Leerzeichen und Zeilenumbrüche und überreicht den gesäuberten URL dem Chrome-Browser.

Abbildung 1: Das hinter der Propellermütze steckende Perlskript schnappt sich den URL aus der primären Textselektion und startet Chrome.

Abbildung 2: Der Chrome-Launcher, der den Chrome-Browser mit der in X-Windows selektierten URL startet.

Zum Zugriff auf die primäre Desktop-Selektion nutzt Listing 1 das CPAN-Modul Clipboard ([3]), das auf der auf Linux laufenden Grafik-Unterlage X-Windows unter der Haube das Programm xclip verwendet. Letzteres lässt sich auf Ubuntu mit sudo apt-get install xclip nachinstallieren. Das CPAN-Modul hat gegenüber der direkten Verwendung von xclip den Vorteil, dass es auch auf einem Mac oder sogar einem Windows-Rechner funktioniert, da es auf diesen Plattformen automatisch auf die nativen Clipboard-Mechanismen umschwenkt.

Listing 1: chrome-select

    01 #!/usr/local/bin/perl -w
    02 use strict;
    03 use local::lib;
    04 use Clipboard;
    05 
    06 my $browser = "/usr/bin/google-chrome";
    07 my $url = Clipboard->paste;
    08 
    09 $url =~ s/\s+//g;
    10 
    11 system( $browser, $url );

Propellermütze hebt ab

Da das Clipboard-Modul zwar mittels der CPAN-Shell, doch unter meiner User-ID in meinem Home-Verzeichnis und nicht unter root installiert wurde, weist local::lib den Perl-Interpreter auf das lokale Verzeichnis hin. Die Methode paste der Klasse Clipboard holt den Inhalt der aktuellen primären Selektion ein, Zeile 9 entfernt mittels eines regulären Ausdrucks unerwünschte Umbrüche und das Kommando system ruft den Chrome-Browser mit dem URL als Argument auf. Wird das Skript in einem "Custom Applicaition Launcher" über den Kontext-Menüpunkt Add to Panel im Panel mit einem leicht erkennbaren Icon eingetragen (Abbildung 2), braucht der User nach der Selektion der URL (ohne Copy-Kommando) nur auf die Propellermütze zu klicken, damit der Chrome-Browser mit der gesäuberten URL hochfährt und der Email-lesende paranoide Dinosaurier zähneknirschend einem Link folgen kann.

Copy per Desktop-Button

Um das eingangs erwähnte Kommunikationsproblem zwischen xterm und dem Flashplayer zu lösen, greift sich Listing 2 die primäre Selektion und schiebt sie aufs Clipboard. Damit der User dieses Kommando auch aus einer Applikation ausführen kann, die den Clipboard-Mechanismus nicht kennt, definiert das Programm gconf-editor in Abbildung 3 ein globales Key-Mapping in Gnomes Window-Manager Metacity. Drückt der User nach dem Selektieren des gewünschten Textabschnitts die Tastenkombination CTRL-ALT-c (definiert im Abschnitt global_keybindings), löst Metacity das konfigurierbare Kommando run_command_2 aus, das im Abschnitt keybinding_commands (Abbildung 4) auf das Skript in Listing 2 gesetzt ist.

Listing 2: primary-to-clipboard

    1 #!/usr/local/bin/perl
    2 use local::lib;
    3 use Clipboard::Xclip;
    4 
    5 my $primary = Clipboard::Xclip->
    6     paste_from_selection( "primary" );
    7 
    8 Clipboard::Xclip->copy_to_selection(
    9     "clipboard", $primary );

Dies ermöglicht es dem User, in einer Applikation, die kein Clipboard kennt, einen Text zu selektieren, und diesen mit CTRL-ALT-c aufs Clipboard zu befördern. In der Zielapplikation, die die primäre Selektion nicht unterstützt, ist dann nur noch CTRL-V zu drücken, um den gewünschten Text herunterzurasseln. Das Skript nutzt die undokumentierten Methoden paste/copy_from_selection der abgeleiteten Klasse Clipboard::Xclip, da die Basisklasse Clipboard keine Unterscheidung der verschiedenen Puffer zulässt.

Abbildung 3: In Gnomes Window-Manager Metacity löst die Tastenkombination CTRL-ALT-c das Kommando 2 aus ...

Abbildung 4: ... das wiederum das Skript primary-to-clipboard zum Kopieren der Selektion aufs Clipboard ausführt.

Cut/Paste auf Steroiden

Wer hat es sich nicht schon einmal gewünscht, mehrere Cut-und-Paste-Puffer zur Verfügung zu haben, um zunächst N Abschnitte zu selektieren und und sie anschließend alle zusammen in einem anderen Fenster abzulegen? Auf einem normalen Gnome-Desktop muss der User dazu N-mal zwischen Quelle und Ziel hin- und herspringen, jeweils einen Abschnitt an der Quelle aufnehmen, und ihn anschließend am Ziel ablegen.

Listing 3 implementiert darum einen persistenten Stack, auf den der User den Inhalt der primären Selektion schieben kann, um mit clipboard-stack push Platz im Puffer für weitere Selektionen freizuräumen. Um eine ausgediente Selektion wieder mit der kürzlich im Stack abgelegten zu ersetzen, ruft der User clipboard-stack pop auf. Das Skript legt die im Stack befindlichen Werte im Array @$stack ab, dessen Inhalt es mittels des CPAN-Moduls YAML persistent in die Datei .clipboard im Home-Verzeichnis schreibt.

Listing 3: clipboard-stack

    01 #!/usr/local/bin/perl -w
    02 use strict;
    03 use local::lib;
    04 use Clipboard;
    05 use YAML qw(DumpFile LoadFile);
    06 
    07 my($home) = glob "~";
    08 my $clipboard = "$home/.clipboard";
    09 
    10 my $stack = [];
    11 $stack = LoadFile( $clipboard ) if 
    12    -f $clipboard;
    13 
    14 my( $command ) = @ARGV;
    15 
    16 die "usage: $0 [push|pop]" if 
    17   !defined $command;
    18 
    19 {
    20   no strict 'refs';
    21   &$command( $stack );
    22 }
    23 
    24 DumpFile( $clipboard, $stack );
    25 
    26 ###########################################
    27 sub push {
    28 ###########################################
    29     my($stack) = @_;
    30 
    31     push @$stack, Clipboard->paste;
    32 }
    33 
    34 ###########################################
    35 sub pop {
    36 ###########################################
    37     my($stack) = @_;
    38 
    39     Clipboard->copy( pop @$stack );
    40 }

Beim erneuten Aufruf des Skripts liest die Funktion LoadFile() des YAML-Moduls die abgelegten Daten wieder ein. Je nachdem, ob der User das Skript mit dem Argument push oder pop aufgerufen hat, springt der Aufruf &$command( $stack ) in Zeile 21 eine der weiter unten definierten Funktionen an. Da das Skript im strict-Modus keine als Textstring vorgegebenen Funktionsaufrufe erlaubt, lockert das Pragma no strict 'refs' in Zeile 20 vorübergehend diese Einschränkung. Die ab Zeile 27 definierte Funktion push() holt mittels der Methode paste() der Klasse Clipboard den selektierten Text ein und schiebt ihn auf den Stack. Die in Zeile 35 definierte Funktion pop() kopiert den archivierten Inhalt mit der Methode copy() in die primäre Selektion. Klickt der User anschließend auf die mittlere Maustaste, fließt der archivierte Inhalt heraus.

Damit der User zum Jonglieren mit den Selektions-Inhalten nicht umständlich ein Perlskript aufrufen muss, erhält das Gnome-Panel für den Selektions-Stack zwei Einträge, die mit zwei formschönen Icons in Pfeilform (gefunden unter /usr/share/icons/Human/48x48/actions als edit-redo.png und edit-undo.png) zum Klicken einladen.

Abbildung 5: Eintragen des Clipboard-Stacks auf dem Gnome-Panel.

Abbildung 6: Der grüne Pfeil schiebt die aktuelle Selektion auf den Stack, der orange Pfeil holt sie wieder.

Zu beachten ist, dass eine aufeinanderfolgende Kombination von Push und Pop nichts bewirkt. Eine Selektion im Puffer kann der User auch sofort wieder irgendwo ablegen, nur falls die Selektion ab ins Archiv soll, weil eine weitere Selektion ansteht, bietet der Stack mit push die erforderliche Funktionalität. Nachdem die aktuelle Selektion dann nicht mehr gebraucht wird, holt der User mit pop die archivierte Selektion aus dem Archiv zurück auf den Desktop.

Klick-Klick-Klick

Statt nach jedem Paste im Clipboard-Archiv aufgereihte Daten per Knopfdruck ins Clipboard nachzufüllen, wäre es nun geradezu revolutionär, den User einfach N-mal klicken zu lassen und zwischendurch automatisch den nächsten Puffer nachzuschieben. Dies hilft zum Beispiel beim Ausfüllen von Web- oder PDF-Formularen, wenn man die Reihenfolge der Felder kennt und die Daten entsprechend im erweiterten Clipboard-Puffer vorab aufgereiht hat. Der User muss dann nur noch von Feld zu Feld springen und jeweils den Paste-Befehl absetzen.

Listing 4 implementiert das Verfahren, in dem es xclip direkt aufruft. Statt der primären Selektion nutzt es im Gegensatz zu den vorher vorgestellten Skripts den Clipboard-Puffer, der mit CTRL-C (Edit->Copy) aufgefüllt und mit CTRL-V (Edit->Paste) entleert wird. Der Grund hierfür liegt schlichtweg in der Tatsache, dass ich das Skript ursprünglich zur Befüllung der Formulardaten einer Flashplayer-Applikation entwickelt habe. Lässt man -selection CLIPBOARD weg, greift es stattdessen auf die primäre Selektion zu und der User muss statt mehrmaligem CTRL-V nur auf die mittlere Maustaste hämmern.

Das Skript iteriert über eine Reihe von Wörtern ("yes", "no", "maybe", "so"), schiebt sie eins nach dem anderen aufs Clipboard und wartet mit -loops 2, bis der User den aktuellen Inhalt mit dem Paste-Kommando freigibt. Daraufhin kehrt das bis dahin blockierende xclip zurück, die Schleife des Perlskripts geht in die nächste Runde und der folgende Aufruf von xclip bekommt über die mit open geöffnete Pipeline das nächste Wort nachgeschoben.

Listing 4: multipaste

    01 #!/usr/local/bin/perl -w
    02 use strict;
    03 
    04 my @words = qw(yes no maybe so);
    05 
    06 for my $word ( @words ) {
    07 
    08     open my $pipe, "|-", 
    09     qw(xclip -verbose 
    10        -selection CLIPBOARD -loops 2);
    11 
    12     print $pipe $word;
    13     close $pipe or die;
    14 }

In Abbildung 7 ist der User, nachdem er in einem anderen Fenster multipaste aufgerufen hat, mit der Maus- oder der Tab-Taste in die verschiedenen Felder des Registrierungsformulars gesprungen und hat jeweils mit CTRL-V einen Paste-Vorgang ausgelöst. Herausgepurzelt aus dem Puffer kam jeweils ein neues Wort aus dem vorher eingetüteten Fundus.

Abbildung 7: Der User hat zunächst multipaste aufgerufen, und ist dann von Feld zu Feld gesprungen und hat jeweils CTRL-V gedrückt.

Wer also oft die gleichen Webformulare ausfüllt, die sich nicht einfach durch Verwendung von APIs oder Screenscraper automatisieren lassen, kann sich auf diese Weise mit einem Skript wie multipaste die Werte in der richtigen Reihenfolge vorab aufbereiten, um später dann immer noch von Hand, aber blitzschnell von Feld zu Feld zu springen und ohne nachdenken zu müssen die richtigen Werte tippfehler- und verdrussfrei einzufügen.

Infos

[1]

Listings zu diesem Artikel: ftp://www.linux-magazin.de/pub/listings/magazin/2012/03/Perl

[2]

"X Selections, Cut Buffers, and Kill Rings", Jamie Zawinski, http://www.jwz.org/doc/x-cut-and-paste.html

[3]

CPAN-Modul Clipboard, http://search.cpan.org/~king/Clipboard-0.13/

Michael Schilli

arbeitet 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.