Vor einigen Tagen wollte ich mal wieder kurz was an einem LaTeX Dokument ändern. Aber, wie bei LaTeX leider so oft, wurde aus kurz ein länglicher Kampf.

Die Ausgangslage

Ich nutze LaTeX schon sehr lange. Bereits vor über 20 Jahren habe ich damit live Uni-Vorlesungen mitgeschrieben. Damals war ich noch der einzige, der mit dem Laptop in der Vorlesung saß. Aber ich schweife ab. Worauf ich hinaus will ist, dass ich gerne und häufig LaTeX verwende. Einfach weil es sich gut skripten lässt und es auf einfachen ASCII Dateien beruht, welche sich mit GIT versionieren lassen.

So habe ich auch meine Kursunterlagen für den BZF-Funksprechkurs mit LaTeX erstellt. Damit dieser Post nicht zu lang wird konzentriere ich mich hier auf den LaTeX Aspekt. Details zum BZF-Funkkurs habe ich im Post BZF-Funksprechkurs Kursunterlagen erläutert.

Mein Ziel war es, einige Textzeilen farblich zu hinterlegen.

Herausforderung

'Das dürfte ja nicht so schwer sein', dachte ich noch, kurz bevor ich ins Kaninchenloch hinab gestiegen bin... Denn bei LaTeX ist, so erscheint es mir auch nach zwanzig Jahren noch, nichts einfach leicht.

Die Funksprüche sind letztlich Tabellen und zum Erzeugen verwende ich folgende Makros:

