
Markdown-Tabellen sind höllisch:
- Sie können keinen Text in Zellen schreiben, die länger als ein paar Wörter und noch weniger eine Liste sind.
- Wenn der Dialekt Absatz 1 zulässt, ist die Formatierung unpraktisch.
- Wenn die Zellen nicht ausgerichtet sind, kann die Tabelle nicht gelesen werden.
- Es gibt keine Unterstützung für Tabellen desselben Typs und derselben Automatisierung, z. B. Zeilennummerierung.
Es ist Zeit, einen Filter für Pandoc zu schreiben, der Tabellen aus strukturiertem YAML mit Zeilennummerierung, horizontaler Ausrichtung, Diagrammvorlagen erstellt und gleichzeitig herausfindet, wie Lua-Filter geschrieben werden.
Normalerweise schreibe ich Texte in Markdown und konvertiere sie mit Pandoc in das Zielformat. Dies ist ein Programm, das Dokumente zwischen Formaten konvertiert. Beispielsweise können Sie aus Markdown HTML und einen anderen Dialekt von MD, DOCX und PDF erhalten (mehr als 30 Eingabe- und mehr als 50 Ausgabeformate). Pandoc Markdown bietet viele praktische Erweiterungen für Links, Fußnoten, Signaturen und Formeln.
Pandoc arbeitet als Zusammenstellung von Funktionen (es wäre in Haskell geschrieben worden): ein bestimmtes Eingabeformat → abstrakte Darstellung eines Dokuments → ein bestimmtes Ausgabeformat. Eine abstrakte Darstellung kann mithilfe von in Lua geschriebenen Filtern geändert werden. Filter müssen das Ausgabeformat nicht kennen, können es aber berücksichtigen.
Unser Filter sucht nach abstrakten Codeblöcken in der table
bedingten Sprachen in einer abstrakten Darstellung, liest YAML darin und generiert abstrakte Darstellungen von Tabellen, die Pandoc selbst im Zielformat erzeugt.
pandoc --lua-filter table.lua input.md -o output.html
Was sind die Alternativen und warum sind sie schlimmer?
- HTML-Tabellen funktionieren nur in Markdown und werden nur in HTML konvertiert. nur das problem der reichhaltigen formatierung in zellen ist gelöst.
- Tabellengeneratoren müssen von einem Texteditor aus umgeschaltet werden, da es unpraktisch ist, den Inhalt der Zellen in ihnen zu bearbeiten ( Beispiel ).
- Editoren-Plugins ( Emacs Org-Mode , VIM-Plugins ) sind nicht universell und nicht immer verfügbar.
Im Gegensatz dazu pandoc-crossref
und alle Pandoc-Brötchen mit dem Filter für Übersichtstabellen. Der Filter kann auch zum Generieren von Standard-Markdown-Tabellen verwendet werden, indem das entsprechende Ausgabeformat angegeben wird. Von den Nachteilen:
- Zellen können nicht zusammengeführt werden, Pandoc unterstützt dies (noch) nicht.
- Bei horizontalen Tabellen muss die Stilisierung im Ausgabeformat erfolgen, z. B. über CSS.
Die Beschreibung der Tabelle besteht aus drei Teilen:
Tabellenstruktur
Eine geordnete Liste von Diagrammen (Spalten):
- Die Spalte sollte mindestens einen Titel haben.
- Um die Spalten neu anordnen zu können, ohne die Daten zu berühren, muss das in der Spalte (
id
) angezeigte Datensatzattribut angegeben werden. - Spezielle Spalten haben keine ID, aber eine Beschreibung, wie sie gefüllt werden. Zunächst benötigen Sie eine Seriennummer (
special: number
). - Spaltenausrichtung (
align
).
Der Tisch kann auch vertikal oder horizontal orientation
. Im letzteren Fall sind die Graphen Zeilen.
Tabelleneigenschaften: ID für Links ( id
) und Signatur ( caption
). Mit Pandoc können Sie Tabellen, aber keine Codeblöcke signieren.
Daten in Form eines Arrays von YAML-Wörterbüchern.
Die Struktur kann für mehrere Tabellen gleich sein. Sie können sie also sowohl direkt mit der Tabelle als auch einmal in den Metadaten (im Vordergrund) beschreiben und dann auf die angegebene Vorlage verweisen.
Umsetzungsplan:
Aus den Metadaten des Dokuments bilden wir ein Wörterbuch mit Vorlagen.
Für jeden Codeblock mit der Klassentabelle:
- Wir analysieren die YAML-Tabellen.
- Wenn eine Vorlage angegeben ist, nehmen wir sie aus dem Wörterbuch, ansonsten füllen wir die Vorlage aus YAML aus.
- Wir füllen die einzelnen Eigenschaften der Tabelle von YAML aus.
- Wir bilden Tabelleneinträge aus YAML (ein Datensatz ist eine Zeile in einer regulären Tabelle oder eine Spalte in einer horizontalen).
- Wir "zeichnen" eine Tabelle anhand einer Vorlage, Eigenschaften und Aufzeichnungen.
Die obere Ebene wird wie geschrieben implementiert (der gesamte Code ist unter dem Link am Ende des Artikels verfügbar):
function Pandoc(doc) local meta_templates = doc.meta['table-templates'] if meta_templates then for name, value in pairs(meta_templates) do templates[name] = parse_template(value) end end local blocks = pandoc.walk_block(pandoc.Div(doc.blocks), { CodeBlock = create_table }) return pandoc.Pandoc(blocks, doc.meta) end
Die Funktion parse_template()
konvertiert das Metadatenformat geringfügig. Pandoc repräsentiert ihre Werte als MetaBlock
und MetaInline
. Entweder werden einfache Linien pandoc.utils.stringify()
Funktion pandoc.utils.stringify()
(z. B. Ausrichtung) oder visuelle Elemente (z. B. ein Textblock in der Spaltenüberschrift) daraus erstellt.
Über das Debuggen. Es gibt viele Beispiele in der Pandoc-Dokumentation, aber die Typen sind nicht sehr detailliert. Für das Debuggen von Filtern ist es praktisch, eine variable Dump-Funktion zu haben. In seriösen Bibliotheken werden zu viele Details gedruckt. Ich bevorzuge eine der einfachen Optionen .
Funktionen zum Konvertieren von Metadaten in Dokumentelemente local function to_inlines(content) if content == nil then return {} elseif type(content) == 'string' then return {pandoc.Str(content)} elseif type(content) == 'number' then return to_inlines(tostring(content)) elseif content.t == 'MetaInlines' then inlines = {} for i, item in ipairs(content) do inlines[i] = item end return inlines end end local function to_blocks(content) if (type(content) == 'table') and content.t == 'MetaBlocks' then return content else return {pandoc.Plain(to_inlines(content))} end end
Die Funktion create_table create_table()
wird in Triple Backtics für jeden Codeblock aufgerufen.
Wir interessieren uns nur für Codeblöcke "in der Sprache" der table
:
if not contains('table', block.classes) then return block end
Um YAML in einem Codeblock zu analysieren, erstellen wir ein Dokument, das nur aus YAML-Metadaten besteht, analysieren es mit Pandoc und lassen nur Metadaten:
local meta = pandoc.read('---\n' .. block.text .. '\n---').meta
Als nächstes wird aus dem meta
Link zu einer Vorlage oder Tabellenstruktur und den Eigenschaften einer bestimmten Tabelle gelesen.
Die Funktion fill_table()
liest aus meta
die in der Beschreibung des Diagramms angegebenen Attribute. Wenn die Spalte als speziell markiert ist, wird gleichzeitig ihr Inhalt generiert:
local data = {} for i, serie in ipairs(template.series) do if serie.special == 'number' then data[i] = to_blocks(#datum + 1) else data[i] = to_blocks(item[serie.id]) end end
Die Funktion format_table()
bildet abhängig von der Ausrichtung der Tabelle das resultierende Array von Zellen und erstellt ein abstraktes Tabellenobjekt. Es sollte beachtet werden, dass Pandoc einfach keine Tabelle erstellt, wenn die Breiten oder Überschriften für alle Spalten oder für keine festgelegt werden sollen.
Das fertige Skript kann in ~/.local/share/pandoc
(das ~/.local/share/pandoc
Datenverzeichnis ) ~/.local/share/pandoc
, um von überall nach Namen darauf zuzugreifen.
PS
Informationen zur Berücksichtigung der Ausgabeformatfilter. Zum Beispiel schreibe ich Spoiler in Pandoc wie folgt:
::: {.spoiler title=""} . :::
Das Pandoc-Dokumentmodell enthält keine Spoiler. Daher sollte der Filter Rohblöcke auf ungefähr folgende Weise erzeugen. Natürlich sollte der echte Code ( spoiler.lua
) das Ausgabeformat über die Variable FORMAT
und nicht mechanisch berücksichtigen: Das folgende Fragment erzeugt Rohblöcke in HTML, obwohl das Ausgabeformat ein Markdown ist.
function Div(el) if not el.attr or not contains('spoiler', el.attr.classes) then return el end local title = el.attr.attributes['title'] or '' table.insert(el.content, 1, pandoc.RawBlock('html', '<' .. 'spoiler title="' .. title .. '">', 'RawBlock')) table.insert(el.content, pandoc.RawBlock('html', '<' .. '/spoiler>', 'RawBlock')) return el.content end
Referenzen