The highlighter module adds syntax highlighting for Aussom source code to any
browser page. It tokenizes a source string with a regex-based lexer and returns
a styled HNode tree that you insert into the DOM. Two built-in themes (dark and
light) mirror the VS Code color palette, and a custom-theme map lets you override
any token color.
Add include highlighter; to your Aussom script block. Because highlighter
depends on hnodes and util, those modules are loaded automatically. You still
need include html; in the page so the DOM element types (Element, Text,
etc.) are available.
include html;
include highlighter;
The order matters: html must come before highlighter.
include html;
include highlighter;
class Main {
public main(args) {
container = Doc.getElementById("output");
code = "x = 42;\nc.log(x);";
h = new Highlighter();
container.add(h.highlight(code).obj);
}
}
new Highlighter() with no arguments defaults to the dark theme, no line
numbers, and no copy button. highlight(code) returns a Div HNode. Call
.obj on it before passing to container.add() -- see the
DOM Insertion Gotcha for why.
Pass "dark" or "light" as the first argument:
hDark = new Highlighter("dark");
hLight = new Highlighter("light");
null and omitting the argument both default to "dark".
The constructor takes three optional parameters:
Highlighter(Theme = null, bool ShowLineNumbers = false, bool ShowCopyButton = false)
Enable both extras:
h = new Highlighter("dark", true, true);
container.add(h.highlight(code).obj);
The copy button uses navigator.clipboard.writeText via an inline onclick
attribute. It requires the page to be served over HTTPS or localhost (the
Clipboard API is not available on plain file:// URLs in most browsers).
setTheme(Theme) accepts the same arguments as the constructor and returns
this, so calls can be chained:
h = new Highlighter();
h.setTheme("light");
container.add(h.highlight(code).obj);
Because highlight() builds a new DOM tree every time it is called, re-rendering
with a different theme is a matter of clearing the container and calling
highlight() again:
public renderAll(string theme) {
container = Doc.getElementById("output");
container.clear();
h = new Highlighter(theme, true, false);
for (snippet : this.snippets) {
container.add(h.highlight(snippet).obj);
}
}
The Highlighter instance can be reused across multiple highlight() calls with
the same theme.
Tokenizer.tokenize(Code) returns a list of maps, each with "type" and
"text" keys. This is useful if you want to analyze tokens without producing any
DOM output.
t = new Tokenizer();
tokens = t.tokenize("x = 42;");
for (tok : tokens) {
c.log(tok.get("type") + " : " + tok.get("text"));
}
Sample output:
ident : x
ws :
operator : =
ws :
number : 42
punctuation: ;
Token types are string constants. TokenType is a static class that provides
named constants if you prefer not to hard-code the strings:
if (tok.get("type") == TokenType.KEYWORD) { ... }
Pass a map of {tokenType: colorString} as the theme. Missing token types fall
back to the dark-theme defaults, so you only need to supply the colors you want
to override.
myTheme = {
"keyword": "#ff79c6",
"string": "#f1fa8c",
"number": "#bd93f9",
"comment": "#6272a4",
"doc": "#6272a4",
"ident": "#f8f8f2",
"operator": "#ff79c6",
"unknown": "#ff5555"
};
h = new Highlighter(myTheme, true, true);
container.add(h.highlight(code).obj);
The background, header, label, and border colors are not part of the token color
map. When a custom map is supplied, those values are taken from the dark-theme
defaults (#1e1e1e background, #2d2d30 header, etc.). There is currently no
API to override them through the constructor; post-process the returned HNode if
you need different chrome colors.
highlight() returns a Div HNode. You can modify it before inserting it into
the DOM:
result = h.highlight(code);
result.setStyle("margin-bottom", "0");
result.setStyle("border-radius", "0");
container.add(result.obj);
The full DOM structure produced is:
Div.aus-highlighter (outermost wrapper)
Div.aus-header
Span.aus-lang-label ("aussom")
Button.aus-copy-btn (optional)
Pre.aus-pre
Code.aus-code
Span.aus-line (one per source line)
Span.aus-line-num (optional, non-selectable)
Span.aus-token.aus-{type} (one per token)
All classes and inline styles are applied at build time so the output is self-contained. You can add CSS rules that target the class names to override individual properties.
Because highlight() uses both class names and inline styles, CSS specificity
may require !important to override inline values:
.aus-highlighter {
font-size: 13px !important;
border-radius: 0 !important;
}
.aus-line-num {
min-width: 3em !important;
}
To highlight only certain token types differently, target the combined class:
.aus-token.aus-keyword { font-weight: bold; }
.aus-token.aus-unknown { text-decoration: underline wavy red; }
When the source snippet itself contains """, the Aussom triple-quote sequence
would terminate the outer literal. Escape each inner " as \":
code = """block = \"\"\"line one
line two\"\"\";""";
h = new Highlighter();
container.add(h.highlight(code).obj);
The highlighter receives the string with literal """ characters and tokenizes
them as a triple-quoted string literal correctly.
highlight() returns an HNode Div object, not a raw DOM element. When you add
it to a container obtained from Doc.getElementById(), you must call .obj on the
result to extract the underlying Element extern:
container = Doc.getElementById("output");
// WRONG -- throws "Unexpected extern object type" at runtime:
container.add(h.highlight(code));
// CORRECT:
container.add(h.highlight(code).obj);
Doc.getElementById() returns a raw Element extern whose .add() method is
implemented in Java. That method only accepts other Element, Text, Video,
or Img externs. Passing a plain Aussom HNode wrapper causes the type check to
fail.
The same rule applies when adding any other HNode to a Doc.getElementById() container:
lbl = new P();
lbl.setHtml("Label");
container.add(lbl.obj); // extract the Element
This issue does not arise when adding HNodes to other HNodes (e.g., inside
highlight() itself), because HNode.add() is an Aussom method that extracts
.obj internally.
| Class | Element | Description |
|---|---|---|
aus-highlighter |
div |
Outermost code window wrapper |
aus-header |
div |
Header bar (label + optional copy button) |
aus-lang-label |
span |
Language tag ("aussom") in the header |
aus-copy-btn |
button |
Copy-to-clipboard button (when enabled) |
aus-pre |
pre |
Scrollable code area |
aus-code |
code |
Inner code block |
aus-line |
span |
One block-level span per source line |
aus-line-num |
span |
Line number gutter cell (when enabled) |
aus-token |
span |
Present on every token span |
aus-{type} |
span |
Token-type class (e.g., aus-keyword) |
| Type | TokenType constant |
What it matches |
|---|---|---|
doc |
TokenType.DOC |
/** ... */ doc comments |
comment |
TokenType.COMMENT |
/* ... */ and // ... comments |
string |
TokenType.STRING |
"...", '...', and """...""" literals |
number |
TokenType.NUMBER |
Integer and floating-point literals |
keyword |
TokenType.KEYWORD |
Reserved words (class, if, return, ...) |
boolean |
TokenType.BOOLEAN |
true and false |
operator |
TokenType.OPERATOR |
Operators (=, +=, ==, &&, ...) |
punctuation |
TokenType.PUNCTUATION |
Delimiters (;, ,, (, {, ...) |
ident |
TokenType.IDENT |
Identifiers not matched by other types |
ws |
TokenType.WS |
Spaces, tabs, and form feeds |
unknown |
TokenType.UNKNOWN |
Any character that matches no pattern (shown in red) |
newline tokens are consumed internally to split lines and are not present in
token spans.
Reuse the Highlighter instance. Each new Highlighter(...) call sets up the
theme and options once. Calling highlight() multiple times on the same instance
is safe and efficient.
Prefer triple-quoted strings for multi-line snippets. Aussom's """..."""
literals preserve newlines exactly, making them the natural choice for source
code snippets:
code = """public greet(string Name) {
c.log("Hello, " + Name + "!");
}""";
Unknown tokens do not abort highlighting. If the source contains a character
that the lexer cannot match (for example $), the highlighter emits a single
unknown token for that character and continues from the next position. The rest
of the snippet is highlighted normally. This error-recovery behavior means
partially valid or experimental code still renders usefully.
The copy button requires a secure context. navigator.clipboard.writeText
is only available over HTTPS or on localhost. On plain file:// pages the
button renders but the write silently fails (the .catch handler suppresses the
error). Disable the copy button (ShowCopyButton = false) if you are serving
from file:// and want to avoid confusion.
Line numbers are non-selectable. The line number spans have user-select: none and -webkit-user-select: none applied inline, so selecting and copying
code does not include the line numbers.
Custom themes only override token colors. Background, header, border, and
label colors are fixed to the dark-theme values when a custom map is supplied.
To change those, call setStyle() on the returned HNode after highlight():
result = h.highlight(code);
result.setStyle("background", "#282a36");
container.add(result.obj);