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:

``` xml
<import src="constants.xml" />
<device type="web" uri="HOST">
  <form ... />
</device>
```

Here is a Java snippet:

``` java
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

2
  • 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, 2022 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). Jul 29, 2022 at 18:29

1 Answer 1

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>

    <pre>
Hello!
    </pre>

    <pre>
    <code class="language-lua">
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 .. ",option=" .. lang
    end

    buffers.assign(
      "highlight",
      "\\starttyping[" ..
      options ..
      "]\n" ..
      xml.textonly( t ) ..
      "\n\\stoptyping"
    )
    context.getbuffer { "highlight" }
  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.

1
  • 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. Jul 29, 2022 at 18:36

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .