summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVivien Kraus <vivien@planete-kraus.eu>2022-10-06 21:02:35 +0200
committerVivien Kraus <vivien@planete-kraus.eu>2022-10-06 21:15:20 +0200
commit95c3c983e87d5ee1fb02848f1315cb65a7c6fa0c (patch)
tree616e4386e8755f206da7e6c983364e6f73f5f02d
parentfe08dcdb9220bf5b8b42ea503637e20ddbb818eb (diff)
Use a formatter instead of trying to strip space.
-rw-r--r--mped.xml160
-rw-r--r--tangle-bootstrap.xsl76
2 files changed, 42 insertions, 194 deletions
diff --git a/mped.xml b/mped.xml
index ecfe859..04dd33d 100644
--- a/mped.xml
+++ b/mped.xml
@@ -140,7 +140,8 @@
<xsl:value-of select="@mped:tangle-to" />
<xsl:text>")&#xA;</xsl:text>
- <xsl:text>cat >> </xsl:text>
+ <xsl:apply-templates select="." mode="source-code-formatter" />
+ <xsl:text> > </xsl:text>
<xsl:value-of select="@mped:tangle-to" />
<xsl:text> &lt;&lt; "_MPED_EOF"&#xA;</xsl:text>
@@ -152,139 +153,45 @@
</programlisting>
<para>
This template starts by creating the directory where the file
- should go, then fills the file with the source code. For this to
- work, we need to do two things about the text of the program
- listing: remove the first empty lines and the last empty
- lines of the content (but preserve indentation).
+ should go, then fills the file with the source code. XML has a
+ precise behavior when it comes to whitespace preservation, but
+ it’s not always the prettiest when we write it with whitespace
+ output in mind. So, the code output is frequently not indented
+ correctly, and has too many empty lines. To counter this
+ effect, we use a code source <emphasis>formatter</emphasis>, a
+ program that reads source code and indents it correctly. For
+ XSLT, we can use <command>xmllint</command> from
+ <application>libxml2</application>. The important thing about
+ the formatter is that it should take its input from standard
+ input and write the formatted code to standard output.
</para>
- <para>
- Let us start with removing leading or trailing empty
- lines. Removing leading empty lines seems easier.
- </para>
- <programlisting language="xml"
- xml:id="mped-private-leading-empty-lines">
- <![CDATA[
-<xsl:template name="mped-private-leading-empty-lines">
- <xsl:param name="indentation" select="''" />
- <xsl:param name="text" select="." />
- <xsl:choose>
- <xsl:when test="substring($text, 1, 1) = '&#xA;'">
- <xsl:call-template name="mped-private-leading-empty-lines">
- <xsl:with-param name="indentation" select="''" />
- <xsl:with-param name="text"
- select="substring($text, 2)" />
- </xsl:call-template>
- </xsl:when>
-
- <xsl:when test="(
- substring($text, 1, 1) = ' '
- or substring($text, 1, 1) = '&#9;'
- or substring($text, 1, 1) = '&#13;')">
- <xsl:call-template name="mped-private-leading-empty-lines">
- <xsl:with-param name="indentation"
- select="concat($indentation, substring($text, 1, 1))" />
- <xsl:with-param name="text"
- select="substring($text, 2)" />
- </xsl:call-template>
- </xsl:when>
-
- <xsl:otherwise>
- <xsl:value-of select="$indentation" />
- <xsl:value-of select="$text" />
- </xsl:otherwise>
- </xsl:choose>
-</xsl:template>
- ]]>
- </programlisting>
- <para>
- There are three different cases. If the text starts with a
- newline, discard the indentation that we carried and the
- newline. If the text starts with whitespace, carry it and look
- at the next character. Otherwise, the whitespace that we carried
- is indentation, so print it, and print the text.
- </para>
- <para>
- To avoid exposing the carried indentation, it is better to mark
- this template as internal and wrap it in a new template.
- </para>
- <programlisting language="xml" xml:id="remove-leading-empty-lines">
+ <programlisting language="xml" xml:id="formatter-for-xml">
<![CDATA[
-<xsl:template name="remove-leading-empty-lines">
- <xsl:param name="text" select="." />
- <xsl:call-template name="mped-private-leading-empty-lines">
- <xsl:with-param name="indentation" select="''" />
- <xsl:with-param name="text" select="$text" />
- </xsl:call-template>
+<xsl:template match="docbook:programlisting[@language = 'xml']"
+ mode="source-code-formatter">
+ <xsl:text>xmllint --format -</xsl:text>
</xsl:template>
]]>
</programlisting>
<para>
- To remove trailing empty lines, the solution is easier since
- there is no indentation to keep around: just discard all the
- trailing whitespace.
+ If no formatter applies, then we can resort to
+ <command>cat</command>.
</para>
- <programlisting language="xml" xml:id="remove-trailing-whitespace">
+ <programlisting language="xml" xml:id="default-formatter">
<![CDATA[
-<xsl:template name="remove-trailing-whitespace">
- <xsl:param name="text" select="." />
- <xsl:choose>
- <xsl:when test="$text = ''">
- <xsl:value-of select="$text" />
- </xsl:when>
- <xsl:otherwise>
- <xsl:variable name="last" select="substring($text, string-length ($text), 1)" />
- <xsl:variable name="before" select="substring($text, 1, string-length ($text) - 1)" />
- <xsl:choose>
- <xsl:when test="$last = ' ' or $last = '&#9;'
- or $last = '&#10;' or $last = '&#13;'">
- <xsl:call-template name="remove-trailing-whitespace">
- <xsl:with-param name="text" select="$before" />
- </xsl:call-template>
- </xsl:when>
- <xsl:otherwise>
- <xsl:value-of select="$text" />
- </xsl:otherwise>
- </xsl:choose>
- </xsl:otherwise>
- </xsl:choose>
+<xsl:template match="docbook:programlisting"
+ mode="source-code-formatter">
+ <xsl:text>cat</xsl:text>
</xsl:template>
]]>
</programlisting>
<para>
- Using these templates, we can process the program listing code
- in the “copy-source-code” mode: if there is only one text node,
- then remove the leading emtpy lines and trailing
- whitespace. Otherwise, remove the leading emtpy lines from the
- first text node and the trailing whitespace from the last text
- node. By “first” (respectively, “last”) text node, I mean the
- text node that has no preceding (respectively, following)
- siblings. Maybe there are no such text nodes.
+ We also need to specify how the source code is copied.
</para>
<programlisting language="xml" xml:id="copy-source-code-text">
<![CDATA[
-<xsl:template match="text()[position() = 1 and position() = last()]"
- mode="copy-source-code">
- <xsl:call-template name="remove-trailing-whitespace">
- <xsl:with-param name="text">
- <xsl:call-template name="remove-leading-empty-lines">
- <xsl:with-param name="text" select="." />
- </xsl:call-template>
- </xsl:with-param>
- </xsl:call-template>
-</xsl:template>
-
-<xsl:template match="text()[position() = 1 and position() != last()]"
- mode="copy-source-code">
- <xsl:call-template name="remove-leading-empty-lines">
- <xsl:with-param name="text" select="." />
- </xsl:call-template>
-</xsl:template>
-
-<xsl:template match="text()[position() > 1 and position() = last()]"
- mode="copy-source-code">
- <xsl:call-template name="remove-trailing-whitespace">
- <xsl:with-param name="text" select="." />
- </xsl:call-template>
+<xsl:template match="text()" mode="copy-source-code">
+ <xsl:value-of select="." />
</xsl:template>
]]>
</programlisting>
@@ -340,10 +247,12 @@
<para>
The collection of all these templates gives the following:
</para>
- <programlisting language="xml" xml:id="whole-tangling-stylesheet"
- mped:tangle-to="tangle.xsl">
- <![CDATA[
-<?xml version="1.0"?>
+ <programlisting
+ language="xml"
+ xml:id="whole-tangling-stylesheet"
+ mped:tangle-to="tangle.xsl"
+ ><![CDATA[<?xml version="1.0"?>
+
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:mped="https://labo.planete-kraus.eu/mped.git"
@@ -353,9 +262,8 @@
<xsl:strip-space elements="*" />
]]>
<mped:copy linkend="tangle-programlisting" />
- <mped:copy linkend="mped-private-leading-empty-lines" />
- <mped:copy linkend="remove-leading-empty-lines" />
- <mped:copy linkend="remove-trailing-whitespace" />
+ <mped:copy linkend="formatter-for-xml" />
+ <mped:copy linkend="default-formatter" />
<mped:copy linkend="copy-source-code-text" />
<mped:copy linkend="ignore-text-other-than-source" />
<mped:copy linkend="tangle-mped-copy" />
diff --git a/tangle-bootstrap.xsl b/tangle-bootstrap.xsl
index ffe19f5..baa9669 100644
--- a/tangle-bootstrap.xsl
+++ b/tangle-bootstrap.xsl
@@ -7,7 +7,8 @@
<xsl:value-of select="@mped:tangle-to"/>
<xsl:text>")
</xsl:text>
- <xsl:text>cat &gt;&gt; </xsl:text>
+ <xsl:apply-templates select="." mode="source-code-formatter"/>
+ <xsl:text> &gt; </xsl:text>
<xsl:value-of select="@mped:tangle-to"/>
<xsl:text> &lt;&lt; "_MPED_EOF"
</xsl:text>
@@ -16,75 +17,14 @@
_MPED_EOF
</xsl:text>
</xsl:template>
- <xsl:template name="mped-private-leading-empty-lines">
- <xsl:param name="indentation" select="''"/>
- <xsl:param name="text" select="."/>
- <xsl:choose>
- <xsl:when test="substring($text, 1, 1) = '&#10;'">
- <xsl:call-template name="mped-private-leading-empty-lines">
- <xsl:with-param name="indentation" select="''"/>
- <xsl:with-param name="text" select="substring($text, 2)"/>
- </xsl:call-template>
- </xsl:when>
- <xsl:when test="( substring($text, 1, 1) = ' ' or substring($text, 1, 1) = '&#9;' or substring($text, 1, 1) = '&#13;')">
- <xsl:call-template name="mped-private-leading-empty-lines">
- <xsl:with-param name="indentation" select="concat($indentation, substring($text, 1, 1))"/>
- <xsl:with-param name="text" select="substring($text, 2)"/>
- </xsl:call-template>
- </xsl:when>
- <xsl:otherwise>
- <xsl:value-of select="$indentation"/>
- <xsl:value-of select="$text"/>
- </xsl:otherwise>
- </xsl:choose>
+ <xsl:template match="docbook:programlisting[@language = 'xml']" mode="source-code-formatter">
+ <xsl:text>xmllint --format -</xsl:text>
</xsl:template>
- <xsl:template name="remove-leading-empty-lines">
- <xsl:param name="text" select="."/>
- <xsl:call-template name="mped-private-leading-empty-lines">
- <xsl:with-param name="indentation" select="''"/>
- <xsl:with-param name="text" select="$text"/>
- </xsl:call-template>
+ <xsl:template match="docbook:programlisting" mode="source-code-formatter">
+ <xsl:text>cat</xsl:text>
</xsl:template>
- <xsl:template name="remove-trailing-whitespace">
- <xsl:param name="text" select="."/>
- <xsl:choose>
- <xsl:when test="$text = ''">
- <xsl:value-of select="$text"/>
- </xsl:when>
- <xsl:otherwise>
- <xsl:variable name="last" select="substring($text, string-length ($text), 1)"/>
- <xsl:variable name="before" select="substring($text, 1, string-length ($text) - 1)"/>
- <xsl:choose>
- <xsl:when test="$last = ' ' or $last = '&#9;' or $last = '&#10;' or $last = '&#13;'">
- <xsl:call-template name="remove-trailing-whitespace">
- <xsl:with-param name="text" select="$before"/>
- </xsl:call-template>
- </xsl:when>
- <xsl:otherwise>
- <xsl:value-of select="$text"/>
- </xsl:otherwise>
- </xsl:choose>
- </xsl:otherwise>
- </xsl:choose>
- </xsl:template>
- <xsl:template match="text()[position() = 1 and position() = last()]" mode="copy-source-code">
- <xsl:call-template name="remove-trailing-whitespace">
- <xsl:with-param name="text">
- <xsl:call-template name="remove-leading-empty-lines">
- <xsl:with-param name="text" select="."/>
- </xsl:call-template>
- </xsl:with-param>
- </xsl:call-template>
- </xsl:template>
- <xsl:template match="text()[position() = 1 and position() != last()]" mode="copy-source-code">
- <xsl:call-template name="remove-leading-empty-lines">
- <xsl:with-param name="text" select="."/>
- </xsl:call-template>
- </xsl:template>
- <xsl:template match="text()[position() &gt; 1 and position() = last()]" mode="copy-source-code">
- <xsl:call-template name="remove-trailing-whitespace">
- <xsl:with-param name="text" select="."/>
- </xsl:call-template>
+ <xsl:template match="text()" mode="copy-source-code">
+ <xsl:value-of select="."/>
</xsl:template>
<xsl:template match="text()"/>
<xsl:template match="mped:copy" mode="copy-source-code">