Newer
Older
XML / modules / code-formatting.xml
<?xml version="1.0" encoding="utf-8"?>

<!--
	Inline code and code blocks (preformatted text, in HTML terms).
	
	TODO (2011-10-07):
		* Switch to listings for actual code.
		* Add an "inline-verbatim|verb" template for inline verbatim (which is what the "code" template does now).
		* Add "block-verbatim" as a match for "verbatim".
-->

<stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform">


	<!-- Inline code. -->
	<template name="code" match="code">
		<!--
			Inline code. LaTeX uses listings to display this; delimiters for \lstinline are chosen automatically, depending on the contents.
		-->
		<common formats="/latex/xelatex/">
			<xsl:text>\lstinline</xsl:text>
			<xsl:if test="@language">
				<xsl:text>[language=</xsl:text>
				<xsl:value-of select="@language" />
				<xsl:text>]</xsl:text>
			</xsl:if>
			<!--
				We could just call choose-delimiter twice, but this avoids any possibility of weird corner cases where the second call returns a different delimiter from the first call. It's also slightly more efficient to only call the function once.
			-->
			<xsl:variable name="code-delimiter" select="infosci:choose-delimiter( node() )" />
 			<xsl:value-of select="$code-delimiter" />
			<xsl:apply-templates />
 			<xsl:value-of select="$code-delimiter" />
		</common>
		<common formats="/html/xhtml/">
			<code><xsl:apply-templates /></code>
		</common>
	</template>
	
	
	<!--
		Choose a valid delimiter for a LaTeX inline verbatim macro (e.g., \verb or \lstinline). "Valid" means that the delimiter can't occur in the source text. The function thus scans through a list of possible delimiters and looking for those that don't occur in the source text.
		
		$source-text: The source text to be wrapped inside a \verb macro.
		
		Returns: The function actually finds /all/ valid delimiters for the source text because of the effective parallel execution of xsl:for-each on sequences, but it only returns the first one found. If no valid delimiter can be found, the function raises an error and terminates the transformation.
	-->
	<function name="infosci:choose-delimiter" as="xs:string">
		<common formats="/latex/xelatex/">
			<xsl:param name="source-text" />
			
			<xsl:variable name="valid-delimiters">
				<!--
					The LaTeX documentation says that you can use any character as a delimiter except * (because there is a \verb* form). To keep things simple, we've restricted the possible delimiters to punctuation that can be easily expressed in XML.
				-->
				<xsl:for-each select="
					'`', '~', '!', '@', '#', '$', '%', '^', '(', ')', '-', '_',
					'=', '+', '[', ']', '{', '}', '\', '|', ';', ':', ',', '.',
					'/', '?'">
					<xsl:if test="not( contains( $source-text, . ) )">
						<xsl:value-of select = "." />
					</xsl:if>
				</xsl:for-each>
			</xsl:variable>
			
			<!-- $valid-delimiters will be empty if none were found. -->
			<xsl:if test="string-length( $valid-delimiters ) = 0">
				<xsl:message terminate="yes">
					<xsl:text>ERROR: unable to determine a valid delimiter to use in \verb or \lstinline for the source text: </xsl:text>
					<xsl:value-of select="$source-text" />
				</xsl:message>
			</xsl:if>
			
			<xsl:sequence select="substring( $valid-delimiters, 1, 1 )" />
		</common>
	</function>
	
	
	<!--
		Displayed code block. The LaTeX template uses the listings package.
		
		@allow-breaks: Whether or not to allow page breaks in the code block.
			'yes' [default]
			'no
		
		@language: Any language supported by the listings package in LaTeX. Has
			no effect in (X)HTML.
	-->
	<template name="code-block" match="code-block">
		<common formats="/latex/xelatex/">
			<xsl:call-template name="newline-internal" />
			<!--
				If the code-block specifies "allow-breaks='no'", wrap the code block inside a minipage to avoid page breaks within the code.
			-->
			<xsl:if test="@allow-breaks = 'no'">
				<xsl:call-template name="newline-internal" />
				<xsl:text>\begin{minipage}{\textwidth}</xsl:text>
			</xsl:if>
			<xsl:call-template name="newline-internal" />
			<xsl:text>\begin{lstlisting}</xsl:text>
			<!--
				Note that code-block shouldn't be used for code that's really inline (in other words, don't create a code-block element that occurs all on the same line). Otherwise, the template generates a lstlisting environment with the \begin, code \end all on the same line, which eventually gives LaTeX severe indigestion.
				
				We can't just do the obvious fix of wrapping newlines around the code, because this messes up code that actually /does/ have newlines at the start or end by adding extra whitespace.
			-->
			<xsl:if test="@language">
				<xsl:text>[language=</xsl:text>
				<xsl:value-of select="@language" />
				<xsl:text>]</xsl:text>
			</xsl:if>
			<xsl:apply-templates />
			<xsl:text>\end{lstlisting}</xsl:text>
			<xsl:call-template name="newline-internal" />
			<xsl:if test="@allow-breaks = 'no'">
				<xsl:text>\end{minipage}</xsl:text>
				<xsl:call-template name="newline-internal" />
			</xsl:if>
			<xsl:call-template name="newline-internal" />
		</common>
		<common formats="/html/xhtml/">
			<pre class="code"><xsl:apply-templates /></pre>
		</common>
	</template>
	
	
	<!--
		Inline verbatim text (as opposed to inline code). In LaTeX this equates to \verb; delimiters for this are chosen automatically, depending on the contents.
	-->
	<template name="inline-verbatim" match="inline-verbatim|verb">
		<common formats="/latex/xelatex/">
			<!--
				We could just call choose-delimiter twice, but this avoids any possibility of weird corner cases where the second call returns a different delimiter from the first call. It's also slightly more efficient to only call the function once.
			-->
			<xsl:variable name="verb-delimiter" select="infosci:choose-delimiter( node() )" />
 			<xsl:value-of select="$verb-delimiter" />
			<xsl:apply-templates />
 			<xsl:value-of select="$verb-delimiter" />
		</common>
		<common formats="/html/xhtml/">
			<code><xsl:apply-templates /></code>
		</common>
	</template>
	
	
	<!--
		This is for stuff that should unequivocally be treated verbatim (e.g., problem code).
	-->
	<template name="verbatim" match="verbatim|block-verbatim">
		<common formats="/latex/xelatex/">
			<xsl:call-template name="newline-internal" />
			<xsl:text>\begin{verbatim}</xsl:text>
			<xsl:call-template name="newline-internal" />
			<xsl:apply-templates />
			<xsl:call-template name="newline-internal" />
			<xsl:text>\end{verbatim}</xsl:text>
			<xsl:call-template name="newline-internal" />
		</common>
		<common formats="/html/xhtml/">
			<pre><xsl:apply-templates /></pre>
		</common>
	</template>

</stylesheet>