\newcommand{\FunkDe}[1]{ %
  \fcolorbox{black}{black!5}{\parbox{\textwidth}{ %
  \begin{tabular}{p{0.9\textwidth}p{0.05\textwidth}} %
    \\ %
    & \\ \hline %
  #1 %
  \end{tabular} %
  }} 
}
\newcommand{\LineDeEn}[3]{ %
  \textbf{#1} #2 & \textbf{#1} #3 \\
}

Jetzt wollte ich beim \LineDeEn Makro einen zusätzlichen, optionalen Parameter hinzufügen. Wenn dieser Parameter gesetzt ist, sollte dann der gesamte Funkspruch gelb hinterlegt werden.

Also folgende Schritte wollen umgesetzt werden:

  1. Hinzufügen eines optionalen Parameters zum Makro.
  2. Abfragen, ob dieser Parameter gesetzt ist.
  3. Gegebenenfalls den gesamten Funkspruch, also den Text in dieser Tabellenzeile, gelb hinterlegen.

Klingt einfach, oder?

Das Leiden beginnt

Halt! Nicht so schnell! Immerhin haben wir es hier mit LaTeX zu tun.

Beim Hinzufügen eines optionalen Parameters wird die Anzahl der Parameter erhöht. Somit sind es jetzt vier, anstelle von drei Parametern. Dabei landet der optionale Parameter an Stelle eins, weshalb alle Paremter im existierenden Makro um eins inkrementiert werden müssen:

\newcommand{\LineDeEn}[4][]{ %
  \textbf{#2} #3 & \textbf{#2} #4 \\
}

Dann wollte ich abfragen, ob dieser optionale Parameter gesetzt ist, oder nicht. Eine schnelle Suche führte zum Beispiel zu dieser Stackexchange Frage, welche schon mehrere, sehr lange Antworten enthält. Dieser Thread zeigt aber auch, dass die Frage gar nicht so einfach zu beantworten ist. Auch auf latex.org gibt es eine Antwort zu dieser Frage, mit anderen Lösungsvorschlägen.

Eigentlich hätte ich nicht gedacht, dass ich für diese einfache Abfrage ein neues LaTeX Paket benötige. Dennoch habe ich nach kurzem Rumprobieren kapituliert und schließlich das Paket ifthen verwendet.

\usepackage{ifthen}       % If Then Else Abfragen für markierte Funksprüche

\newcommand{\LineDeEn}[4][]{ %
  \ifthenelse{\equal{#1}{}}{ %
    \textbf{#2} #3 & \textbf{#2} #4 \\
  }{ %
    Parameter gesetzt!
  } %
}

Also nochmals kurz zum Zusammenfassen: um in LaTeX eine Abfrage einzubauen, ob ein Makro Paraemter leer ist oder nicht (bzw. auch jede andere Abfrage), bindet man am besten das ifelse Paket ein ... soweit logisch? So langsam überrascht mich nichts mehr.

Farbig hinterlegter Text

Kommen wir zum letzten Punkt: den Text farbig hinterlegen. Dafür gibt es zum Beispiel die \colorbox. Funktioniert auch ganz einfach. Hat nur leider ein Problem: der Text in der colorbox bricht nicht mehr um. Es bedarf somit weiterer Klimmzüge.

Man kann zum Beispiel eine \parbox innerhalb der \colorbox verwenden. Zumindest so lange man ganze Absätze markieren möchte.

Recht schnell stieß ich dann auf das Paket soul, welches häufiger in diesem Zusammenhang erwähnt wird. Dieses ist allgemein zum Markieren von Textblöcken gedacht, wie zum Beispiel unterstreichen, durchstreichen, etc. Es stellt auch den Befehl \hl (für Highlight) zur Verfügung, welches den Text farbig hinterlegt.

Hier kann man jedoch nicht direkt die Farbe angeben, sondern die Highlight-Farbe wird über einen separaten Befehl global definiert ... ough. Ja, kann man auch innerhalb von Blöcken machen und somit den Scope ändern, aber dennoch ist das sehr umständlich für meinen Anwendungsfall. Fühlt sich einfach nicht passgenau an.

\usepackage{ifthen}       % If Then Else Abfragen für markierte Funksprüche
\usepackage{soul}     % Für Hintergrundfarbe der markierten Funksprüche

\definecolor{towerspruch}{rgb}{.95,.95,0.60}
\newcommand{\LineDeEn}[4][]{ %
  \ifthenelse{\equal{#1}{}}{ %
    \textbf{#2} #3 & \textbf{#2} #4 \\
  }{ %
    \sethlcolor{towerspruch}\hl{\textbf{#2} #3} & \sethlcolor{towerspruch}\hl{\textbf{#2} #4} \\
  } %
}

Die Sache mit den Umlauten

Hatte ich jetzt das Ziel erreicht? Leider noch immer nicht. Ich hatte diese neue Funktion zufällig zu erst an einem englischen Funkspruch erfolgreich ausprobiert. Als ich das Makro jedoch auf einen deutschen Funkspruch anwenden wollte, krachte LaTeX mit einer (leider wie so oft) fehlleitenden Fehlermeldung:

Argument of \UTFviii@two@octets has an extra }

What? Ein zusätzliches }? Woher soll das denn bitte kommen? Lange Fehlersuche später stellte sich heraus, dass soul nicht mit Umlauten zurecht kommt. Die Lösung heist (seit 2007) soulutf8. Dies ist ein Wrapper um das soul Paket für die utf-8 Kompatibilität. Die finale Lösung sieht somit wie folgt aus:

bzf-kursunterlagen-funksprueche.tex (Source)

\usepackage{ifthen}       % If Then Else Abfragen für markierte Funksprüche
\usepackage{soulutf8}     % Für Hintergrundfarbe der markierten Funksprüche

\newcommand{\FunkDe}[1]{ %
  \fcolorbox{black}{black!5}{\parbox{\textwidth}{ %
  \begin{tabular}{p{0.9\textwidth}p{0.05\textwidth}} %
    \\ %
    & \\ \hline %
  #1 %
  \end{tabular} %
  }} 
}
\definecolor{towerspruch}{rgb}{.95,.95,0.60}
\newcommand{\LineDeEn}[4][]{ %
  \ifthenelse{\equal{#1}{}}{ %
    \textbf{#2} #3 & \textbf{#2} #4 \\
  }{ %
    \sethlcolor{towerspruch}\hl{\textbf{#2} #3} & \sethlcolor{towerspruch}\hl{\textbf{#2} #4} \\
  } %
}

\FunkDe{
  \LineDeEn{T}{
  hinter Beechcraft Bonanza von Links,
  rollen sie zum Rollhalt A Piste 07 über Mike}{
  }

  \LineDeEn{P}{
  DE... Rollhalt A Piste 07, Abflugbereit}{
  }
  \LineDeEn{T}{
  hinter Abfliegender Cessna 172 rollen Sie zum Abflugpunkt Piste 07 dahinter}{
  }

  \LineDeEn[1]{T}{
  Verlassen Sie Kontrollzone über Abflugstrecke Oscar,
  Steigen Sie auf maximal 2500 Fuß,
  Wind 070 Grad 2 Knoten Piste 07 Start Frei}{
  }

  \LineDeEn{P}{
  über Oscar 1, 2500 Fuß
  (Erbitte verlassen der Frequenz)}{
  }
  \LineDeEn{T}{
  Verlassen der Frequenz genehmigt}{
  }
}

Fazit

Ich finde LaTeX noch immer gut, auch wenn es für mich leider immer häufiger nur das kleiner Übel ist. Viele Dinge lassen sich skripten und ich kann den Single Source of Truth Ansatz damit sehr gut umsetzen. Angenommen ich hätte mein Trainings-Skript mit LibreOffice oder ähnlichem geschrieben, so wäre es wesentlich aufwändiger, Präsentation, Skript und Handout konsisten zu halten. Auch Änderungen am Layout lassen sich mit Hilfe von LaTeX Makros wesentlich einfacher und einheitlicher realisieren, da diese zentral definiert und angepasst werden.

Dennoch würde ich mir ein Textsatzsystem wünschen, bei dem man nicht bei jeder kleinen Änderung in die Google-Untiefen abtauchen muss, sondern welches irgendwie einheitlicher und vorhersagbarer funktioniert.

Ich meine, die Aufgabe ein paar Wörter oder einen Absatz farblich zu hinterlegen, ist jetzt wirklich nicht so esoterisch, dass es dafür, inklusive utf-8 Unterstützung, zwei neuer Pakete benötigt, oder? Das selbe gilt auch für die If-Abfrage, für die ich letztendlich ein neues Paket eingebunden habe. Einfach weil ich mich nicht mit den Quirks von TeX herum schlagen wollte.