Compact Web Language (COWEL)
Contents
Introduction
Motivation
Getting started
Native installation
Syntax
EBNF grammar
Text
Whitespace
Escape sequences
Comments
Directives
Directive names
Directive arguments
Named arguments
Positional arguments
Ellipses
Groups
Directive content
Document processing
Content policies
Directive processing
Lazy processing
Themes
New directives
Common principles
Parameter notation
Usual argument matching
Character utilities
\cowel_char_by_entity
— Character by HTML character reference
\cowel_char_by_name
— Character by Unicode name
\cowel_char_by_num
— Character by code point number
\cowel_char_get_num
— Get digits of character
HTML utilities
\cowel_html_element
— HTML element
\cowel_html_self_closing_element
— Self-closing HTML element
Content policies
\cowel_to_html
— Process with to-HTML policy
\cowel_no_invoke
— Process with no-invoke policy
\cowel_actions
— Process with actions policy
\cowel_text_only
— Process with text-only policy
\cowel_text_as_html
— Process with text-as-HTML policy
\cowel_source_as_text
— Process with source-as-text policy
Syntax highlighting
\cowel_highlight
— Perform syntax highlighting
\cowel_highlight_as
— Syntax highlight override
\cowel_highlight_phantom
— Syntax highlight phantom text
Paragraph control
Paragraph splitting
\cowel_paragraphs
— Perform paragraph splitting
\cowel_paragraph_enter
— Enter a paragraph
\cowel_paragraph_leave
— Leave a paragraph
\cowel_paragraph_inherit
— Activate paragraph splitting inside a directive
File management
\cowel_include
— Include a sub-document
\cowel_include_text
— Include text from a file
Aliases and macros
\cowel_alias
— Define aliases for an existing directive
\cowel_macro
— Define a macro
\cowel_put
— Process provided macro content or arguments
Invocations
\cowel_invoke
— Invoke a directive
Legacy directives
Comments
\comment
— Comments
Text formatting
Code and syntax highlighting
\code
— Inline code
Manual nested highlighting
Further advice on highlighting
\codeblock
— Code blocks
\hl
— Syntax highlight override
\pre
— Preformatted blocks
\literally
— Treat input literally as text
\unprocessed
— Suppress directive processing
Math
\math
— Inline math
\mathblock
— Math blocks
Separators and word breaking
\br
— Break line
\hr
— Horizontal rule
\wbr
— Word break opportunity
\nobr
— Unbroken words
Special blocks
\Babstract
— Abstract blocks
\Bquote
— Quote blocks
\blockquote
— Alias for \Bquote
\Bug
— Bug blocks
\Bdecision
— Decision blocks
\Bdel
— Deletion blocks
\Bdetails
— Details blocks aka spoilers
\details
— Alias for \Bdetails
\Bdiff
— Difference blocks
\Bex
— Example blocks
\Bins
— Insertion blocks
\Bimp
— Important blocks
\Bnote
— Note blocks
\Btip
— Tip blocks
\Btodo
— TODO blocks
\Bwarn
— Warning blocks
Lists
\ul
— Unordered lists
\ol
— Ordered lists
\li
— List items
\item
— List item pseudo-directive
\dl
— Definition lists
Tables
Headings
\make_contents
— Make table of contents
Bibliography
\bib
— Add bibliography entry
\make_bib
— Generate bibliography
References
\ref
— References
\mail
— E-Mail addresses
\tel
— Telephone numbers
Foreign languages
\script
— JavaScript blocks
\noscript
— No-JavaScript content
\style
— CSS blocks
Sections
\there
— Append content to section
\here
— Copy section content
\hereblock
— Copy section content in block
Miscellaneous
\div
— Content division
\trim
— Trim input
\text
— Plaintext context
\p
— Paragraphs
Variables and calculations
\Vset
— Set a variable
\Vget
— Get a variable
\Cadd
— Perform addition
\Csub
— Perform subtraction
\Cmul
— Perform multiplication
\Cdiv
— Perform division
1. Introduction
COWEL is a markup language with TeX-like syntax, intended to generate HTML documents, mainly for proposals and technical text. Many of its features are purpose-built for use in WG21, such as for writing C++ proposals.
... generates the HTML ...
... which renders as:
2. Motivation
Many similar tools (mpark/wg21, bikeshed, etc.) are based on Markdown. This makes them beginner-friendly, but advanced formatting requires heavy use of Markdown extensions or mixed use of Markdown and HTML tags. Metadata such as bibliographies, document information, etc. also rely on yet another format (e.g. JSON, YAML).
This makes these tools difficult to master and makes the design incoherent. Why do we need three languages glued together just to format our documents?
COWEL is the missing middle, the missing link. It makes producing HTML a natural part of the language, lets you specify metadata, and more, all in one, simple syntax.
3. Getting started
To use and install COWEL,
you need to install Node.js and
See also https://www.npmjs.com/package/cowel. With COWEL installed, you can convert COWEL documents to HTML by using:
To see a list of available options and commands,
run
by itself or
.
or otherwise elevate your permissions
because
performs a "global"/system-wide installation.
This is necessary to make the
command available everywhere.
It is recommended to use a
Many text editors support associating such file extensions with TeX or LaTeX syntax highlighting, whose syntax is similar enough to get some basic highlighting. A VSCode plugin for proper highlighting is planned, among other features.
3.1. Native installation
There also exists a more limited native CLI for development purposes. To install it and run COWEL:
The
and
.
Running
without extra arguments also brings up the help menu.
4. Syntax
COWEL has a minimalistic but powerful syntax, built on top of only three syntactical constructs:
Text.
- Escape sequences, such as
,\ {
,\ }
, etc.\ \ \ : Comments \ various_directives ( positional args, named-args = 0) { and content}
4.1. EBNF grammar
Formally, in EBNF
grammar format,
a
4.2. Text
Text (
<
in text will render as a < character,
but will be converted to
when fed into a To-HTML Policy.
Furthermore, text is subject to special effects like syntax highlighting
and paragraph splitting.
4.2.1. Whitespace
COWEL translates text in whitespace directly into HTML in most situations.
Additional styling with CSS can be applied
to interpret that whitespace literally (like in
elements)
or to have it merged into spaces,
which happens by default.
At the document top-level, §7.6.1. Paragraph splitting takes place.
Generated HTML:
Rendered output:
4.3. Escape sequences
COWEL supports multiple escape sequences,
all of which begin with a \
(like directives),
but are followed by some special character.
The meaning of the escape sequences is described in the table below.
Escape sequence | Meaning |
---|---|
|
Expands to the second character in the escape sequence. These sequences are stable. |
|
Expands to the second character in the escape sequence. These sequences are unstable, meaning that they could be given a different meaning in the future. Use with caution! |
|
Expands to nothing; feature is stable |
In EBNF grammar, an
If there is an ambiguity between a CRLF escape and a simple U+000D CARRIAGE RETURN escape, this ambiguity is resolved in favor of a CRLF escape.
The purpose of the newline escapes is to remove unwanted newlines and to join long content that spans multiple lines, but without introducing any whitespace in the markup.
4.4. Comments
Comments begin with
and extend until the end of the line.
In almost every context,
comments are discarded instead of being emitted into the output HTML.
This makes them useful for adding information to the COWEL markup.
— Process with source-as-text policy will render as expected:
This renders as:
In EBNF grammar, a
Comments include a
Generated HTML:
4.5. Directives
A directive is a way of generating plaintext, HTML, both, or neither. You can think of it as a "command" or "function call".
Every directive has three parts:
-
The
selects a specific directive to be processed.\ directive_name -
An optional
provides additional inputs to the directive.( comma-separated, positional arguments, named-arguments = ...) -
An optional
provides a "main input" to a directive.{ block of content}
In EBNF grammar, a
4.5.1. Directive names
A directive name selects a specific directive to be processed.
The name begins with a U+005C (
Doing so is equivalent to writing
and longword
immediately following one another.
Grammatically, the arguments are a
4.5.2. Directive arguments
Directive arguments can be positional arguments, named arguments, or ellipses. Arguments are separated by commas. Unlike anywhere else, whitespace surrounding directive arguments is ignored. The value of positional or named argument is either a markup sequence or a group.
Generated HTML:
4.5.2.1. Named arguments
Named arguments are of the form
name = value
, where spaces anywhere around name
and value
are ignored.
Named arguments are matched to directive parameters before any positional arguments,
meaning that positional arguments fill the remaining unmatched arguments.
Argument names can consist of any character, except
ASCII control characters,
U+0020 SPACE,
U+0022 (
name = value
instead,
you can do so by writing:
Only the literal =
character can be used for named arguments,
not its escaped variant
.
Grammatically, a
4.5.2.2. Positional arguments
Positional arguments are content just like any other content,
except that an unbalanced closing U+005D (
Grammatically, a positional argument is a
4.5.2.3. Ellipses
Ellipsis arguments (spelled
)
are placeholders which expand to arguments provided to a surrounding macro.
See also §7.8.2.
— Define a macro and §7.8.3.
— Process provided macro content or arguments.
Generated HTML:
Specifically, any positional argument which begins with
(ignoring leading whitespace and comments)
is considered an ellipsis.
The text
An error is raised if
- any content follows the ellipsis, or
- an ellipsis is used as an argument outside of a macro expansion.
(only the first dot is part of the escape).
4.5.2.4. Groups
Groups make it possible to group any of the aforementioned constructs.
Groups begin with
and end with
.
They can appear both in positional and in named arguments.
4.5.3. Directive content
The directive content is the primary input to a directive.
It is delimited by a '
Generated HTML:
Escape sequences don't participate in this "brace matching", so they can be used to literally produce a brace character.
Generated HTML:
Unlike in the directive arguments, whitespace is not trimmed.
Generated HTML:
5. Document processing
A COWEL document is processed from top to bottom, left to right, where each piece of content is fed into the current content policy.
There exists a top-level content policy which takes its input and writes it to the output HTML file.
5.1. Content policies
A content policy dictates how each pice of content (text, comments, escapes, directives) is transformed into HTML or consumed in some other way. For example, most content policies ignore comments, process directives, etc., but other policies can process all these pieces of content into text.
Content policies are piped, meaning that the output of one policy is used as the input to another policy. In a COWEL document, it is common to create long pipes of content policies. These ultimately terminate in the top-level content policy or in a policy which captures the output and writes it to memory for further processing.
The following builtin content policies exist:
- To-HTML policy
- Comments are ignored, escape sequences are expanded, text is sanitized and converted to "inner HTML" text for elements, and directives are processed as usual. Received HTML is taken literally, and received plaintext is sanitized like text.
- Highlight policy
- Like a to-HTML policy, but any text content and any received plaintext has syntax highlighting applied to it.
- Paragraphs policy
- Like a to-HTML policy, but surrounds given text content in paragraphs, and treats blank lines in text as paragraph separators. See §7.6.1. Paragraph splitting for details.
- No-invoke policy
- Like a to-HTML policy, but directives are not processed. Instead, the source code of directives is taken, sanitized, and fed as HTML into the surrounding policy.
- Actions policy
- Ignores text, escape sequences, and comments, and passes any other content (e.g. directives) to the surrounding policy.
- Text-only policy
- Comments are ignored, escape sequences are expanded, text is taken literally, and directives are processed as usual. HTML content fed into this policy is ignored.
- Text-as-HTML policy
- Like a text-only policy, but instead of feeding its parent policy with the generated plaintext, all plaintext is reinterpreted as HTML before being fed into the parent policy.
- Source-as-text policy
- The source code of all processed content is interpreted as plaintext and fed into the surrounding policy. This includes comments.
To process directives as usual means that when a directive is encountered, a definition matching the directive name is looked up, and the definition is invoked with the arguments and content of the directive.
The top-level content policy within a document is a paragraph split content policy, feeding content into an HTML content policy.
5.2. Directive processing
The job of directives is to feed the current content policy with content. Unlike text or escape sequences, directives can do so programmatically.
,
the
directive feeds the current content policy with
- an opening
tag,< b > - all content within
, i.e. the text\ b { x} x
, and - a closing
tag.</ b >
Content policies differ in how they treat the content they're fed:
-
At a top level within the document,
the opening
and closing< b >
are simply written as HTML to the output file. The given text</ b > x
is sanitized (i.e. characters like< are escaped) and turned into inner HTML content. The result is simply
.< b > x</ b > -
When fed into a highlight policy,
HTML tags are interpreted literally in the same way.
However, syntax highlighting is applied to the given input text,
resulting in
.< b > syntax highlighted x</ b > -
A literally content policy would not have processed
in the first place, but taken its source code interpreted as text, and fed that into the surrounding policy.\ b { x} - …
5.2.1. Lazy processing
Unlike in typical programming languages, where the input to a function is processed at the call site and the resulting values are passed into the function, COWEL directives have absolute control over their inputs and how they are processed.
Say you have a JavaScript function:
has no idea that its input was originally
.
It only sees the value
and prints it, "oblivious to the outside".
COWEL follows a different model:
No
tag is ever generated because
is never processed.
is not magical feature;
it simply has control over all of its contents and arguments,
and it can choose not to process them.
You can even make a
directive that works
just like
yourself:
6. Themes
COWEL outputs documents that can be viewed in light mode and dark mode.
When the document is opened with support for JavaScript, there is an button in the top-right that can be used to switch between three modes:
- Sync the theme with the OS (default)
- Light mode (ignoring system preference)
- Dark mode (ignoring system preference)
Forced light/dark mode works by adding a
element in the DOM.
For reference, you can look at the CSS in the COWEL source code to see how it's done properly.
7. New directives
Find below a list of builtin directives. That is, directives that you can always use because they are "built into the language".
Even if one wanted to use them, builtin directive have long names which make them impractical for direct use in markup. However, those long names are self-document, unambiguous, and guaranteed not to collide with any user directives.
7.1. Common principles
There are a few common principles, which all builtin directives have in common:
- Unless otherwise stated, arguments to builtin directives are processed using the text-only policy (§5.1. Content policies).
- Arguments to builtin directives use the usual argument matching (§7.1.2. Usual argument matching).
- Whenever content or arguments are said to be ignored, a warning is emitted when content or arguments are provided by the user, respectively.
7.1.1. Parameter notation
While COWEL does not yet support a syntax for defining directives with parameters of a specific type, this documentation does for the builtin directives. This notation consists of
- the directive name,
-
a list of parameters in parentheses,
consisting of the parameter name and the parameter type, separated by '
: ', and optionally followed by '= ' and a default value, and -
optionally,
the symbol
{...} to indicate that the directive accepts content.
The type notation
any - Placeholder for any other type.
integer - An integer, such as
123 . boolean - An boolean; either
true orfalse . string - A sequence of content.
markup -
A sequence of content which is processed lazily, i.e. it is not evaluated
where the directive is invoked, but at some later point (or not at all).
This is essentially
lazy string . pack(element: type) -
Multiple occurrences of the same
element , zero or more times. group(members: pack type) - A group of zero or more members, possibly of different types.
optional(t: type) -
Same as
t , but can be omitted in usual argument matching (§7.1.2. Usual argument matching). lazy(t: type) -
Same as
t , but not processed during argument matching, but within the directive. named(t: type) -
A named argument with value type
t .
looks as follows:
cowel_html_element( name: string, attr: optional group pack named lazy string, ){...}
Or equivalently:
cowel_html_element( name: string, attr: optional(group(pack(named(lazy(string))))), ){...}
This describes that
can be invoked as follows,
among various options:
matches the
7.1.2. Usual argument matching
The usual argument matching allows matching positional and named arguments to parameters of directives. An error is raised if positional and named arguments are mixed, unless all positional arguments appear contiguously at the start of the argument list.
The usual argument matching is performed as follows:
- Positional arguments match parameters in the same order. An error is raised if there are more positional arguments than parameters.
- The following named arguments match parameters with the same name. An error is raised if a named argument does not match any parameter.
-
If any parameter has not been matched by an argument,
the parameter is matched by its default argument value if there is one,
otherwise, if it has
optional type, it is matched by nothing, and otherwise an error is raised.
be a directive with parameters
7.2. Character utilities
It is quite common that a text document should include special characters. While COWEL is built on UTF-8 and in theory, one could just write the character directly into the source code, not every text editor handles special characters well, not to mention that some characters are invisible when rendered.
For portability and convenience COWEL has builtin directives for generating and querying characters.
7.2.1. \cowel_char_by_entity
— Character by HTML character reference
cowel_char_by_entity(){...}
The
directive takes the name of a character
and outputs the respective code points as text.
The input to a
directive is provided as content,
which consists of an HTML entity
without the leading '
- Literally '
& ' in text
(like\ c { amp}
, named character reference)&
(like\ c { #38}
, decimal character reference)&38;
(like\ c { #x26}
, hexadecimal character reference)&x26;
7.2.2. \cowel_char_by_name
— Character by Unicode name
cowel_char_by_name(){...}
The input to a
directive is text content which should be a
Unicode name
for a code point.
That is, the name of a code point,
or one of its "control", "alternate", or "correction" aliases.
generates '
7.2.3. \cowel_char_by_num
— Character by code point number
cowel_char_by_num(){...}
The input to a
directive is text content
which should be a sequence of hexadecimal numbers
specifying a Unicode scalar value;
that is, a code point which UTF-8 permits to be encoded.
All arguments are ignored.
generates '
can lead to much more descriptive,
human-friendly code, compared to
.
The main issue with
is
that it is very non-descriptive in source code.
It simply contains a handful of digits,
and unless the reader is a Unicode expert who happens to know that sequence,
they cannot easily tell what the purpose of the character is.
7.2.4. \cowel_char_get_num
— Get digits of character
cowel_char_get_num( zfill: integer = 0, base: integer = 16, lower: boolean = false, ){...}
The
directive is essentially the
inverse of the
directive.
Its input is also plaintext content.
Rather than producing a code point from a digit sequence,
it produces a digit sequence from its input code point.
This can be fine-tuned with the following parameters:
This renders as:
Note that U+0078 is the usual way in which Unicode code points are represented.
That is,
can also be combined with
to produce human-readable descriptions of code points,
while also keeping our source code readable:
This renders as:
uses only the first code point within the input text,
even though the entire input text is processed into plaintext.
This renders as
... which corresponds to a
, whereas b
and c
are discarded.
7.3. HTML utilities
7.3.1. \cowel_html_element
— HTML element
cowel_html_element( name: string, attr: optional group pack named lazy string, ){...}
The
directive generates content,
surrounded in HTML opening and closing HTML tags.
That is, it
- writes an opening tag, where any named arguments are converted to HTML attributes,
- feeds the provided content into the current content policy, and then
- writes a closing tag.
The name of the HTML element is contained in the
Generated HTML:
A
directive produces an error if the given
tag name is not a valid HTML tag name, or
if any of the argument names are not valid HTML attribute names.
7.3.2. \cowel_html_self_closing_element
— Self-closing HTML element
cowel_html_self_closing_element( name: string, attr: optional group pack named lazy string, )
The
directive generates a self-closing HTML element.
That is, an element with no content,
and where there is no closing tag.
Content is ignored.
The name of the HTML element is contained in the
Generated HTML:
7.4. Content policies
As explained in §5.1. Content policies, all content within the document and produced by directives is fed into a content policy, which, in turn, feeds content into some parent content policy.
The table below lists directives which process content using some content policy.
Directive | Content policy | Notes |
---|---|---|
|
HTML policy | |
|
highlight policy | see §7.5.1. — Perform syntax highlighting |
|
paragraphs policy | see §7.6.2. — Perform paragraph splitting |
|
no-invoke policy | |
|
no-invoke policy | |
|
text-only policy | |
|
text-as-html policy | |
|
source-as-text policy |
7.4.1. \cowel_to_html
— Process with to-HTML policy
cowel_to_html(){...}
simply processes the provided content using the to-HTML policy.
The purpose of this policy/directive is mainly to feed its parent policy pure HTML content, rather than a mixture of plaintext and HTML. This also suppresses paragraph splitting, syntax highlighting, and other such "special treatments" of plaintext, since none of those operate on HTML.
This renders as:
reinterpret_cast
is discouraged.
Or, if line wrapping takes place in the middle of the highlighted keyword, it renders as:
7.4.2. \cowel_no_invoke
— Process with no-invoke policy
cowel_no_invoke(){...}
processes the provided content
using the no-invoke policy.
Generated HTML:
Under the no-invoke policy selected by no_invoke
,
is not invoked,
but its source code is fed into the current policy as plaintext.
This is particularly useful when writing code blocks
which contain character escapes (e.g. containing
in C++)
because such escapes should not treated as COWEL directives.
7.4.3. \cowel_actions
— Process with actions policy
cowel_actions(){...}
processes the provided content
using the actions policy.
This is particularly useful in macros and surrounding macros because it prevents whitespace from being emitted into the HTML file. Normally, whitespace is preserved, unless explicitly eliminated (e.g. with newline escapes or commas).
Generated HTML:
Note that nine macros have also been defined by the COWEL markup, but macro definitions produce no output.
7.4.4. \cowel_text_only
— Process with text-only policy
cowel_text_only(){...}
processes the provided content
using the text-only policy.
Generated HTML:
As can be seen, only plaintext "makes it through", whereas HTML is stripped.
strong
positional argument to
in the example above.
It is mainly useful in situations where it makes no sense to have non-plaintext content.
7.4.5. \cowel_text_as_html
— Process with text-as-HTML policy
cowel_text_as_html(){...}
processes the provided content
using the text-as-HTML policy.
Generated HTML:
As can be seen, the provided text is reinterpreted as HTML.
and other safer directives should be preferred.
7.4.6. \cowel_source_as_text
— Process with source-as-text policy
cowel_source_as_text(){...}
processes the provided content
using the source-as-text policy.
Generated HTML:
It can be seen as a more extreme form of
,
and is more niche in its applications.
7.5. Syntax highlighting
Syntax highlighting improves the readability of inline code and code snippets by applying different formatting (usually colors) based on the syntactical meaning of text. Many examples can be found in this document.
7.5.1. \cowel_highlight
— Perform syntax highlighting
cowel_highlight( lang: string, ){...}
The
processes content using the highlight policy,
which wraps parts of code in HTML tags for the purpose of syntax highlighting.
has a single
7.5.2. \cowel_highlight_as
— Syntax highlight override
The
directive forces certain syntax highlighting
to be applied to some text;
it is a manual override for when automatic syntax highlighting is insufficient or broken.
This is done by wrapping the given content in HTML tags for syntax highlighting
and feeding the provided content, converted to HTML into the surrounding policy,
so it is not subject to automatic highlighting.
has a single
.
The long name is the enumerator name without the
This generates the HTML (subject to change):
It renders as
.
,
the "short names" (e.g. kw_type
) are not stable,
i.e. they are more likely to change.
Only µlight long names should be used directly.
7.5.3. \cowel_highlight_phantom
— Syntax highlight phantom text
cowel_highlight_phantom(){...}
The
directive
can be used to further customize syntax highlighting.
It outputs phantom text, which is fed into the syntax highlighter,
but is not part of the output content.
The provided content is processed using a text-only policy (§5.1. Content policies). If the current policy is a highlight policy, the text output by the former is turned into phantom text within the latter. Otherwise, the generated text is discarded. All arguments are ignored.
,
we can control whether a JSON string is interpreted as a markup key,
or as a string value:
Using the highlight theme of this document, this renders as:
"keys"
and " values "
.
Notice that the color of
is different
because it is highlighted as if it was positioned like:
7.6. Paragraph control
Dividing content into paragraphs manually would take a huge amount of effort,
so COWEL provides means of doing so semi-automatically.
Text within in a paragraphs policy (§5.1. Content policies)
is automatically wrapped in paragraphs (
),
divided at blank lines.
While content expanded from macros and from
is fed into the surrounding content policy
(which may be a paragraphs policy) directly,
directives are generally treated as "black boxes"
for the purpose of paragraph splitting,
and they neither begin nor end a paragraph.
The following paragraph control directives define interactions
between paragraph splitting and directives.
7.6.1. Paragraph splitting
At the top-level in the document and within the content of certain directives,
paragraph splitting takes place.
All content in COWEL is either inline content, block content, or meta content.
Text and escape sequences are inline content,
and directives are sometimes inline and sometimes block content.
Certain directives (e.g.
) that don't generate anything rendered are meta content.
The process of paragraph splitting works as follows:
-
Blank-line-separated blocks of inline content is wrapped in in
tags. Meta content is not counted as a blank line, so it "continues" inline content, but no effort is made to wrap it in< p > ...</ p >
.< p > ...</ p > -
Block content stays untouched, i.e. it is not wrapped in
. However, it also terminates prior inline content, like a blank line.< p > ...</ p >
Generated HTML:
7.6.2. \cowel_paragraphs
— Perform paragraph splitting
cowel_paragraphs(){...}
The
directive
creates a paragraphs policy (§5.1. Content policies)
and feeds all provided content into that policy.
The beginning and end of the provided content are considered to be outside a paragraph.
All arguments are ignored.
Generated HTML:
.
However, this does not extend recursively,
so if one wants to have paragraph splitting inside say,
,
has to be used.
7.6.3. \cowel_paragraph_enter
— Enter a paragraph
cowel_paragraph_enter()
If the current content policy is a paragraphs policy and
and the paragraph state is "outside",
the paragraph state becomes "inside",
and a
tag is emitted.
Otherwise, has no effect.
Generated HTML:
As explained, directives are "black boxes" for paragraph splitting,
so when the paragraphs policy processes
,
it does not automatically begin a paragraph.
should rarely be used directly,
but from within macros.
For example, the user can define an
directive which combines
and
.
7.6.4. \cowel_paragraph_leave
— Leave a paragraph
cowel_paragraph_leave()
If the current content policy is a paragraphs policy and
and the paragraph state is "inside",
the paragraph state becomes "outside",
and a closing
tag is emitted.
Otherwise, has no effect.
Generated HTML:
As explained, directives are "black boxes" for paragraph splitting,
so when the paragraphs policy processes
,
it does not automatically leave a paragraph.
This would be necessary because horizontal rules (
)
are not supposed to be inside a paragraph.
should rarely be used directly,
but from within macros.
For example, the user can define a
directive which combines
and
.
7.6.5. \cowel_paragraph_inherit
— Activate paragraph splitting inside a directive
cowel_paragraph_inherit()
may be used to alter behavior.
As already stated,
paragraph splitting generally treats directives as "black boxes".
However, content expanded from
and macros
inherits the surrounding paragraph for splitting,
i.e. any content produced by such directives is fed directly into the paragraphs policy.
can be used inside programmatic directives
defined by the user to achieve the same behavior.
7.7. File management
Once projects get larger, it often becomes difficult to manage everything in a single file. Also, tooling may benefit from having separate files. For example, keeping separate SVG files or CSS files may have better IDE support than writing these out directly inside of COWEL.
COWEL provides directives to load content from other files.
7.7.1. \cowel_include
— Include a sub-document
The
directive loads the content from another COWEL document,
and processes it using the current content policy.
The path to the document is provided as content to
,
and is assumed to be relative to the current file.
All arguments are ignored.
If the current content policy is a paragraphs policy (§5.1. Content policies),
paragraph splitting of the included sub-document takes place
as if its contents were expanded directly where
appears.
In other words,
inherits the paragraph context,
or is not a "black box" to paragraph splitting.
When using
,
the contents of the other file are substituted where we have written
,
which means that imported content also plays nicely with paragraph splitting:
Generated HTML:
them when needed.
This can help you avoid copying boilerplate between multiple documents.
It is also common to split documents into multiple files that are combined using a sequence
of
s.
7.7.2. \cowel_include_text
— Include text from a file
cowel_include_text(){...}
The
directive reads the UTF-8 text contents of another file
and feeds that text into the current content policy.
The path to the document is provided as content to
,
and is assumed to be relative to the current file.
block to use it as a script,
or we can include it into a
to display its contents.
Assuming that
and
are similar,
there are some stark differences:
-
is used for COWEL documents, while\cowel_include
is used for anything else.\cowel_include_text -
doesn't just load the text from another file, but parses it and ensures that the contents are a valid COWEL document.\cowel_include -
feeds content from another document piece by pice into the current content policy.\cowel_include
reads text and feeds it all in a single block to the content policy.\cowel_include_text
7.8. Aliases and macros
7.8.1. \cowel_alias
— Define aliases for an existing directive
cowel_alias( names: pack string, ){...}
The
directive defines one or more aliases for an existing directive.
The content of
is converted to text,
and must be the name of an existing directive or directive alias.
Each positional argument is converted to text,
and results in the definition of a new directive alias.
After processing
,
the target can also be invoked using the alias name.
A fatal error is raised if
- generation of the alias or target names is erroneous,
- the target name or any of the alias names are empty,
- the target name or any of the alias names are not valid directive names,
- the target was not found, or
- an alias name matches the name of an existing macro or alias.
7.8.2. \cowel_macro
— Define a macro
cowel_macro( names: pack string, ){...}
The
directive defines a block of content which
can be processed at a later point in the document.
The provided content is not processed, but remembered.
Each positional argument is converted to text,
and results in the definition of a new macro.
After processing
,
the target can also be invoked using the macro name.
Named arguments are ignored.
A fatal error occurs if
- generation of the alias or target names is erroneous,
- any macro name is not a valid directive name (this includes empty names), or
- a macro name matches the name of an existing macro or alias.
Generated HTML:
When a macro is processed,
the behavior is as if
(§7.6.5.
— Activate paragraph splitting inside a directive)
was invoked immediately before processing the content in the macro definition.
This means that blank lines in the macro definition
may also result in paragraph splits outside the macro.
7.8.3. \cowel_put
— Process provided macro content or arguments
cowel_put( else: lazy any, ){...}
The
directive processes content
which was provided when a macro was invoked.
The content provided to
is converted to text,
and designates
- if that text is empty, the provided macro content;
- otherwise, if that text expands to only ASCII digits, the provided positional macro argument at the index obtained by parsing the digits (counting starts at zero);
- otherwise, if there exists a named macro argument whose name matches the target text, that argument;
- otherwise, nothing.
has the following effect:
- If any content is designated, the designated content is processed.
-
Otherwise, if an argument matches the
parameter, the content within theelse parameter is processed.else - Otherwise, an error is raised.
Generated HTML:
The behavior is erroneous if
is not expanded from a macro,
such as when
appears at a top-level in the document.
is not processed in any special way,
meaning that it cannot be used for "macro substitution" directly:
Generated HTML:
However,
accesses the inputs to the macro invocation
which expands
:
This results in a fatal error because when
is processed,
the
in the macro definition
expands to the top-level
.
That
in
is not expanded from any macro.
This functionality is implemented by tracking the "stack frame"
where content was expanded from (or none, in the case of the document top level).
This also makes it possible to deeply nest
within other directives while still referring to parameters of the macro invocation:
with the same input multiple times
results in multiple processing of the same provided content.
Sometimes this is useful,
but it can have unintended side effects:
7.9. Invocations
7.9.1. \cowel_invoke
— Invoke a directive
cowel_invoke( name: string, ){...}
The
directive invokes a directive by name.
This process is called a dynamic invocation.
Most invocations are static invocations.
The name of the invoked directive is provided as the first positional argument.
All other arguments are ignored.
The content provided to
is the content provided to the invoked directive.
can be invoked statically or dynamically:
works in the future,
argument forwarding is not supported at all right now.
8. Legacy directives
The documentation for these directives is not actively maintained.
8.1. Comments
In addition to the
syntax for single-line comments,
there exists a
directive which
discards all of its contents.
This can be used for multi-line comments.
8.1.1. \comment
— Comments
The
directive does not process its arguments or content.
It outputs no plaintext or HTML.
Generated HTML:
8.2. Text formatting
COWEL allows for basic text formatting using various directives. Many of the formatting directives are some direct equivalent of an HTML element. For these, there is a fixed HTML element that will always be used. You can rely on this when adding custom CSS.
Directive | HTML | Renders as |
---|---|---|
|
|
Bold text |
|
|
Name of cited work |
|
|
|
|
|
Definition |
|
|
Emphasized text |
|
unspecified | |
|
|
Italic text |
|
|
Inserted text |
|
|
Ctrl + Keyboard key |
|
|
Marked/highlighted |
|
unspecified | Oblique text |
|
|
Quoted text |
|
|
|
|
|
Sample output |
|
unspecified | |
|
unspecified | |
|
|
Small text |
|
|
(No change in formatting) |
|
|
Subscript |
|
|
Superscript |
|
|
Strong text |
|
unspecified | |
|
|
Variable name |
|
|
Underlined text |
All such formatting directives convert all named arguments directly into HTML attributes.
,
,
and
are all italic.
Both
and
are bold.
Both
and
use teletype font.
However, you can customize the style; see §8.12.3.
— CSS blocks.
) and italic (
) text
is that oblique text is merely slanted,
while italic text is fundamentally a different font with different characters.
8.3. Code and syntax highlighting
COWEL uses µlight for syntax highlighting. While the set of supported language is relatively small, the highlighter is ultra-light, extremely fast, and deals with modern C++ features correctly.
8.3.1. \code
— Inline code
The
directive produced syntax-highlighted text in code font.
- Arguments
-
-
(plaintext) — the syntax highlighting language.lang -
(true/false) — whether to omitnested
tags.< code >
-
- Input content
-
The input to a
directive is a plaintext context. However, there are special rules for formatting directives and pure plaintext directives (see below).\code - HTML output
-
In an HTML context, the
takes the input source code, applies syntax highlighting, and outputs the result surrounded by\code
.< code > ...</ code > - Plaintext output
-
In a plaintext context,
simply outputs the input source code.\code - Display style
- Inline
This applies C++ syntax highlighting, and generates HTML.
The
tags are an implementation detail and may be subject to change.
8.3.1.1. Manual nested highlighting
The
tags are omitted,
which makes it suitable for nesting languages
within other
or
directives.
This renders as follows:
out . write_json ( " { "x" : 123 , "y" : true , "z" : null } " )
Note that by default,
you may often not even notice a visual difference between using the
elements
to have borders, background color, padding, and other such styling features.
8.3.1.2. Further advice on highlighting
directives directly is often too tedious,
so you'll likely want to define a macro to make this easier:
8.3.2. \codeblock
— Code blocks
The
directive works exactly like
,
but it is a block directive, not an inline directive.
Additionally, code blocks render using borders and a dark background by default.
This can be controlled using the
This renders as:
8.3.3. \hl
— Syntax highlight override
The
directive forces certain syntax highlighting to be applied to some text;
it is a manual override for when automatic syntax highlighting is insufficient or broken.
It displays as inline content and wraps its content (which is an HTML context)
in the appropriate syntax highlighting tags.
It has a single
.
The long name is the enumerator name without the
This generates the HTML (subject to change):
It renders as
.
,
the "short names" (kw_type
) are not stable, i.e. they are more likely to change.
Only µlight long names should be used directly.
8.3.4. \pre
— Preformatted blocks
The
directive contains pre-formatted content.
It can be used to contain code, however, there is no syntax highlighting in a
block.
This renders as:
Hello, world! ============= a b c
,
currently does not support the
8.3.5. \literally
— Treat input literally as text
The
directive treats its input source code as plain text,
even if it contains directives or escape sequences.
It outputs the given input source code as text.
Its content is an unprocessed context, and it takes no arguments.
This renders as:
\: Even comments are preserved! This \comment{comment} \{ is taken literally \}!
pseudo-directives in macros are still processed,
even inside
blocks
because
replaces any appearances of
with the given content,
disregarding the semantics of any directives nested within.
8.3.6. \unprocessed
— Suppress directive processing
The
directive works just like
,
except that escape sequences are processed into their escaped characters.
This renders as:
This \comment{comment} { is unprocessed }!
and (to a lesser extent)
are very useful for nesting
code inside COWEL that already contains underscores.
For example,
is an escape sequence for newline characters in many languages,
and it may be annoying if it gets interpreted as an
directive:
This renders as:
Notice that COWEL technically parses a
directive instead of just
,
which is the part that turns into a newline escape sequence in the C++ code block.
However, that is ultimately irrelevant for syntax highlighting
because the source characters of
are taken as text,
and then split up according to C++ syntax.
pseudo-directives in macros are still processed,
even inside
blocks
because
replaces any appearances of
with the given content,
disregarding the semantics of any directives nested within.
8.4. Math
In recent years, browser support for MathML within HTML has become widespread. COWEL relies entirely on the browser for properly rendering math as MathML, which is very simple and lightweight, but not as portable as "baking" the math into an SVG.
:
This renders as:
You can also keep the MathML separate within an XML document
and use
:
However, hand-writing MathML would be extremely tedious and verbose, so COWEL offers some convenience directives, listed below.
8.4.1. \math
— Inline math
A
directive surrounds its content with
tags,
and displays as inline content.
Its content is an HTML context,
and within it, additional pseudo-directives like
or
corresponding to MathML elements can be used.
Essentially, this allows you to build MathML using COWEL syntax.
See Mozilla's MathML elements reference for a list of supported elements/directives.
This renders as:
8.4.2. \mathblock
— Math blocks
The
directive functions almost exactly as the
directive,
but it displays as block content instead of inline content,
and it produces an opening
tag.
8.5. Separators and word breaking
8.5.1. \br
— Break line
The
directive produces a line break,
and corresponds to the HTML element
.
It displays as inline content, and its input content is ignored.
is particularly useful when line breaks are treated same as spaces,
which is the case in most HTML content.
8.5.2. \hr
— Horizontal rule
The
directive produces a horizontal rule,
and corresponds to the HTML element
.
It displays as block content, and its input content is ignored.
Here is an example:
8.5.3. \wbr
— Word break opportunity
The
directive produces a word break opportunity,
and corresponds to the HTML element
.
It displays as inline content, and its input content is ignored.
elements can be inserted into the middle of long words,
which, if they don't fit on one line,
will be broken at the point of the
element
(without a hyphen at the end of the line).
Since µlight only supports UTF-8 output,
is equivalent to
,
which outputs a U+200B ZERO-WIDTH SPACE code point.
or
to output a U+00AD SOFT HYPHEN.
8.5.4. \nobr
— Unbroken words
The
directive is a formatting directive
which prevents word breaks within its content.
Its content is an HTML context.
This is done by applying a
style its content.
Combined
,\ c { nbsp} WordCombined
, or\ N { NO-BREAK SPACE} WordCombined
.\ U { A0} Word
8.6. Special blocks
Often, the content we write falls into some special category like "example", "note", etc. COWEL supports a large number of special block directives, which wrap their content in a block, with background color, borders, etc.
The input to all special block directives is an HTML context, they all convert their arguments to HTML attributes, and they all display as block content.
8.6.1. \Babstract
— Abstract blocks
8.6.2. \Bquote
— Quote blocks
The
directive directly corresponds to the
element.
Quotes blocks or "block quotes" display quoted text.
8.6.3. \blockquote
— Alias for \Bquote
The
directive is equivalent to the
directive.
8.6.4. \Bug
— Bug blocks
8.6.5. \Bdecision
— Decision blocks
8.6.6. \Bdel
— Deletion blocks
A deletion block acts as a wrapper for a large amount of deleted content.
It is typically used when individual
directives would be too tedious to use.
8.6.7. \Bdetails
— Details blocks aka spoilers
The
directive directly corresponds to the
element.
Within
,
the
directive can be used to specify summary text.
This is a summary. Click to open!
A details block contains details which need to be revealed by the user. This is also referred to as "spoiler".8.6.8. \details
— Alias for \Bdetails
The
directive is equivalent to the
directive.
8.6.9. \Bdiff
— Difference blocks
A difference block contains changes,
where some content within is typically deleted or inserted.
8.6.10. \Bex
— Example blocks
8.6.11. \Bins
— Insertion blocks
A deletion block acts as a wrapper for a large amount of inserted content.
It is typically used when individual
directives would be too tedious to use.
8.6.12. \Bimp
— Important blocks
8.6.13. \Bnote
— Note blocks
8.6.14. \Btip
— Tip blocks
8.6.15. \Btodo
— TODO blocks
8.6.16. \Bwarn
— Warning blocks
8.7. Lists
8.7.1. \ul
— Unordered lists
The
directive corresponds to the
element,
and produces an unordered list.
8.7.2. \ol
— Ordered lists
The
directive corresponds to the
element,
and produces an ordered list.
8.7.3. \li
— List items
The
directive corresponds to the
element,
and produces a list item with
or
.
This renders as:
- first bullet
- second bullet
- first bullet
- second bullet
8.7.4. \item
— List item pseudo-directive
Within
and
,
the
pseudo-directive can also be used instead of
.
8.7.5. \dl
— Definition lists
The
directive corresponds to the
element,
and produces a definition list.
Within that list, you can use
for definition terms, and\dt
for definition descriptions.\dd
8.8. Tables
Tables are simply produced by using the
,
,
,
,
,
,
,
,
,
and
directives to
produce the corresponding HTML tags with the same name.
directive.
8.9. Headings
Headings can be produced using the
,
,
,
,
, and
directives
to produce the corresponding HTML tags with the same name.
Headings take a
— Make table of contents) automatically.
Headings also take a
Other arguments to these headings are converted into attributes of the corresponding HTML element.
An
If none is provided, an
directive:
8.9.1. \make_contents
— Make table of contents
The
directive generates the table of contents,
which is comprised of all the headings within the document.
It takes no arguments and its content is ignored.
It displays as a block.
The table of contents is is populated by headings (§8.9. Headings) as the document is processed.
A similar effect can be achieved using
(§7.3.1.
— HTML element).
However, using
will also not emit a link icon in the gutter,
and it will not synthesize an
.
additionally wraps those contents in HTML elements to
chang their visual appearance.
8.10. Bibliography
In technical writing it is common for documents to reference other papers, and it is expected that references are properly cited. To support this,
COWEL provides directives for adding bibliography entries, and for generating a bibliography automatically.
8.10.1. \bib
— Add bibliography entry
The
directive adds a single entry to the bibliography.
Its content is ignored, and it displays as a meta directive.
It has a number of parameters, each of which is a plaintext context:
id -
The identifier of the bibliography entry.
This can later be referenced using
.\ ref ( id) author - The name of the author(s). This is in no particular format, and if you want to provide multiple authors, you can do so via a comma-separated list here.
title - The title of the cited work.
date - The date of publication. No particular format is enforced; this is simply a string, so you can choose some local format.
publisher - The name of the publisher.
link -
The primary link to the document.
This should typically be a short link because it is copied into each
to the bibliography entry.\ref long-link -
A "long link" to the document.
If present, this will be rendered within the bibliography,
and it is typically meant to be a semantic or more stable link than the
. You can also think of it as a "link for pretty printing".link issue-link - A link to issue tracking for the document. For example, in WG21 circles, this may be a link to the GitHub issue where a paper is tracked.
Every argument except the
8.10.2. \make_bib
— Generate bibliography
The
directive generates a bibliography.
This is typically done towards the bottom of the document, but can be done anywhere.
It takes no arguments, its content is ignored, and it displays as a block.
The
directive is populated by uses of
directives in order of use.
That is, the bibliography is not automatically sorted for you;
the order in which
directives are used is also the order in which the bibliography
entries are generated.
,
it is a wrapper for the underlying
8.11. References
8.11.1. \ref
— References
The
directive takes a single
tag with some content inside.
The content is an HTML context, and is what actually gets displayed. If no content is provided, it can be synthesized from the following types of references:
mailto URLs (e-mail addresses)tel URLs (telephone numbers)http andhttps URLs- Anchors (
#id ) for some heading in the document - Anything defined in the bibliography using
\bib
HTML output (
tag may have additional attributes):
This renders as:
8.11.2. \mail
— E-Mail addresses
A
directive behaves the same
directive that is given a
8.11.3. \tel
— Telephone numbers
A
directive behaves the same
directive that is given a
8.12. Foreign languages
8.12.1. \script
— JavaScript blocks
The content of a
directive is a plaintext context,
where the input is treated as JavaScript code
and surrounded in
tags.
displays as meta content (like
).
Generated HTML:
8.12.2. \noscript
— No-JavaScript content
The
directive corresponds to the
element.
Its content is an HTML context,
and will only be shown by the browser when JavaScript is disabled.
8.12.3. \style
— CSS blocks
The content of a
directive is a plaintext context,
where the input is treated as JavaScript code and surrounded in
tags.
displays as meta content (like
).
Generated HTML:
8.13. Sections
Often, you want to produce content in one place,
but have it display in another place within the document.
A classic example is collecting headings automatically in a table of contents,
or copying the content of a heading into a preview when referenced by
.
8.13.1. \there
— Append content to section
The
directive displays as meta content.
Basically, it stashes away its input content (which is an HTML context) somewhere else.
It takes a single
By default, all document content is placed within a
element,
inside
, inside html
.
allows you to write outside of the
element:
-
will write\ there ( std.head) { text} text
inside of the
element (following auto-generated content).< head > -
will write\ there ( std.body) { text} text
inside of the
element (following< body >
and other automatically inserted elements).< main >
8.13.2. \here
— Copy section content
The
directive inserts the content from another section at its location.
It displays as inline content.
It takes a single
All references produced by
are resolved in a post-processing step,
which allows forward-references.
Generated HTML:
8.13.3. \hereblock
— Copy section content in block
The
directive functions exactly like the
directive,
but displays as block content instead of inline content.
8.14. Miscellaneous
8.14.1. \div
— Content division
The
directive surrounds its contents in
tags.
It displays as a block, and its content is an HTML context.
's named arguments are turned into HTML attributes.
8.14.2. \trim
— Trim input
The content of a
directive is an HTML context
(§5.1. Content policies).
Its arguments are ignored.
is a formatting directive.
The process of trimming eliminates leading and trailing whitespace in the input, at the COWEL source level.
This renders as:
is primarily useful inside of macros.
We might not want to space-separate content if some of it is empty.
For example, we could define a
macro
where the user can optionally provide a number for that note:
This renders as:
Note: Something something.
Note 1: Something else.
Notice that because
expands to no content,
the trailing space after Note
is eliminated.
If it wasn't eliminated, we would end up with
,
but there should never be a space before the colon.
8.14.3. \text
— Plaintext context
The content of a
directive is a plaintext context
(§5.1. Content policies).
Its arguments are ignored.
It simply outputs the input that it was given as text.
Therefore, it acts as a sort of wrapper for plaintext.
Notably, this forces the generation of plaintext even when
is within an HTML context.
8.14.4. \p
— Paragraphs
The
directive surrounds its content in
tags.
8.15. Variables and calculations
While COWEL is not intended to be general purpose programming language, and more advanced interactive features are better suited for JavaScript, it does provide a few ways to perform calculations.
8.15.1. \Vset
— Set a variable
sets the value of a variable to some provided plaintext.
It displays as a meta directive.
It takes a single
This renders as:
8.15.2. \Vget
— Get a variable
obtains the value of a variable,
and displays as inline.
Its content is ignored.
It takes a single
If the variable denoted by the
expands to nothing.
8.15.3. \Cadd
— Perform addition
The
directive performs an integer addition between its (nameless) arguments.
Its content is ignored, and it displays as inline.
Each of its arguments is a plaintext context, where the argument is interpreted as an integer, and then summed.
This renders as:
with
and
to store the results
of your calculations:
This renders as:
Paragraph 1
Paragraph 2
and other calculation directives are mainly intended
for incrementing paragraph numbers and other basic tasks.
8.15.4. \Csub
— Perform subtraction
The
directive behaves like the
directive,
except that it performs subtraction instead of addition.
8.15.5. \Cmul
— Perform multiplication
The
directive behaves like the
directive,
except that it performs multiplication instead of addition.
8.15.6. \Cdiv
— Perform division
The
directive behaves like the
directive,
except that it performs division instead of addition.