Im zweiten Teil der Reihe brechen wir den Willen des Monsters XEmacs endgültig, indem wir ihm in seiner Sprache Befehle erteilen. Außerdem entlocken wir ihm sein Geheimnis, wie er uns mit verschiedenen Dateitypen Hilfe leisten kann. Auf in den Kampf!
Nachdem wir uns im ersten Teil mit den vermeintlich kryptischen und komplizierten Tastenkombinationen beschäftigt haben, widerlegen wir in diesem Teil das Vorurteil, XEmacs sei für den Anfänger nicht konfigurierbar, da dies mit einer merkwürdigen Programmiersprache erfolge.
Richtig ist an diesem Vorurteil nur, dass die Programmiersprache merkwürdig ist. Denn der Name dieser Sprache, Lisp, wird auch von gewieften Programmierern mit Lots of Infernal Stupid Parentheses! (sinngemäß: Viele teuflische, dumme Klammern) übersetzt. In Wahrheit steht Lisp allerdings für List Processor (zu deutsch: Listenverarbeiter).
Falsch ist natürlich, dass nur Profis Lisp beherrschen und nur diese XEmacs konfigurieren können. Dieser Artikel wird Sie in die Lage versetzen, die Grundkonfiguration von XEmacs selbst vorzunehmen und einfache Programmschnipsel zu verstehen und gegebenfalls an Ihre Wünsche anzupassen. Eine detaillierte Einführung finden Sie beispielsweise in [1], Programmschnipsel zu XEmacs in [2]. In gedruckter Form können die Bücher [3,4] weiterhelfen.
Befehlsstand
XEmacs erwartet seine Konfiguration an einer bestimmten Stelle: in Ihrem Home-Verzeichnis in der Datei ~/.emacs. Abgewöhnen können Sie ihm das, indem Sie XEmacs mit der Option -vanilla auf der Kommandozeile starten. Es präsentiert sich Ihnen dann ein jungfräulicher XEmacs, was dann Sinn hat, wenn Sie eine wichtige Einstellung in Ihrer ~/.emacs geändert, aber dabei einen Fehler gemacht haben.
Beachten Sie aber, dass gewohnte Tastenkombinationen oder andere Einstellungen nicht unbedingt mehr dieselben sein müssen. Mit der Option -load Datei veranlassen Sie XEmacs, das Lisp-Programm Datei direkt zu laden.
Kommandeur
Da wir nun wissen, wo XEmacs gerne seine Befehle mitgeteilt haben möchte, müssen wir uns nun noch um das Wie kümmern. Wie gesagt spricht XEmacs die Sprache Lisp, die ursprünglich für Programme mit künstlicher Intelligenz erschaffen wurde. Wir begnügen uns aber zuerst mit etwas einfacheren Dingen.
Wie Sie vielleicht bemerkt haben, zeigt XEmacs standardmäßig nicht die Spalten und Zeilen, in denen sich der Cursor im aktuellen Buffer befindet, an. Wie im ersten Teil der Reihe gezeigt, können wir mit M-x apropos RET nach Befehlen dazu suchen. XEmacs liefert zum Suchbegriff column den Befehl column-number-mode.
Der Beschreibung des Befehls nach scheint er auf unseren Zweck anwendbar: Non-nil means display column number in mode line, das heißt, er zeigt die Spaltenzahl in der Modeline an. Das tut er aber nur, wenn ihm ein Wert übergeben wird, der nicht nil ist. nil bedeutet soviel wie “nichts”. Wir können dem Befehl also jeden sonstigen Wert übergeben, damit dieser die Spaltenzahl in der Modeline anzeigt. Damit dies bei jedem Start von XEmacs geschieht, tragen wir dazu folgende Zeile in ~/.emacs ein:
(column-number-mode 1)
Sind Emacs und XEmacs installiert, besitzt der XEmacs eventuell eine gesonderte Konfigurationsdatei. Auf einem Mandrake-System mit beiden Emacs-Versionen war die Datei ~/.xemacs/custom.el der richtige Ort für Änderungen.
Die Klammern sind zwingend für jeden Lisp-Ausdruck. Den ersten Ausdruck innerhalb der Klammer interpretiert XEmacs immer als Befehl, alle weiteren als Parameter, die diesem Befehl übergeben werden. Die Zahl “1” ist einfach der Wert ungleich “nil”, der dem Befehl übergeben werden sollte.
Speichern Sie nun ab und starten XEmacs erneut, so sollten Sie in der Modeline am rechten Rand die Spaltenzahl angezeigt bekommen. Alternativ könnten Sie auch C-u 1 M-x column-number-mode RET eingeben. Mit C-u sorgen Sie dafür, dass Sie die Zahl 1 als Parameter übergeben können.Versuchen Sie einmal, das Gleiche für die Zeilenzahl zu konfigurieren.
Da ich XEmacs bevorzugt auf der Textkonsole benutze, fehlt mir natürlich eine Uhr auf dem Monitor. Auch hier bietet XEmacs eine Lösung an, nämlich den Befehl display-time, den Sie so in Ihrer ~/.emacs unterbringen (und der neben der Zeit auch noch neue Mails und die CPU-Last anzeigt):
(display-time)
Also wieder mit den obligatorischen Klammern und dem Befehl dazwischen. Wie Ihnen die Informationen von C-h f display-time RET zeigen, erwartet er keinen Parameter. Unschönerweise zeigt er die Uhrzeit aber im 12-Stunden-Format an. Dem können wir mit folgendem Eintrag abhelfen:
(setq display-time-24hr-format t)
Hier lautet der Befehl setq, der einer Variablen (hier: display-time-24hr-format) einen Wert zuordnet. Nachdem er ausgeführt wurde, enthält somit die Variable display-time-24hr-format den Wert “t”. Dieser ist das Gegenstück zu “nil” und steht für “true” (dt.: wahr). Variablen, die entweder “nil” oder “t” enthalten, nennt man boolsche Variablen. Wie C-h v display-time-24hr-format zeigt, wird die Zeit von nun an im 24-Stunden-Format angezeigt.
Abacus
Natürlich kann XEmacs nicht nur gleichsetzen, sondern auch rechnen. Um die Zahlen 2 und 3 zu addieren, schreibt man in Lisp:
(+ 2 3)
Das Pluszeichen ist wieder der Befehl, die beiden Zahlen 2 und 3 sind die Werte, die diesem Befehl übergeben werden. Natürlich kann man als Parameter auch Variablen übergeben:
(setq Alter 10) (+ Alter 3)
Beliebig schachteln kann man Befehle auch, denn der Rückgabewert eines Befehls kann wieder einem anderen Befehl als Parameter übergeben werden:
(+ (- 10 3) (* 10 10))
Dies ist gleichlautend zu “(+ 7 100)”, denn (- 10 3) gibt als Wert 7 zurück und (* 10 10) die 100. XEmacs hat also erst die inneren Befehle ausgeführt und sie dann dem Befehl + übergeben, der als Endergebnis 107 zurückgibt. Die Division erfolgt über den Befehl /.
Tabelle 1: Grundrechenarten
| Befehl | Beschreibung |
|---|---|
| (+ a b) | Addiere a und b |
| (- a b) | Subtrahiere a von b |
| (/ a b) | Dividiere a durch b |
| (* a b) | Multipliziere a mit b |
| (setq a Wert) | Weise der Variablen a Inhalt von Wert zu |
Tabelle 2: Logische und relationale Operatoren
| Befehl | Beschreibung |
|---|---|
| (and a b) | Wenn a oder b gleich nil, dann liefere nil zurück |
| (or a b) | Wenn a oder b gleich t, dann liefere t zurück |
| (eq a b) | Wenn a gleich b ist, dann liefere t zurück |
| (not Ausdruck) | Liefert nil zurück, wenn Ausdruck t ist, sonst t |
| (< a b) | Liefert t zurück, wenn a kleiner als b ist |
| (> a b) | Liefert t zurück, wenn a größer als b ist |
| (= a b) | Liefert t zurück, wenn a gleich b ist |
| (>= a b) | Liefert t zurück, wenn a größer gleich b ist |
| (<= a b) | Liefert t zurück, wenn a kleiner gleich b ist |
Tabelle 3: String-Operatoren
| Befehl | Beschreibung |
|---|---|
| (stringp s) | Liefere t zurück, wenn s eine Zeichenkette ist |
| (string= s1 s2) | Liefere t zurück, wenn s1 gleich s2 ist |
| (string-lessp s1 s2) | Liefert t zurück, wenn s1 alphabetisch vor s2 liegt |
| (concat s1 s2 s3 …) | Verbinde Zeichenketten s1, s2, s3 ... zu einer neuen |
| (substring s von bis) | Gibt Teilzeichenkette beginnend bei Position von bis Position bis zurück. Wird bis nicht angegeben, so wird die Teilzeichenkette bis zum Ende der Zeichenkette zurückgegeben |
| (aref s i) | Gibt Buchstabe i der Zeichenkette s zurück. (Zählung beginnt bei 0.) |
| (aset s i c) | Ersetzt Buchstaben i der Zeichenkette s durch c |
Auf Knopfdruck
XEmacs kennt Zeichenketten als Wert. Diese werden in Anführungsstrichen geschrieben. Schauen wir uns dazu folgendes Beispiel an: Angenommen Sie möchten, dass die Tastenkombination C-x C-c XEmacs nicht beendet, sondern, dass dies ausschließlich über M-x save-buffers-kill-emacs erfolgt, weil man sich zu leicht vertippen kann, dann schreiben Sie in Ihre ~/.emacs:
(global-set-key "\C-x\C-c" nil)
Der Wert in der Mitte ist eine Zeichenkette. Er ist eine Umschreibung für die Tastenkombination C-x C-c als Zeichenkette. Die beiden C müssen dabei durch ein “\” angeführt werden, weil nicht der Buchstabe “C” gemeint ist, sondern die [Strg]-Taste. Der Befehl global-set-key bewirkt nun, dass dieser Kombination ein Befehl zugewiesen wird. Da wir ihr gerade keinen Befehl zuweisen wollen, übergeben wir nil, also nichts.
Aufgelistet
Den gleichen Effekt können wir auch mit folgender, etwas ausführlicherer Darstellung erreichen:
(global-set-key [(control x) (control c)] nil)
Der Ausdruck in der Mitte ist wieder unsere Tastenkombination. Allerdings steht das Ganze jetzt in eckigen Klammern und darin die einzelnen Umschreibungen für die Tasten in runden Klammern.
Fangen wir mit den Ausdrücken in den runden Klammern an. Diesmal ist der erste Ausdruck beispielsweise in (control x) kein Befehl. Vielmehr handelt es sich um einen besonderen Datentyp, der einzelne Werte oder Variablen zusammenfasst. Dieser Datentyp heißt list, das heißt Liste. Hier ein paar Beispiele für Listen: * Liste mit Zahlen: ( 1 2 3) * Liste mit einer Zahl und einer Zeichenkette: ( 1 "abcd") * Liste mit Variable und einer Liste mit Variablen: (a (b c)) * leere Liste: ()
Um auf die einzelnen Elemente einer Liste zugreifen zu können, bietet XEmacs einige nützliche Befehle: * Der Befehl car liefert das erste Element einer Liste: (car '(a b c )) gibt als Ergebnis a zurück. * cdr liefert alles außer dem ersten Element zurück: (cdr '(a b c)) gibt als Ergebnis (b c) zurück. * Mit list können Sie eine neue Liste aus dem ihm übergebenen Werten oder Variablen erzeugen: (list 'a "abc" 7) gibt als Ergebnis eine neue Liste (a "abc" 7) zurück, (list '(a b c) d) dagegen ((a b c) d). * cons fügt ein Argument in einer schon existierenden Liste vorne an: (cons 'a (b c)) hat (a b c) als Ergebnis, (cons '( a b) '(c d)) gibt (( a b) c d) zurück. * append fügt Listen so zusammen: (append '(a b c) '(d e f)) wird zu (a b c d e f). * Der Befehl reverse kehrt die Reihenfolge der Elemente um: (reverse '(1 2 3)) führt zu (3 2 1), (reverse '( ( 1 2) 3 4) aber zu (4 3 (1 2)). * Mit dem schon bekannten Befehl setq können wir einer Variablen auch eine Liste zuweisen: (setq a '(c d)).
Die Liste (control x) enthält also zwei Variablen, die für die [Strg]- und die [x]-Taste stehen. Für die gewünschte Tastenkombination brauchen wir aber noch die andere Verknüpfung mit der Kombination (control c). Man könnte daran denken, dem Befehl global-set-key die Liste ((control x) (control c)) zu übergeben. Dieser verlangt jedoch einen anderen Datentyp, Vektor genannt. Die Elemente eines Vektors werden in eckigen Klammern geschrieben. Elemente können eines beliebigen Datentyps sein. Vorteil eines Vektors gegenüber einer Liste ist, dass die einzelnen Elemente des Vektors direkt angesprochen werden können, anstatt sie mühsam mit car und cdr zu ermitteln.Mit (aref v i) erhalten Sie das i-te Element des Vektors v, wobei die Zählung der Elemente bei 0 beginnt. Beispiel: (aref [a b c] 0) gibt a als Ergebnis zurück. (aset v i Element) setzt das i-te Element des Vektors v auf Element. Beispiel:
(setq v '(vector 1 2 3)) (aset v 0 0)
In der ersten Zeile erzeugen wir mit dem Befehl vector erst einen neuen Vektor und weisen ihn der Variablen v zu. Danach ersetzen wir das erste Element von v (die “1”) durch die Zahl “0”. Mit (vectorp v) können wir überprüfen, ob es sich bei v wirklich um einen Vektor handelt: Wenn dies zutrifft, wird t zurückgeliefert.
Mit (length v) erhalten Sie schließlich die Länge des Vektors v. length gibt die Länge von Listen oder Zeichenketten zurück.
Alles fließt
Um den Ablauf eines Programms zu steuern, können in Lisp zwei Befehle verwendet werden. Den ersten, if, kennt man aus anderen Programmiersprachen:
(if (>= Alter 16) (setq Zigaretten t) ; ja, Alter >= 16 (setq Zigaretten nil) ; nein, Alter < 16 )
Die erste Klammer nach dem Befehl if erhält die zu überprüfende Bedingung. Ist diese wahr, das heißt nicht nil, wird der zweite Ausdruck ausgewertet, sonst der letzte. In unserem Beispiel wird die Variable Zigarette auf t gesetzt, wenn die Variable Alter größer als oder gleich 16 ist, sonst wird sie auf nil gesetzt.
Nach der zu prüfenden Bedingung darf für die Anweisungen jeweils nur ein Ausdruck verwendet werden. Damit Sie auch komplexere Ausdrücke verwenden können, können Sie solche mit dem Befehl progn vorher auswerten lassen. (Der Befehl message im Beispiel gibt eine Zeichenkette aus.)
(if (>= Alter 16)
(progn
(setq Zigaretten t)
(setq Bier t)
(message "Du darfst Bier und Zigaretten kaufen.")
)
(progn
(setq Zigaretten nil)
(setq Bier nil)
(message "Du darfst weder Bier noch Zigaretten kaufen.")
)
)
Wenn Sie viele Bedingungen überprüfen müssen, wird Ihr Programm durch den Befehl cond übersichtlicher als mit if:
(cond
((< Alter 7) (setq geschaeftsfaehig nil)
(and (>= Alter 7) (< Alter 18)) (setq geschaeftsfaehig beschraenkt)
(>= Alter 18) (setq geschaeftsfaehig t)
))
Am Anfang jeder Zeile nach dem Befehl cond steht die Bedingung, die geprüft werden soll. Ist diese wahr, so werden die danach stehenden beliebig vielen Ausdrücke ausgeführt. Ist eine Bedingung unwahr, geht cond direkt zur nächsten Bedingung über und überprüft diese. Sind alle Bedingungen unwahr, liefert condnil zurück. In der zweiten Bedingung sehen Sie übrigens ein Anwendungsbeispiel für den logischen Operator and.
Eigene Funktionen
Wie man in Lisp eigene Funktionen definiert, soll folgendes Beispiel zeigen: Angenommen, wir wollen an der aktuellen Cursorposition durch Drücken der Taste [F2] das aktuelle Datum und die Uhrzeit einfügen, dann könnte dies wie folgt aussehen. (Diesen Programmschnipsel können Sie übrigens, wenn Sie ihn in einem Buffer eingegeben haben, markieren und dann mittels M-x eval-region RET auswerten lassen. Wenn Sie dann die [F2]-Taste drücken, sollte Datumeinfuegen ausgeführt werden.)
(defun Datumeinfuegen () (interactive "*") (insert (format-time-string "%d. %B %Y" (current-time)) ) ) (global-set-key [f2] 'Datumeinfuegen)
Mit dem ersten Teil, der mit dem Befehl defun beginnt, definieren wir eine eigene Funktion, die den Namen Datumeinfuegen trägt. Die leere Klammer dahinter bedeutet, dass ihr keine Parameter übergeben werden sollen.
Über interactive wird festgelegt, dass die Funktion über M-x Funktionsname ausgeführt werden kann. Als Parameter erwartet interactive eine Zeichenkette, die angibt, wie die übergebenen Parameter der Funktion interpretiert werden sollen. Doch dazu gleich ein Beispiel.
Mittels insert wird dann das Datum eingefügt werden, das vorher mit format-time-string in die gewünschte Form gebracht wurde. Sodann belegen wir mit global-set-key die [F2]-Taste mit unserer vorher definierten Funktion.
Nun noch ein kleines Beispiel für eine Funktion mit Parametern:
(defun Multiply (x y) "Erwartet Eingabe von zwei Zahlen und multipliziert diese." (interactive "nErste Zahl: \nnZweite Zahl: \n") (message "%d" (* x y)) )
Bei dieser Funktion haben wir nun die Parameter x und y angegeben. In der zweiten Zeile wird der so genannte “Docstring” für diese Funktion definiert. Mittels C-h f Multiply RET wird er angezeigt. Die Parameter der interactive-Funktion bedeuten Folgendes: Der erste Buchstabe n bedeutet, dass der erste Parameter x eine Zahl ist. Da die Funktion interaktiv ist, also vom Benutzer explizit aufgerufen werden kann, folgt danach eine Zeichenkette, die zur Eingabe der ersten Zahl auffordert. Angezeigt wird sie im Minibuffer. Abgeschlossen wird dieser Teil des Docstrings mit einem Zeilenumbruch (\n). Das Gleiche folgt dann für den Parameter y.
Welche Parameter Sie der interactive-Funktion übergeben können, erfahren Sie über C-h f interactive RET.
Der Zweck heiligt die Mittel
Ein besonderes Feature von XEmacs sind die Modi. Diese verleihen XEmacs beispielsweise abhängig vom Dateityp (HTML, LaTeX und andere) der Datei, die Sie gerade in einem Buffer bearbeiten, besondere, auf dieses Format zugeschnittene Funktionen. So definieren sie etwa bestimmte Tastenkombinationen, die die Bearbeitung oder Erstellung der Datei vereinfachen.
Dabei unterscheidet man zwischen “major”- und “minor”-Modi. Vereinfacht gesagt ergänzt ein minor-Modus einen major-Modus um zusätzliche Eigenschaften. So ergänzt etwa der auto-fill-mode geeignete andere Modi um die Funktion, bei Erreichen einer bestimmten Zeilenlänge die Zeile automatisch umzubrechen. Aber schauen wir uns ein paar interessante Modi und ihre Hauptfunktionen genauer an:
Um den auto-fill-mode zu aktivieren, tragen Sie in ~/.emacs Folgendes ein:
(auto-fill-mode 1)
Alternativ geben Sieim Editor C-u 1 M-x auto-fill-mode ein.
Der abbrev-mode erlaubt Ihnen, Abkürzungen für Wörter festzulegen, die bei Eingabe automatisch erweitert werden: Aktivieren Sie dazu zunächst den Modus mit C-u 1 M-x abbrev-mode oder in ~/.emacs mit (abbrev-mode 1). Danach geben Sie das Wort ein, für das Sie eine Abkürzung definieren wollen, gehen mit dem Cursor hinter das Wort und drücken C-x a g.
XEmacs fragt Sie dann im Minibuffer nach der Abkürzung. Immer wenn Sie nun dieses Kürzel eingeben und dann die [Space]-Taste drücken, wird es durch das eigentliche Wort ersetzt. Mit M-x write-abbrev-file sorgen Sie dafür, dass die von Ihnen definierten Abkürzungen abgespeichert werden.
Wenn Sie keinen Namen angeben, geht der Modus von ~/.abbrev_defs als Standardname aus. M-x read-abbrev-file lädt die Datei beim nächsten Mal wieder ein. Wollen Sie das automatisieren, ergänzen Sie ~/.emacs um den Eintrag (quietly-read-abbrev-file).
Falls Sie eine eigene Homepage verwalten, sollten Sie einen Blick auf den html-mode werfen, der nützliche Funktionen zum Editieren von HTML-Dateien bietet. Geben Sie in einem leeren Buffer M-x html-mode ein, sehen Sie in der Modeline “HTML”: Der Modus ist dann für diesen Buffer aktiviert.
Eine Beschreibung zum HTML-Modus erhalten Sie mit C-h m. Es öffnet sich ein neuer Buffer, der alle Tastenkombinationen enthält, die dieser Modus zur Verfügung stellt. Noch mehr Komfort bietet hm--html[5].
Für LaTeX-Benutzer gibt es standardmäßig den latex-mode, aus dem AucTeX-Paket. Geben Sie einfach M-x latex-mode ein und drücken Sie wieder C-h m, um sich über die Funktionen von AucTeX zu informieren. Wie der html-mode bietet auch der latex-mode Syntax-Highlighting, d. h. die HTML- bzw. LaTeX-Befehle werden farblich unterschiedlich dargestellt, so dass der Quelltext übersichtlicher ist. Außerdem können Sie einzelne Elemente ausblenden (“folden”), so dass Sie nur die Teile sehen, die für die Bearbeitung gerade wichtig sind.
XEmacs bietet noch sehr viele weitere Modi, darunter welche für nahezu jede Programmiersprache. Laden Sie Ihre ~/.emacs und geben Sie dann M-x lisp-mode RET ein, sehen Sie, wie dies für Lisp selbst aussieht. Eine Übersicht über die Modi, die bei Ihrer XEmacs-Version schon installiert sind, erhalten Sie über M-x apropos RET mode RET. Daneben finden sich im Netz unzählige weitere. Beachten Sie aber, dass sich nicht alle für XEmacs eignen, da manche Modi Befehle verwenden, die nur Emacs bietet.
Glossar
-
Variablen
-
Eine Variable ist ein Platzhalter für einen Wert, z. B. eine Zahl oder eine Zeichenkette.
-
Parameter
-
Als Parameter bezeichnet man Variablen, die einem Befehl übergeben werden, damit er sie verarbeiten kann und ein entsprechendes Ergebnis zurückliefern kann. Dieses Ergebnis nennt man Rückgabewert.
-
Symboloperator
-
Immer wenn man einem Befehl nicht den Wert einer Variablen, sondern die Variable selbst übergeben will, muss der Variablen der Operator ‘ vorangestellt werden. (setq a b) würde a den Wert von b zuweisen, während (setq a ‘b) ihr b selbst zuweist. a und b sind damit identisch und enthalten nicht nur dieselben Werte.
Infos
[1] Lisp-Reference: C-h i in XEmacs eingeben, dann unter XEmacs den Unterpunkt Lispref wählen.
[2] XEmacs Customization: http://www.xemacs.org/Links/customization.html
[3] Bob Glickstein: “Writing GNU Emacs Extensions”, O’Reilly, 1997, ISBN 1-56592-261-1, USD 29.95.
[4] Otto Mayer: “Programmieren in Common Lisp.”, Spektrum Akad. Vlg., 1995, ISBN: 3860257102, EUR 24,95
[5] hm–html: ftp://ftp.tnt.uni-hannover.de/pub/editors/xemacs/contrib/





