2

Background

Looking to apply syntax highlighting to source code snippets embedded within XHTML code elements, demarcated with a class attribute to indicate the language.

Using:

mtx-context     | current version: 2021.11.30 19:49

Note: The XHTML is produced from a Markdown document, such as:

Here is an XML snippet:
<import src="constants.xml" />
<device type="web" uri="HOST">
  <form ... />
</device>

Here is a Java snippet:

import java.net.*;

public class JavaClass {
  // ...
}

Problem

There are a couple of issues:

  • Calling \xmlflushspacewise{#1} does not seem to afford the ability to apply syntax highlighting to the nested source code snippet.
  • Applying syntax highlighting dynamically based on the code element's class, which follows the form "language-X" where X could be any well-known programming language (xml, python, java, ruby, javascript, and others).

Code

The following example typesets the source code snippet as expected:

\startbuffer[html]
<html>
<body>
<pre>
      <code class="language-xml">&lt;import src="constants.xml" /&gt;
&lt;import src="tests/login.xml" /&gt;

&lt;device type="web" uri="HOST"&gt; &lt;click id="device" /&gt;

&lt;form id="upload-file"&gt; &lt;assign id="firmware" value="FILENAME.fw" /&gt; &lt;click id="upload-file-button" /&gt; &lt;/form&gt; &lt;/device&gt; </code> </pre> </body> </html> \stopbuffer

\startxmlsetups xml:initialize \xmlsetsetup{#1}{}{-} \xmlsetsetup{#1}{html|body|pre|code}{xml:} \stopxmlsetups

\xmlregistersetup{xml:initialize}

\startxmlsetups xml:html \startdocument \xmlflush{#1} \stopdocument \stopxmlsetups

\startxmlsetups xml:body \xmlflush{#1} \stopxmlsetups

\startxmlsetups xml:pre \xmlflush{#1} \stopxmlsetups

\startxmlsetups xml:code \xmlflushspacewise{#1} \stopxmlsetups

\xmlprocessbuffer{main}{html}{}

This produces:

XML document output

Question

How would you apply syntax highlighting to the output in a way that is agnostic with respect to the code snippet language being coloured?

As a bonus, is it possible to do in a cross-platform way (that is, not relying on vim)?

Related

Dave Jarvis
  • 11,809
  • I understand the desire not to rely on vim, but would just point out that the t-vim module is cross platform. – Aditya Jul 29 '22 at 12:28
  • Right. It's cross-platform, but vim must be installed on all platforms and, presumably, its executable directory added to the PATH. Installation a bit painful on Windows, especially if you need to get IT's permission to install executables (self-contained versions notwithstanding). – Dave Jarvis Jul 29 '22 at 18:29

1 Answers1

2

Mostly copied from the Wiki page "Verbatim XML":

\startbuffer[html]
<html>
<body>
<pre>
      <code class="language-xml">&lt;import src="constants.xml" /&gt;
&lt;import src="tests/login.xml" /&gt;

&lt;device type="web" uri="HOST"&gt; &lt;click id="device" /&gt;

&lt;form id="upload-file"&gt; &lt;assign id="firmware" value="FILENAME.fw" /&gt; &lt;click id="upload-file-button" /&gt; &lt;/form&gt; &lt;/device&gt; </code> </pre>

&lt;pre&gt;

Hello! </pre>

&lt;pre&gt;
&lt;code class=&quot;language-lua&quot;&gt;

for k, v in ipairs(table) do print(k, v) end </code> </pre> </body> </html> \stopbuffer

\startxmlsetups xml:initialize \xmlsetsetup{#1}{}{-} \xmlsetsetup{#1}{html|body|pre|code}{xml:} \stopxmlsetups

\xmlregistersetup{xml:initialize}

\startxmlsetups xml:html \startdocument \xmlflush{#1} \stopdocument \stopxmlsetups

\startxmlsetups xml:body \xmlflush{#1} \stopxmlsetups

\usemodule[scite] % Optional

\startluacode function xml.functions.highlight( t ) local lang = (xml.attribute( t, "/", "class" ) or "") :match("language%-(.*)") local options = "before=\startlinenumbering,after=\stoplinenumbering"

if lang then
  options = options .. &quot;,option=&quot; .. lang
end

buffers.assign(
  &quot;highlight&quot;,
  &quot;\\starttyping[&quot; ..
  options ..
  &quot;]\n&quot; ..
  xml.textonly( t ) ..
  &quot;\n\\stoptyping&quot;
)
context.getbuffer { &quot;highlight&quot; }

end \stopluacode

\startxmlsetups xml:pre \xmlflush{#1} \stopxmlsetups

\startxmlsetups xml:code \pushcatcodetable \setcatcodetable\ctxcatcodes \startnarrower[left] \xmlfunction{#1}{highlight} \stopnarrower \popcatcodetable \stopxmlsetups

\xmlprocessbuffer{main}{html}{}

As a bonus, is it possible to do in a cross-platform way (that is, not relying on vim)?

You can use the builtin highlighters to highlight XML, MetaPost, TeX, Lua, and C. You can also use the builtin scite module which supports XML, MetaPost, TeX, Lua, C, C++, SQL, and JSON.

If you need more languages, you can code your own highlighters (not too difficult) or use the vim module.

Dave Jarvis
  • 11,809
Max Chernoff
  • 4,667
  • FWIW, I looked into adding my own highlighter for Java and it was confusing right out of the gate. For example, C++ has two syntax files in different locations with no immediate indication as to which one is needed. What would be helpful is a full and complete step-by-step guide that describes how to add a simple C-family syntax highlighter to scite. Another example, it isn't obvious how to "debug" problems with the highlighter---like how do you output a simple logging statement into ConTeXt's logger? It may be a bit misleading to state that it's "not too difficult". I eventually gave up. – Dave Jarvis Jul 29 '22 at 18:36