Compact Web Language (COWEL)

github.com/eisenwave/cowel

Contents

1

Introduction

2

Motivation

3

Getting started

3.1

Native installation

4

Syntax

4.1

EBNF grammar

4.2

Text

4.2.1

Whitespace

4.3

Escape sequences

4.4

Comments

4.5

Directives splices

4.5.1

Directive names

4.5.2

Directive arguments

4.5.2.1
Named arguments
4.5.2.2
Positional arguments
4.5.2.3
Ellipses
4.5.2.4
Groups
4.5.3

Directive content

5

Document processing

5.1

Content policies

5.2

Directive processing

5.2.1

Lazy processing

6

Types

6.1

General principles

6.2

Basic types

6.2.1

any — Top type

6.2.2

nothing — Bottom type

6.2.3

unit — Unit type

6.2.4

null — Null type

6.2.5

bool — Boolean type

6.2.6

int — Integer

6.2.7

f32 — 32-bit floating-point number

6.2.8

f64 — 64-bit floating-point number

6.2.9

str — String

6.2.10

block — Block

6.3

Compound types

6.3.1

group — Product type

6.3.2

named — Named group member

6.3.3

pack — Variadic pack of group members

6.3.4

lazy

6.3.5

Union

6.3.5.1
Shorthand notation for optional types (?)
6.4

Splicing

7

Themes

8

New directives

8.1

Common principles

8.1.1

Parameter notation

8.1.2

Usual argument matching

8.2

Character utilities

8.2.1

\cowel_char_by_entity — Character by HTML character reference

8.2.2

\cowel_char_by_name — Character by Unicode name

8.2.3

\cowel_char_by_num — Character by code point number

8.2.4

\cowel_char_get_num — Get digits of character

8.3

HTML utilities

8.3.1

\cowel_html_element — HTML element

8.3.2

\cowel_html_self_closing_element — Self-closing HTML element

8.4

Content policies

8.4.1

\cowel_to_html — Process with to-HTML policy

8.4.2

\cowel_no_invoke — Process with no-invoke policy

8.4.3

\cowel_actions — Process with actions policy

8.4.4

\cowel_text_only — Process with text-only policy

8.4.5

\cowel_text_as_html — Process with text-as-HTML policy

8.4.6

\cowel_source_as_text — Process with source-as-text policy

8.5

Syntax highlighting

8.5.1

\cowel_highlight — Perform syntax highlighting

8.5.2

\cowel_highlight_as — Syntax highlight override

8.5.3

\cowel_highlight_phantom — Syntax highlight phantom text

8.6

Paragraph control

8.6.1

Paragraph splitting

8.6.2

\cowel_paragraphs — Perform paragraph splitting

8.6.3

\cowel_paragraph_enter — Enter a paragraph

8.6.4

\cowel_paragraph_leave — Leave a paragraph

8.6.5

\cowel_paragraph_inherit — Activate paragraph splitting inside a directive

8.7

File management

8.7.1

\cowel_include — Include a sub-document

8.7.2

\cowel_include_text — Include text from a file

8.8

Aliases and macros

8.8.1

\cowel_alias — Define aliases for an existing directive

8.8.2

\cowel_macro — Define a macro

8.8.3

\cowel_put — Process provided macro content or arguments

8.9

Invocations

8.9.1

\cowel_invoke — Invoke a directive

9

Legacy directives

9.1

Comments

9.1.1

\comment — Comments

9.2

Text formatting

9.3

Code and syntax highlighting

9.3.1

\code — Inline code

9.3.1.1
Manual nested highlighting
9.3.1.2
Further advice on highlighting
9.3.2

\codeblock — Code blocks

9.3.3

\hl — Syntax highlight override

9.3.4

\pre — Preformatted blocks

9.3.5

\literally — Treat input literally as text

9.3.6

\unprocessed — Suppress directive processing

9.4

Math

9.4.1

\math — Inline math

9.4.2

\mathblock — Math blocks

9.5

Separators and word breaking

9.5.1

\br — Break line

9.5.2

\hr — Horizontal rule

9.5.3

\wbr — Word break opportunity

9.5.4

\nobr — Unbroken words

9.6

Special blocks

9.6.1

\Babstract — Abstract blocks

9.6.2

\Bquote — Quote blocks

9.6.3

\blockquote — Alias for \Bquote

9.6.4

\Bug — Bug blocks

9.6.5

\Bdecision — Decision blocks

9.6.6

\Bdel — Deletion blocks

9.6.7

\Bdetails — Details blocks aka spoilers

9.6.8

\details — Alias for \Bdetails

9.6.9

\Bdiff — Difference blocks

9.6.10

\Bex — Example blocks

9.6.11

\Bins — Insertion blocks

9.6.12

\Bimp — Important blocks

9.6.13

\Bnote — Note blocks

9.6.14

\Btip — Tip blocks

9.6.15

\Btodo — TODO blocks

9.6.16

\Bwarn — Warning blocks

9.7

Lists

9.7.1

\ul — Unordered lists

9.7.2

\ol — Ordered lists

9.7.3

\li — List items

9.7.4

\item — List item pseudo-directive

9.7.5

\dl — Definition lists

9.8

Tables

9.9

Headings

9.9.1

\make_contents — Make table of contents

9.10

Bibliography

9.10.1

\bib — Add bibliography entry

9.10.2

\make_bib — Generate bibliography

9.11

References

9.11.1

\ref — References

9.11.2

\mail — E-Mail addresses

9.11.3

\tel — Telephone numbers

9.12

Foreign languages

9.12.1

\script — JavaScript blocks

9.12.2

\noscript — No-JavaScript content

9.12.3

\style — CSS blocks

9.13

Sections

9.13.1

\there — Append content to section

9.13.2

\here — Copy section content

9.13.3

\hereblock — Copy section content in block

9.14

Miscellaneous

9.14.1

\div — Content division

9.14.2

\trim — Trim input

9.14.3

\text — Plaintext context

9.14.4

\p — Paragraphs

9.15

Variables and calculations

9.15.1

\Vset — Set a variable

9.15.2

\Vget — Get a variable

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.

The following COWEL code ...

Hello, \strong{strong} world!

... generates the HTML ...

Hello, <strong>strong</strong> world!

... which renders as:

Hello, strong world!

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 npm. With npm installed, open a terminal and run:

npm i -g cowel # or npm install --global cowel

See also https://www.npmjs.com/package/cowel. With COWEL installed, you can convert COWEL documents to HTML by using:

cowel run input.cow output.html

To see a list of available options and commands, run cowel by itself or cowel --help.

You may need to use sudo or otherwise elevate your permissions because -g performs a "global"/system-wide installation. This is necessary to make the cowel command available everywhere.

It is recommended to use a .cow or .cowel file extension for COWEL documents.

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:

git clone https://github.com/Eisenwave/cowel.git --recursive cd cowel cmake -B build cmake --build build ./build/cowel-cli input.cow output.html

The npm CLI is slightly different from the native CLI, but they share some options, such as --severity and --help. Running ./build/cowel-cli 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:

4.1. EBNF grammar

Formally, in EBNF grammar format, a document is constructed as follows:

document = { document-markup-element }; document-markup-element = document-text | common-markup-element; document-text = document-text-char, { document-text-char }; document-text-char = ? Any character ? - "\"; common-markup-element = escape | comment | directive-splice; escape = "\", escapable-char | "\", line-terminator; escapable-char = "{" | "}" | "[" | "]" | "(" | ")" | "," | "." | "=" | "!" | '"' | "#" | "$" | "%" | "&" | "'" | "*" | "+" | "/" | ";" | "<" | ">" | "?" | "@" | "^" | "|" | "~" | "-" | " " | TAB | VT ; comment = "\:", { comment-char }, line-terminator; comment-char = ? Any character ? - line-terminator; directive-splice = "\", directive-name, [ group ], [ block ]; directive-name = directive-name-char - digit, { directive-name-char }; directive-name-char = "_" | digit | ? ASCII alphabetic character ?; digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"; group = "(", blank, [ group-member-list ], blank, ")"; group-member-list = group-member, { blank, ",", blank, group-member }, blank, [ "," ]; group-member = member-name, blank, "=", blank, member-value | member-value | "..."; member-name = member-name-char, { member-name-char }; member-name-char = ? HTML attribute name ? - ("\" | "(" | ")" | "{", "}" | ","); member-value = directive-call | primary-value; directive-call = directive-name, blank, group, [ blank, block ] | directive-name, blank, block; primary-value = unit-literal | null-literal | boolean-literal | integer-literal | unquoted-string | quoted-string | group | block; unit-literal = "unit"; null-literal = "null"; boolean-literal = "true" | "false"; integer-literal = [ "-" ], digit, { digit }; unquoted-string = unquoted-string-char, { unquoted-string-char }; unquoted-string-char = directive-name-char | "-"; quoted-string = '"', { quoted-string-markup-element }, '"'; quoted-string-markup-element = quoted-string-text | common-markup-element; quoted-string-text = quoted-string-text-char, { quoted-string-text-char }; quoted-string-text-char = ? Any character ? - ("\" | '"'); block = "{", { block-markup-element }, "}"; block-markup-element = block-text | common-markup-element; block-text = block-text-char, { block-text-char } (* brace-balanced *); block-text-char = ? Any character ? - "\"; blank = { comment | whitespace }; whitespace = { " " | TAB | LF | CR | VT }; line-terminator = LF | CR, LF | CR (* unless the next character is LF *); TAB = ? U+0009 CHARACTER TABULATION ? (* \t in C *); LF = ? U+000A END OF LINE ? (* \n in C *); CR = ? U+000D CARRIAGE RETURN ? (* \r in C *); VT = ? U+000B LINE TABULATION ? (* \v in C *);

At the top-level in the document, there are no other syntactical features, meaning that as long as some bit of code doesn't contain a U+005C (\), it's all interpreted as plaintext. This makes COWEL exceptionally suited to nest other languages inside of it in code blocks etc.

4.2. Text

Text (such as document-text in the grammar) is a markup element which consists of as many characters as possible, excluding U+005C (\).

document-text = document-text-char, { document-text-char }; document-text-char = ? Any character ? - "\";

In most situations, text is not processed specially. However, the output may depend on the context (§5.1. Content policies). For example, < in text will render as a < character, but will be converted to &lt; 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 <pre> elements) or to have it merged into spaces, which happens by default.

At the document top-level, §8.6.1. Paragraph splitting takes place.

COWEL markup:

This displays on one line because line breaks render like spaces.

Generated HTML:

<p>This displays on one line because line breaks render like spaces.</p>

Rendered output:

This displays on one line because line breaks render like spaces.

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.
\!, \#, \$, \%, \&, \', \(, \), \*, \+, \,, \-, \., \/, \;, \<, \= \>, \?, \@, \[, \], \^, \|, \~, \ U+0009 CHARACTER TABULATION, \ U+0020 SPACE 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!
\ U+000A LINE FEED, \ U+000B VERTICAL TABULATION, \ U+000D CARRIAGE RETURN, \ U+000A U+000D (CRLF escape) Expands to nothing; feature is stable

In EBNF grammar, an escape is constructed like:

escape = "\", escapable-char | "\", line-terminator; escapable-char = "{" | "}" | "[" | "]" | "(" | ")" | "," | "." | "=" | "!" | '"' | "#" | "$" | "%" | "&" | "'" | "*" | "+" | "/" | ";" | "<" | ">" | "?" | "@" | "^" | "|" | "~" | "-" | " " | TAB | VT ; line-terminator = LF | CR, LF | CR (* unless the next character is LF *);

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 most escapes is to prevent a character from having special meaning. For example, the \, escape prevents a comma from being interpreted as a separator between directive arguments.

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.

Comments, just like any other content, are actually part of the AST and don't simply get discarded during parsing. This means that a comment wrapped in §8.4.6. \cowel_source_as_text — Process with source-as-text policy will render as expected:

\cowblock{\cowel_source_as_text{ \: A comment ... }}

This renders as:

\: A comment ...

In EBNF grammar, a comment is constructed as follows:

comment = "\:", { comment-char }, line-terminator; comment-char = ? Any character ? - line-terminator;

Comments include a line-terminator, which means that a trailing comment won't add any lines (not even blank lines) to the generated markup.

We can even join words by putting a comment between:

Hello\: this comment will absorb the newline World Hello \: this comment also does, but is preceded by a space World

Generated HTML:

HelloWorld Hello World

4.5. Directives splices

A directive is a way of generating plaintext, HTML, both, or neither. You can think of it as a "command" or "function call".

Splicing means to evaluate a directive (or something else, in the future) and to insert the result between the surrounding markup elements. Splicing consists of three steps:

  1. Looking up the name of the spliced directive.
  2. Evaluating the directive (and its arguments, if any). Evaluation of the directive usually produces a result. This may not happen when evaluation raises an error.
  3. Feeding the result into the current content policy (§5.1. Content policies).

COWEL markup:

1 + 2 + 3 = \cowel_add(1, 2, 3)

Generated HTML:

1 + 2 + 3 = 6

As explained, this markup is processed in three steps:

  1. \cowel_add is looked up by name. This succeeds because \cowel_add is a builtin directive.
  2. The three arguments (of type int) to \cowel_add are evaluated, and \cowel_add itself is evaluated, which produces a value 6 of type int.
  3. The resulting value 6 is fed as plaintext into the surrounding content policy, which usually results in a single U+0036 (6) character being output.

Every directive has three parts:

In EBNF grammar, a directive-splice is constructed as follows:

directive-splice = "\", directive-name, [ group ], [ block ]; directive-name = directive-name-char - digit, { directive-name-char }; directive-name-char = "_" | digit | ? ASCII alphabetic character ?;

4.5.1. Directive names

A directive name selects a specific directive to be processed. The name begins with a U+005C (\) character, followed by a sequence of ASCII alphanumeric characters or U+005F (_). However, the first character after U+005C (\) cannot be an ASCII digit.

You can use an empty block of content to "cut a name short":

Thisisavery\wbr{}longword.

Doing so is equivalent to writing \wbr and longword immediately following one another.

4.5.2. Directive arguments

Grammatically, the arguments are a group, which is constructed as follows:

group = "(", blank, [ group-member-list ], blank, ")"; group-member-list = group-member, { blank, ",", blank, group-member }, blank, [ "," ]; group-member = member-name, blank, "=", blank, member-value | member-value | "...";

Directive arguments can be positional arguments, named arguments, or ellipses. Arguments are separated by commas. Unlike in the surrounding markup, whitespace and comments surrounding directive arguments (i.e. blank) are ignored.

Often, arguments are converted to HTML attributes.

\b(id = abc){Bold text.}

Generated HTML:

<b id=abc>Bold text.</b>
4.5.2.1. Named arguments

A named argument is a group-member 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 ("), U+0027 ('), U+002C (,), U+002F (/), U+003D (=), U+003E (>), U+005B ([), U+005C (\), U+005D (]), U+007B ({), U+007D (}), and noncharacters.

If you want to provide a positional argument that is name = value instead, you can do so by writing:

\: "name = value" as a positional argument \xyz("name = value") \: named argument with name "name" and value "value" \xyz(name = value)

Only the literal = character can be used for named arguments, not its escaped variant \=.

Grammatically, a member-name is constructed as follows:

member-name = member-name-char, { member-name-char }; member-name-char = ? HTML attribute name ? - ("" | "(" | ")" | "{", "}" | ",");
4.5.2.2. Positional arguments

A positional argument is a group-member of the form member-value.

Positional arguments are content just like any other content, except that an unbalanced closing U+005D (]) or a U+002C (,) ends the content.

4.5.2.3. Ellipses

An ellipsis argument is a group-member spelled .... Ellipsis arguments are placeholders which expand to arguments provided to a surrounding macro. See also §8.8.2. \cowel_macro — Define a macro and §8.8.3. \cowel_put — Process provided macro content or arguments.

COWEL markup:

\: Define a macro for generating <div> elements \cowel_macro(div){\cowel_html_element(div, attr = (...)){\cowel_put}} \div(id = abc){inner text}

Generated HTML:

<div id=abc>inner text</div>

Specifically, any positional argument which begins with ... (ignoring leading whitespace and comments) is considered an ellipsis. The text ... is not considered an ellipsis if it appears anywhere else or has preceding content within an argument.

An error is raised if an ellipsis is used as an argument outside of a macro expansion.

\m("...") \: OK, providing string "...", not an ellipsis \m(...) \: error: ellipsis is not expanded from a macro
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.

\d((x), (), (y,)) \: groups as positional arguments \d(n = (x, y)) \: group as named argument \d(((()))) \: nested empty groups

In the future, parentheses surrounding a single positional argument will be treated as (ignored) parentheses around an expression, like in typical programming languages.

For a group containing a single positional member, (x,) may also be used. That is, the trailing comma can only be used in a group, not in an expression, so it acts as a disambiguator.

4.5.3. Directive content

The directive content is the primary input to a directive. It is delimited by a '{' and ends with a matching closing '}'. This means that you can have opening and closing braces inside text, but they need to be balanced.

COWEL markup:

\b{Bold text { with braces }.}

Generated HTML:

<b>Bold text { with braces }.</b>

Escape sequences don't participate in this "brace matching", so they can be used to literally produce a brace character.

COWEL markup:

\b{Bold text \{ with brace.}

Generated HTML:

<b>Bold text { with brace.</b>

Unlike in the directive arguments, whitespace is not trimmed.

COWEL markup:

\b{bold} \i{ italic }

Generated HTML:

<b>bold</b> <i> italic </i>

Only one such block of content can be provided, unlike in TeX, which has a similar syntax, but permits multiple blocks. Each block is separated by a pair of braces.

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 §8.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.

In the COWEL snippet \b{x}, the \b directive feeds the current content policy with

Content policies differ in how they treat the content they're fed:

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:

function f(x) { console.log(x); } f(2 + 2);

f has no idea that its input was originally 2 + 2. It only sees the value 4 and prints it, "oblivious to the outside".

COWEL follows a different model:

\comment{\b{x}}

No <b> tag is ever generated because \b{x} is never processed. \comment 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 \comment2 directive that works just like \comment yourself:

\cowel_macro(comment2){}

6. Types

While most of the content a user writes tends to be in a markup context, some is written in a scripting context. For example, inside the group of a directive-splice.

A scripting context functions similarly to other programming languages, like JavaScript; there are values and types, which can be combined using expressions.

The capabilities of the scripting context are currently extremely limited, but should be expanded greatly in the near future.

type = prefix-type, { "|", prefix-type }; prefix-type = suffix-type | type-prefix, "(", type-list, ")" | type-prefix, prefixed-type; type-prefix = "group" | "pack" | "named" | "opt"; type-list = type, { ",", type }, [ "," ]; prefixed-type = prefixed-suffix-type | type-prefix, prefixed-type; suffix-type = optional-type, { "?" }; prefixed-suffix-type = basic-type, { "?" }; optional-type = basic-type | "(", type, ")"; basic-type = "any" | "nothing" | "unit" | "null" | "bool" | "int" | "f32" | "f64" | "str" | "block";

The commas in a *type-list* act as separators and have no impact on the type.

Note that the type `group(int)` is a unambigously a *prefix-type* where `int` is the only element in the *type-list*, not a `group` *type-prefix* followed by an `(int)` *optional-type*.

Also note that in `group(int)?`, the `?` forms an optional group, not a group of an optional `int`.

6.1. General principles

The process of converting any union type $U$ into its canonical form is called *canonicalization*. A type is in its *canonical* form if canonicalization leaves the type unchanged; otherwise it is in its *degenerate* form.

Two types are *equivalent* if they are identical after both are canonicalized. Equivalent types are semantically the same, but may be spelled differently.

For example, the degenerate union type `any | any` is equivalent to `any`.

6.2. Basic types

Basic types are the most simple building block of the type system. They cannot be broken down any further, although some basic types (namely `any` and `nothing` are symbolic types).

Canonicalization has no effect for basic types; they are always in their canonical form.

6.2.1. any — Top type

any is the root of the type hierarchy, i.e. every other type is a subtype of any. This is also known as a "top type".

any may be used as a type for parameters and variables, but there are no value of type any.

6.2.2. nothing — Bottom type

nothing is a type of which there are no values. This is also known as a "bottom type".

It is the type of expressions that terminate, i.e. don't return.

6.2.3. unit — Unit type

unit is a unit type, i.e. a type with only one possible value also spelled unit.

This is used as a result for directives that don't produce any other result.

6.2.4. null — Null type

null is a unit type with only one possible value also spelled null.

Unlike unit, null is used to indicate errors.

6.2.5. bool — Boolean type

bool is a boolean type. It can represent two values: true and false.

6.2.6. int — Integer

int is an integer. It can represent any integer value (although in practice, there is an implementation limit); this includes negative numbers.

An int can be obtained using integer literals such as 123 or 0xff.

6.2.7. f32 — 32-bit floating-point number

f32 is a single-precision floating-point number. That is, a number in binary32 format, as specified in IEEE-754.

There is no way to obtain a value of type f32 yet, but in the future, one can be obtained using floating-point literals such as 0f32.

6.2.8. f64 — 64-bit floating-point number

f32 is a single-precision floating-point number. That is, a number in binary64 format, as specified in IEEE-754.

There is no way to obtain a value of type f64 yet, but in the future, one can be obtained using floating-point literals such as 0f64 or 0.0.

That is, all floating-point literals have type `f64` unless a suffix was explicitly specified.

6.2.9. str — String

str is a UTF-8 encoded string.

A value of type str can be obtained using string literals such as "abc".

6.2.10. block — Block

block stores markup elements. It is very similar to str, but is evaluated lazily, meaning that it has no effect until spliced.

A value of type block can be obtained using block literals such as {abc}.

6.3. Compound types

Compound types are formed from other types, possibly from other compound types.

6.3.1. group — Product type

group combines other types, called its members, in sequence. This is also known as a product type.

For example group(int, string) is group containing an int followed by a string. A value of such a type can be obtained with the literal (0, "x").

Canonicalization of a group G is performed as follows:

  1. All members of G are canonicalized.
  2. If any member of G is nothing, G is nothing.

6.3.2. named — Named group member

named is a compound type only nestable in a group or pack.

For example, group named int is a group containing only a single int. A value of such a type can be obtained with the literal (x = 0).

Canonicalization of a named N is performed as follows:

  1. The nested type of N is canonicalized.
  2. If the nested type of N is nothing, N is nothing.

6.3.3. pack — Variadic pack of group members

pack is a compound type only nestable in a group. It indicates a variadic repetition of the same type.

For example, group pack int is a group containing any amount of ints. A value of such a type can be obtained with the literals

Canonicalization of a pack P is performed as follows:

  1. The nested type of P is canonicalized.
  2. If the nested type of P is nothing, P is nothing.

6.3.4. lazy

lazy is a lazily evaluated value. That is, when specified as a parameter of a directive, it only gets evaluated when actually needed by that directive.

Canonicalization of a lazy L is performed by canonicalizing its nested type.

6.3.5. Union

Unions can be formed by combining other types with |. They describe variables and parameters that can hold one of a fixed number of alternatives. However, a value cannot be of union type.

Alternatives of a union type are subtypes of that union type. Furthermore, a union type S is a subtype of a union type U if the set of alternatives of S is a subset of the alternatives of U.

For example, int | str is a union of int and str. int and str are subtypes of this union, so a value convertible to this union type can be obtained with either 0 or "x".

Canonicalization of a union U is performed as follows:

  1. Every alternative of U is canonicalized. U is converted to another union type where each alternative that is also a union is expanded or "flattened" into the top-level union. For example, int | (str | bool) is converted to int | str | bool.
  2. Any nothing alternatives are removed.
  3. The alternatives are sorted using an unspecified total order of types.
  4. Any duplicate alternatives are removed.
  5. If U now holds a single alternative, U is that alternative.
  6. If U now holds no alternatives, U is nothing.
  7. If any alternative of U is any, U is any.
6.3.5.1. Shorthand notation for optional types (?)

The type suffix ? forms a union of the given type and null.

int? is equivalent to int | null.

6.4. Splicing

Values can be spliced into strings and blocks. For example, "Hello, \d!" splices the result of the directive \d (with no arguments and no block provided) into a string, and {Hello, \d!} splices the result of \d into a block.

Splicing a directive always results in evaluation of that directive. For example, splicing \cowel_macro evaluates \cowel_macro, and its resulting unit is spliced (resulting in no produced text).

When a value is spliced, it is converted into plaintext. When splicing into strings, that plaintext simply becomes part of the string content. For blocks (which are always lazy-evaluated), splicing means that the resulting plaintext is fed into the current content policy once the block itself is spliced.

The effect of splicing depends on the type of value:

7. 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:

Forced light/dark mode works by adding a light or dark class to the <html> element in the DOM.

If you want to customize colors with CSS, remember to make them respond to theme and OS preference changes.

For reference, you can look at the CSS in the COWEL source code to see how it's done properly.

8. New directives

Find below a list of builtin directives. That is, directives that you can always use because they are "built into the language".

These builtin directives should rarely be used directly, but through macro packages which utilize them.

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.

8.1. Common principles

There are a few common principles, which all builtin directives have in common:

8.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 description of \cowel_html_element looks as follows:

cowel_html_element(
  name: str,
  attr: lazy(group pack named string)?,
){...}: block

Or equivalently:

cowel_html_element(
  name: string,
  attr: lazy(group(pack(named(string))))?,
){...}: block

This describes that \cowel_html_element can be invoked as follows, among various options:

\cowel_html_element(name = div, attr = (id = abc))

div matches the name parameter, and the content div is treated as a string value.

(id = abc) matches the attr parameter, and within that group, there is a single-element pack of named arguments of type string with lazy processing. lazy processing implies that even if we were to reverse the order of name and attr, name would still be processed first.

8.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.

\: OK, two positional arguments \cowel_html_element(div, (id = abc)) \: OK, two named arguments \cowel_html_element(name = div, attr = (id = abc)) \: OK, all positional arguments appear at the start \cowel_html_element(name = div, (id = abc)) \: error: positional argument following named arguments \cowel_html_element(name = div, (id = abc))

The usual argument matching is performed as follows:

  1. Positional arguments match parameters in the same order. An error is raised if there are more positional arguments than parameters.
  2. The following named arguments match parameters with the same name. An error is raised if a named argument does not match any parameter.
  3. 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.

Let \d be a directive with parameters x, y, and z:

\: In each of these calls, \: a, b, and c match x, y, and z, respectively: \d(z = c, y = b, x = a) \: OK, all named arguments \d(a, b, c) \: OK, all positional arguments \d(a, z = c, y = b) \: OK, positional arguments followed by named arguments

The usual argument matching is essentially identical to function calls in Kotlin, but more restrictive when it comes to mixing positional and named arguments.

8.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.

8.2.1. \cowel_char_by_entity — Character by HTML character reference

cowel_char_by_entity(){...}: str

The \cowel_char_by_entity directive takes the name of a character and outputs the respective code points as text. The input to a \c directive is provided as content, which consists of an HTML entity without the leading '&' and trailing ';'. All arguments are ignored.

The '&' character can be produced in a number of ways:

8.2.2. \cowel_char_by_name — Character by Unicode name

cowel_char_by_name(){...}: str

The input to a \cowel_char_by_num 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.

\N{DIGIT ZERO} generates '0' U+0030 DIGIT ZERO.

8.2.3. \cowel_char_by_num — Character by code point number

cowel_char_by_num(){...}: str

The input to a \cowel_char_by_num 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.

\U{30} generates '0' U+0030 DIGIT ZERO.

Use of \cowel_char_by_name can lead to much more descriptive, human-friendly code, compared to \cowel_char_by_num.

The main issue with \cowel_char_by_num 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.

8.2.4. \cowel_char_get_num — Get digits of character

cowel_char_get_num(
  zfill: bool = 0,
  base: int = 16,
  lower: bool = false,
){...}: block

The \cowel_char_get_num directive is essentially the inverse of the \cowel_char_by_num 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:

zfill
The minimum amount of digits that should be produced. This is an integer argument in range [0, 1024], and defaults to zero. If the amount of digits is less than zfill, it will be left-padded with additional '0' characters.
base
The base of the output digit sequence, in range [2, 16]. This defaults to 16, meaning that the digits are printed in hexadecimal.
lower
A yes/no plaintext argument, defaulting to no. If yes is specified, digits beyond '9' (i.e. 'A' to 'F') will be output in lower case instead.

COWEL markup:

U+\cowel_char_get_num(4){x}

This renders as:

U+0078

Note that U+0078 is the usual way in which Unicode code points are represented. That is, U+, followed by at least four hexadecimal digits. It is also possible to define a macro if we need this frequently:

\cowel_macro(code_point){U+\cowel_char_get_num{\cowel_put}} \code_point{x}

\cowel_char_get_num can also be combined with \cowel_char_by_name to produce human-readable descriptions of code points, while also keeping our source code readable:

\macro(named_char){U+\cowel_char_get_num(4){\N{\put}} \cowel_put} \named_char{SECTION SIGN}

This renders as:

U+00A7 SECTION SIGN

\cowel_char_get_num uses only the first code point within the input text, even though the entire input text is processed into plaintext.

If we provide more than a single code point, some input is discarded:

\cowel_char_get_num{abc}

This renders as

61

... which corresponds to a, whereas b and c are discarded.

8.3. HTML utilities

8.3.1. \cowel_html_element — HTML element

cowel_html_element(
  name: string,
  attr: lazy(group pack named string)?,
){...}: block

The \cowel_html_element directive generates content, surrounded in HTML opening and closing HTML tags. That is, it

The name of the HTML element is contained in the name parameter, and the attributes within the HTML element are contained within the attr parameter.

COWEL markup:

This is \cowel_html_element(span, (id = abc)){a span}.

Generated HTML:

This is <span id=abc>a span</span>.

A \cowel_html_element 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.

8.3.2. \cowel_html_self_closing_element — Self-closing HTML element

cowel_html_self_closing_element(
  name: string,
  attr: lazy(group pack named string)?,
): block

The \cowel_html_self_closing_element 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 name parameter, and the attributes within the HTML element are contained within the attr parameter.

COWEL markup:

Horizontal rule: \cowel_html_self_closing_element(hr, (id = abc)){ignored}

Generated HTML:

Horizontal rule: <hr id=abc />

8.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
\cowel_to_html HTML policy
\cowel_highlight highlight policy see §8.5.1. \cowel_highlight — Perform syntax highlighting
\cowel_paragraphs paragraphs policy see §8.6.2. \cowel_paragraphs — Perform paragraph splitting
\cowel_no_invoke no-invoke policy
\cowel_actions no-invoke policy
\cowel_text_only text-only policy
\cowel_text_as_html text-as-html policy
\cowel_source_as_text source-as-text policy

8.4.1. \cowel_to_html — Process with to-HTML policy

cowel_to_html(){...}: block

\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.

Since HTML is not syntax-highlighted, we can insert special characters like U+00AD SOFT HYPHEN into code snippets, without interfering with syntax highlighting:

Use of \cowel_html_element(code){ \cowel_highlight(cpp){reinterpret_\ \cowel_to_html{\cowel_char_by_name{SOFT HYPHEN}}\ cast} } is discouraged.

This renders as:

Use of reinterpret_cast is discouraged.

Or, if line wrapping takes place in the middle of the highlighted keyword, it renders as:

Use of reinterpret_-
cast
is discouraged.

8.4.2. \cowel_no_invoke — Process with no-invoke policy

cowel_no_invoke(){...}: block

\cowel_no_invoke processes the provided content using the no-invoke policy.

COWEL markup:

\cowel_no_invoke{Undefined directive: \awoo}

Generated HTML:

Undefined directive: \awoo

Under the no-invoke policy selected by no_invoke, \awoo 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 "\n" in C++) because such escapes should not treated as COWEL directives.

COWEL comments and COWEL escape sequences are processed as usual. That is, comments are ignored, and escapes are expanded.

8.4.3. \cowel_actions — Process with actions policy

cowel_actions(){...}: block

\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).

COWEL markup:

no escapes: \cowel_macro(a) \cowel_macro(b) \cowel_macro(c) end. newline escapes: \cowel_macro(h)\ \cowel_macro(j)\ \cowel_macro(k)\ end. actions: \cowel_actions{ \: Documentation for x: \cowel_macro(x) \: In here, we can add as much whitespace as we want. \: It won't add anything to the generated HTML 😃 \cowel_macro(y) Text is also ignored, just like whitespace, but it is recommended to use comments even in actions because it expresses intent more clearly. \cowel_macro(z) }\ end.

Generated HTML:

no escapes: end. newline escapes: end. actions: end.

Note that nine macros have also been defined by the COWEL markup, but macro definitions produce no output.

8.4.4. \cowel_text_only — Process with text-only policy

cowel_text_only(){...}: block

\cowel_text_only processes the provided content using the text-only policy.

COWEL markup:

Hello, \cowel_html_element(strong){strong} world! \cowel_text_only{Hello, \cowel_html_element(strong){strong} world!}

Generated HTML:

Hello, <strong>strong</strong> world! Hello, strong world!

As can be seen, only plaintext "makes it through", whereas HTML is stripped.

This policy is used internally when processing arguments in various places, such as in the strong positional argument to \cowel_html_element in the example above.

It is mainly useful in situations where it makes no sense to have non-plaintext content.

8.4.5. \cowel_text_as_html — Process with text-as-HTML policy

cowel_text_as_html(){...}: block

\cowel_no_invoke processes the provided content using the text-as-HTML policy.

COWEL markup:

\cowel_text_as_html{Hello, <strong>strong</strong> world!}

Generated HTML:

Hello, <strong>strong</strong> world!

As can be seen, the provided text is reinterpreted as HTML.

This directive should be used with great caution because it can easily result in producing malformed HTML. While there are legitimate uses (e.g. inline SVG images and other large HTML blocks), \cowel_html_element and other safer directives should be preferred.

8.4.6. \cowel_source_as_text — Process with source-as-text policy

cowel_source_as_text(){...}: block

\cowel_no_invoke processes the provided content using the source-as-text policy.

COWEL markup:

\cowel_source_as_text{ \: Comment ... Hello \source_as_text \{ ... \} }

Generated HTML:

\: Comment ... Hello \source_as_text \{ ... \}

This directive is mainly useful for writing COWEL code blocks, where all content within is treated literally, including comments.

It can be seen as a more extreme form of \cowel_no_invoke, and is more niche in its applications.

8.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.

8.5.1. \cowel_highlight — Perform syntax highlighting

cowel_highlight(
  lang: string,
){...}: block

The \cowel_highlight processes content using the highlight policy, which wraps parts of code in HTML tags for the purpose of syntax highlighting.

\cowel_highlight has a single lang parameter. This specifies the name of language (e.g. cowel) in which the content is to be highlighted. The name has to be one of the language short names supported by the µlight syntax highlighter, which is the highlighter that COWEL uses internally.

8.5.2. \cowel_highlight_as — Syntax highlight override

cowel_highlight_as(
  name: string,
){...}: block

The \cowel_highlight_as 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.

\cowel_highlight_as has a single name parameter, which is the µlight long name for a highlight type.

You can obtain a list of possible long names at ulight.h from the definition of enum ulight_highlight_type. The long name is the enumerator name without the ULIGHT_HL prefix, all lowercase, and with hyphens instead of underscores.

It is possible to mix automatic syntax highlighting with manual overrides:

\: _Int128 is manually highlighted as a type keyword, \: and x is automatically highlighted as an identifier. \cowel_html_element(code){\ \cowel_highlight(c){\cowel_highlight_as(keyword-type){_Int128} x}\ }

This generates the HTML (subject to change):

<code><h- data-h=kw_type>_Int128</h-> <h- data-h=id>x</h-></code>

It renders as _Int128 x.

While it is also possible to produce the highlighting tags using \cowel_html_element(h-,data-h=kw_type){_Int128}, 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.

8.5.3. \cowel_highlight_phantom — Syntax highlight phantom text

cowel_highlight_phantom(){...}: block

The \cowel_highlight_phantom 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.

Using \cowel_highlight_phantom, we can control whether a JSON string is interpreted as a markup key, or as a string value:

In JSON, there are \cowel_html_element(code){\cowel_highlight(json){\cowel_highlight_phantom{\{}"keys"}} and \cowel_html_element(code){\cowel_highlight(json){"values"}}.

Using the highlight theme of this document, this renders as:

In JSON, there are "keys" and "values".

Notice that the color of "keys" is different because it is highlighted as if it was positioned like:

{"keys"

8.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 (<p>...</p>), divided at blank lines.

While content expanded from macros and from \cowel_include 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.

8.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. \comment) that don't generate anything rendered are meta content.

The process of paragraph splitting works as follows:

COWEL markup:

First paragraph. Second paragraph. \blockquote{This is a block directive.}

Generated HTML:

<p>First paragraph.</p> <p>Second paragraph.</p> <blockquote>This is a block directive.</blockquote>

8.6.2. \cowel_paragraphs — Perform paragraph splitting

cowel_paragraphs(){...}: block

The \cowel_paragraphs 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.

COWEL markup:

\cowel_paragraphs{ First paragraph. Second paragraph. }

Generated HTML:

<p>First paragraph.</p> <p>Second paragraph.</p>

At a top-level within the document, paragraph splitting takes place implicitly, as if the whole document was wrapped in \cowel_paragraphs.

However, this does not extend recursively, so if one wants to have paragraph splitting inside say, \cowel_html_­element, \cowel_paragraphs has to be used.

8.6.3. \cowel_paragraph_enter — Enter a paragraph

cowel_paragraph_enter(): block

If the current content policy is a paragraphs policy and and the paragraph state is "outside", the paragraph state becomes "inside", and a <p> tag is emitted. Otherwise, has no effect.

COWEL markup, assuming a surrounding paragraphs policy:

\cowel_char_by_name{DIGIT ONE}. First paragraph \cowel_paragraph_enter\cowel_char_by_name{DIGIT TWO}. Second paragraph

Generated HTML:

1<p>. First paragraph</p> <p>2. Second paragraph</p>

As explained, directives are "black boxes" for paragraph splitting, so when the paragraphs policy processes \cowel_char_by_name, it does not automatically begin a paragraph.

\cowel_paragraph_enter should rarely be used directly, but from within macros.

For example, the user can define an \N directive which combines \cowel_para­graph_enter and \cowel_­char_by_name.

8.6.4. \cowel_paragraph_leave — Leave a paragraph

cowel_paragraph_leave(): block

If the current content policy is a paragraphs policy and and the paragraph state is "inside", the paragraph state becomes "outside", and a closing </p> tag is emitted. Otherwise, has no effect.

COWEL markup, assuming a surrounding paragraphs policy:

Paragraph 1: \cowel_html_self_closing_element(hr) Paragraph 2: \cowel_paragraph_leave\cowel_html_self_closing_element(hr)

Generated HTML:

<p>Paragraph 1: <hr/></p> <p>Paragraph 2: </p><hr/>

As explained, directives are "black boxes" for paragraph splitting, so when the paragraphs policy processes \cowel_html_self_closing_element, it does not automatically leave a paragraph. This would be necessary because horizontal rules (<hr/>) are not supposed to be inside a paragraph.

\cowel_paragraph_leave should rarely be used directly, but from within macros.

For example, the user can define a \hr directive which combines \cowel_para­graph_leave and \cowel_­html_self_closing_element.

8.6.5. \cowel_paragraph_inherit — Activate paragraph splitting inside a directive

cowel_paragraph_inherit(): block

There is no support for programmatic directives yet, so this directive is currently useless. There are plans to add a WASM scripting API from which \cowel_paragraph_inherit may be used to alter behavior.

As already stated, paragraph splitting generally treats directives as "black boxes". However, content expanded from \cowel_include and macros inherits the surrounding paragraph for splitting, i.e. any content produced by such directives is fed directly into the paragraphs policy. \cowel_paragraph_inherit can be used inside programmatic directives defined by the user to achieve the same behavior.

8.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.

8.7.1. \cowel_include — Include a sub-document

cowel_include(){...}: block

The \cowel_include 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 \cowel_include, 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 \cowel_include appears. In other words, \cowel_include inherits the paragraph context, or is not a "black box" to paragraph splitting.

Say we have another test.cow files containing:

Hello, includes! Next paragraph.

When using \cowel_include, the contents of the other file are substituted where we have written \cowel_include, which means that imported content also plays nicely with paragraph splitting:

First paragraph. \cowel_include{test.cow}

Generated HTML:

<p>First paragraph. Hello, includes!</p> <p>Next paragraph.</p>

It is common practice to collect macros and other reusable components in separate documents, and to \cowel_include 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 \cowel_includes.

8.7.2. \cowel_include_text — Include text from a file

cowel_include_text(){...}: block

The \cowel_include_text 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 \cowel_include_text, and is assumed to be relative to the current file.

Say we have a JavaScript file example.js which we want to keep separate from the document. We can then include it into a \script block to use it as a script, or we can include it into a \codeblock to display its contents.

\codeblock(js){ // code included from example.js: \cowel_include_text{example.js} }

Assuming that example.js is located in the same directory as the document and that loading the file succeeds, this renders as:

// code included from example.js: function sqr(x) { return x * x; }

While \cowel_include and \cowel_include_text are similar, there are some stark differences:

8.8. Aliases and macros

8.8.1. \cowel_alias — Define aliases for an existing directive

cowel_alias(
  names: pack string,
){...}: unit

The \cowel_alias directive defines one or more aliases for an existing directive. The content of \cowel_alias 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 \cowel_alias, the target can also be invoked using the alias name.

A fatal error is raised if

One or multiple aliases can be defined as follows:

\cowel_alias(N){cowel_char_by_name} \N{DIGIT ZERO} \: OK, equivalent to \cowel_char_by_name{DIGIT ZERO} \cowel_alias(incl, include){cowel_include} \incl{file.cow} \: OK, equivalent to \cowel_include{file.cow} \include{file.cow} \: OK, same \cowel_alias{cowel_to_html} \: OK, but no effect \cowel_alias{\N{???}} \: error: generation of target name failed \cowel_alias{??} \: error: invalid target name \cowel_alias{undefined} \: error: target not found \cowel_alias("?"){cowel_alias} \: error: invalid alias name \cowel_alias(N){N} \: error: redefinition of N

8.8.2. \cowel_macro — Define a macro

cowel_macro(
  names: pack string,
){...}: unit

The \cowel_macro 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 \cowel_macro, the target can also be invoked using the macro name. Named arguments are ignored.

A fatal error occurs if

COWEL markup:

\cowel_macro(m,x){Hello, macros!}\ \m \x

Generated HTML:

Hello, macros! Hello, macros!

When a macro is processed, the behavior is as if \cowel_paragraph_inherit (§8.6.5. \cowel_paragraph_inherit — 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.

8.8.3. \cowel_put — Process provided macro content or arguments

cowel_put(
  else: lazy any,
){...}: any

The \cowel_put directive processes content which was provided when a macro was invoked.

The content provided to \cowel_put is converted to text, and designates

\cowel_put has the following effect:

COWEL markup:

\: \cowel_put designates content \cowel_macro(content){\cowel_put}\ \content{Content} \: \cowel_put designates first positional argument \cowel_macro(pos){\cowel_put{0}}\ \pos(Positional) \: \cowel_put designates named argument with name "n" \cowel_macro(named){\cowel_put{n}}\ \named(n = Named) \: \cowel_put designates the first positional argument and has a fallback \: Note that equivalently, we could use \cowel_put(Failure){0}. \cowel_macro(try){\cowel_put(else=Failure){0}}\ \try(Success) \try \: All together: \cowel_macro(m){\cowel_put{greeting}, \cowel_put\cowel_put{0}}\ \m(greeting = "Hello, !"){macros}

Generated HTML:

Content Positional Named Success Failure Hello, macros!

The behavior is erroneous if \cowel_put is not expanded from a macro, such as when \cowel_put appears at a top-level in the document.

\cowel_macro is not processed in any special way, meaning that it cannot be used for "macro substitution" directly:

\cowel_macro(m){\cowel_source_as_text{\cowel_put}}\ \m

Generated HTML:

\cowel_put

However, \cowel_put accesses the inputs to the macro invocation which expands \cowel_put:

\cowel_macro(m){\cowel_put}\ \m{\cowel_put}

This results in a fatal error because when \m is processed, the \cowel_put in the macro definition expands to the top-level \cowel_put. That \cowel_put in \m{\cowel_put} 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 \cowel_put within other directives while still referring to parameters of the macro invocation:

\cowel_macro(m){\cowel_to_html{\cowel_put}}\ \: OK, equivalent to \cowel_to_html{...} \: Notably, the expanded \cowel_put refers to the content provided to \m, \: not to the content provided to \cowel_to_html (which would be \cowel_put). \m{...}

Expanding \cowel_put 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:

\cowel_macro(twice){\cowel_put\cowel_put}\ \: error: multiple definitions of alias "\N" for "\cowel_char_by_name" \twice{\cowel_alias(N){cowel_char_by_name}}

8.9. Invocations

8.9.1. \cowel_invoke — Invoke a directive

cowel_invoke(
  name: string,
){...}: any

The \cowel_invoke 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 \cowel_invoke is the content provided to the invoked directive.

Any directive \abc can be invoked statically or dynamically:

\: Static invocation of directive named "abc". \abc{...} \: Static invocation of directive named "cowel_invoke", \: which performs an equivalent dynamic invocation of "abc". \cowel_invoke(abc){...}

It is also planned to allow providing arguments to the invoked directive, but it may be better to add "argument groups" to the syntax first, so that they can be bundled up in an args group. To avoid changing how \cowel_invoke works in the future, argument forwarding is not supported at all right now.

9. Legacy directives

The following builtin directives are all considered deprecated, but not all have a suitable replacement yet. These directives were created during the first iteration of COWEL, before plans were made to create a small set of builtin directives, with macro packages that provide additional functionality.

The documentation for these directives is not actively maintained.

9.1. Comments

In addition to the \: syntax for single-line comments, there exists a \comment directive which discards all of its contents. This can be used for multi-line comments.

9.1.1. \comment — Comments

The \comment directive does not process its arguments or content. It outputs no plaintext or HTML.

While comments don't output anything, §8.6.1. Paragraph splitting is based on blank lines in the source, so comments don't split paragraphs:

Text \comment{This is \directive{comment} content.} Text

Generated HTML:

<p>Text Text</p>

9.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
\b{...} <b>...</b> Bold text
\cite{...} <cite>...</cite> Name of cited work
\del{...} <del>...</del> Deleted text
\dfn{...} <dfn>...</dfn> Definition
\em{...} <em>...</em> Emphasized text
\gterm{...} unspecified grammar-term
\i{...} <i>...</i> Italic text
\ins{...} <ins>...</ins> Inserted text
\kbd{...} <kbd>...</kbd> Ctrl + Keyboard key
\mark{...} <mark>...</mark> Marked/highlighted
\o{...} unspecified Oblique text
\q{...} <q>...</q> Quoted text
\s{...} <s>...</s> Struck text
\samp{...} <samp>...</samp> Sample output
\sans{...} unspecified Sans-serif font
\serif{...} unspecified Serif font
\small{...} <small>...</small> Small text
\span{...} <span>...</span> (No change in formatting)
\sub{...} <sub>...</sub> Subscript
\sup{...} <sup>...</sup> Superscript
\strong{...} <strong>...</strong> Strong text
\tt{...} unspecified Teletype/monospace font
\var{...} <var>...</var> Variable name
\u{...} <u>...</u> Underlined text

All such formatting directives convert all named arguments directly into HTML attributes.

By default, a substantial amount of directives are styled the same way. For example, \cite, \var, \i and \em are all italic. Both \strong and \b are bold. Both \tt and \samp use teletype font.

However, you can customize the style; see §9.12.3. \style — CSS blocks.

The difference between oblique (\o) and italic (\i) text is that oblique text is merely slanted, while italic text is fundamentally a different font with different characters.

9.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.

9.3.1. \code — Inline code

The \code directive produced syntax-highlighted text in code font.

Arguments
  • lang (plaintext) — the syntax highlighting language.
  • nested (true/false) — whether to omit <code> tags.
Input content
The input to a \code directive is a plaintext context. However, there are special rules for formatting directives and pure plaintext directives (see below).
HTML output
In an HTML context, the \code takes the input source code, applies syntax highlighting, and outputs the result surrounded by <code>...</code>.
Plaintext output
In a plaintext context, \code simply outputs the input source code.
Display style
Inline

COWEL markup:

\code(cpp){123}

This applies C++ syntax highlighting, and generates HTML. The <h-> tags are an implementation detail and may be subject to change.

<code><h- data-h=num>123</h-></code>
9.3.1.1. Manual nested highlighting

The nested parameter is a plaintext context, which accepts either true or false, where false is the default. When enabled, the surrounding <code> tags are omitted, which makes it suitable for nesting languages within other \code or \codeblock directives.

You can nest JSON inside of a C++ string literal as follows:

Call: \code(cpp){out.write_json("\code(json,nested=true){{"x":123,"y":true,"z":null}}")}

This renders as follows:

Call: 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 nested parameter and not using it. However, the difference would be obvious once you want to style <code> elements to have borders, background color, padding, and other such styling features. nested=true directly emits the highlighting HTML elements, which is more composable.

9.3.1.2. Further advice on highlighting

Writing \code directives directly is often too tedious, so you'll likely want to define a macro to make this easier:

\: Defines a \js directive that can be used in place of \code(js) from now on: \macro(\js){\code(js){\put}} Let's highlight \js{var} in JavaScript.

9.3.2. \codeblock — Code blocks

The \codeblock directive works exactly like \code, 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 borders.

\codeblock(js){ // Borders enabled let x = 0; } \codeblock(js, borders = false){ // Borders disabled let x = 0; }

This renders as:

// Borders enabled let x = 0; // Borders disabled let x = 0;

9.3.3. \hl — Syntax highlight override

The \hl 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 name argument, which is the µlight long name for a highlight type. You can obtain a list of possible long names at ulight.h from the definition of enum ulight_highlight_type. The long name is the enumerator name without the ULIGHT_HL prefix, all lowercase, and with hyphens instead of underscores.

It is possible to mix automatic syntax highlighting with manual overrides:

\: _Int128 is manually highlighted as a type keyword, \: and x is automatically highlighted as an identifier. \code(c){\hl(keyword-type){_Int128} x}

This generates the HTML (subject to change):

<code><h- data=h=kw_type>_Int128</h-> <h- data-h=id>x</h-></code>

It renders as _Int128 x.

While it is also possible to produce the highlighting tags using \html-h-(data-h=kw_type){_Int128}, the "short names" (kw_type) are not stable, i.e. they are more likely to change. Only µlight long names should be used directly.

9.3.4. \pre — Preformatted blocks

The \pre directive contains pre-formatted content. It can be used to contain code, however, there is no syntax highlighting in a \pre block.

COWEL markup:

\pre{ Hello, world! ============= a b c }

This renders as:

Hello, world!
=============
    a b c

Unlike \codeblock, \pre currently does not support the borders=no option. This will be added in the future.

9.3.5. \literally — Treat input literally as text

The \literally 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.

COWEL markup:

\pre{\literally{ \: Even comments are preserved! This \comment{comment} \{ is taken literally \}! }}

This renders as:

\: Even comments are preserved!
This \comment{comment} \{ is taken literally \}!

\put pseudo-directives in macros are still processed, even inside \literally blocks because \macro replaces any appearances of \put with the given content, disregarding the semantics of any directives nested within.

9.3.6. \unprocessed — Suppress directive processing

The \unprocessed directive works just like \literally, except that escape sequences are processed into their escaped characters.

COWEL markup:

\pre{\unprocessed{ \: Unlike in \literally, comments are ignored. This \comment{comment} \{ is unprocessed \}! }}

This renders as:

This \comment{comment} { is unprocessed }!

\unprocessed and (to a lesser extent) \literally are very useful for nesting code inside COWEL that already contains underscores. For example, \n is an escape sequence for newline characters in many languages, and it may be annoying if it gets interpreted as an \n directive:

\codeblock(cpp){\unprocessed{ std::string_view s = "Several\nLines\nof\nCode."; }}

This renders as:

std::string_view s = "Several\nLines\nof\nCode.";

Notice that COWEL technically parses a \nLines directive instead of just \n, 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 \nLines are taken as text, and then split up according to C++ syntax.

\put pseudo-directives in macros are still processed, even inside \unprocessed blocks because \macro replaces any appearances of \put with the given content, disregarding the semantics of any directives nested within.

9.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.

If you have existing MathML, you can embed their content using \cowel_text_as_html:

Math \cowel_text_as_html{ <math display=inline> <mfrac> <mi>x</mi> <mn>2</mn> </mfrac> </math> } in a sentence.

This renders as:

Math x 2 in a sentence.

You can also keep the MathML separate within an XML document and use \cowel_include_text:

Math \cowel_text_as_html{\cowel_include_text{math.mml}} in a sentence.

However, hand-writing MathML would be extremely tedious and verbose, so COWEL offers some convenience directives, listed below.

9.4.1. \math — Inline math

A \math directive surrounds its content with <math display=inline>...</math> tags, and displays as inline content.

Its content is an HTML context, and within it, additional pseudo-directives like \mi or \mn 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.

The previous example in §9.4. Math could also be written like:

Math \math{ \mfrac{\mi{x}\mn{2}} } in a sentence.

If you frequently use math inside plain sentences, you can define a convenience macro:

\macro(\mathsqr{...}){\math{\msup{\mi{\put}\mn{2}}}} The sum of \mathsqr{x} and \mathsqr{y}

This renders as:

The sum of x2 and y2

9.4.2. \mathblock — Math blocks

The \mathblock directive functions almost exactly as the \math directive, but it displays as block content instead of inline content, and it produces an opening <math display=block> tag.

9.5. Separators and word breaking

9.5.1. \br — Break line

The \br directive produces a line break, and corresponds to the HTML element <br/>. It displays as inline content, and its input content is ignored.

\br is particularly useful when line breaks are treated same as spaces, which is the case in most HTML content.

9.5.2. \hr — Horizontal rule

The \hr directive produces a horizontal rule, and corresponds to the HTML element <hr/>. It displays as block content, and its input content is ignored.

Here is an example:


9.5.3. \wbr — Word break opportunity

The \wbr directive produces a word break opportunity, and corresponds to the HTML element <wbr>. It displays as inline content, and its input content is ignored.

<wbr> 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 <wbr> element (without a hyphen at the end of the line).

Since µlight only supports UTF-8 output, \wbr is equivalent to \U{200B}, which outputs a U+200B ZERO-WIDTH SPACE code point.

If you want to provide a word break hint but have a hyphen at the end of the line, use \U{AD} or \c{shy} to output a U+00AD SOFT HYPHEN.

9.5.4. \nobr — Unbroken words

The \nobr directive is a formatting directive which prevents word breaks within its content. Its content is an HTML context. This is done by applying a white-space: nowrap; style its content.

Another way to prevent word-breaking is to use non-breaking spaces. You can insert these using

9.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.

9.6.1. \Babstract — Abstract blocks

Abstracts provide a summary of the document.

9.6.2. \Bquote — Quote blocks

The \blockquote directive directly corresponds to the <blockquote> element.

Quotes blocks or "block quotes" display quoted text.

9.6.3. \blockquote — Alias for \Bquote

The \blockquote directive is equivalent to the \Bquote directive.

9.6.4. \Bug — Bug blocks

A bug block contains the description of a bug. This often includes a code block which demonstrates how to reproduce the bug.

9.6.5. \Bdecision — Decision blocks

A decision block indicates that a decision needs to be made.

9.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 \del directives would be too tedious to use.

9.6.7. \Bdetails — Details blocks aka spoilers

The \Bdetails directive directly corresponds to the <details> element. Within \Bdetails, the \summary 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".

9.6.8. \details — Alias for \Bdetails

The \details directive is equivalent to the \Bdetails directive.

9.6.9. \Bdiff — Difference blocks

A difference block contains changes, where some content within is typically deleted or inserted.

9.6.10. \Bex — Example blocks

An example block contains examples.

9.6.11. \Bins — Insertion blocks

An insertion block acts as a wrapper for a large amount of inserted content. It is typically used when individual \ins directives would be too tedious to use.

9.6.12. \Bimp — Important blocks

Important blocks contain especially important information.

9.6.13. \Bnote — Note blocks

Note blocks contain less important information, which can often be skipped over by readers.

9.6.14. \Btip — Tip blocks

Tip blocks contain useful advice.

9.6.15. \Btodo — TODO blocks

TODO blocks contain actions that remain to be done. They may indicate that a part of a project is incomplete.

9.6.16. \Bwarn — Warning blocks

Warning blocks warn the reader of some hazard or potential mistake.

9.7. Lists

9.7.1. \ul — Unordered lists

The \ul directive corresponds to the <ul> element, and produces an unordered list.

9.7.2. \ol — Ordered lists

The \ol directive corresponds to the <ol> element, and produces an ordered list.

9.7.3. \li — List items

The \li directive corresponds to the <li> element, and produces a list item with <ul> or <ol>.

COWEL markup:

\ul{ \li{first bullet} \li{second bullet} } \hr \ol{ \li{first bullet} \li{second bullet} }

This renders as:


  1. first bullet
  2. second bullet

9.7.4. \item — List item pseudo-directive

This directive is deprecated and will be removed in a future version.

Within \ul and \ol, the \item pseudo-directive can also be used instead of \li.

9.7.5. \dl — Definition lists

The \dl directive corresponds to the <dl> element, and produces a definition list. Within that list, you can use

9.8. Tables

Tables are simply produced by using the \table, \thead, \tbody, \tfoot, \tr, \th, \td, \colgroup, \col, and \caption directives to produce the corresponding HTML tags with the same name.

To perform advanced styling, like controlling alignment within columns, use a \style directive.

9.9. Headings

Headings can be produced using the \h1, \h2, \h3, \h4, \h5, and \h6 directives to produce the corresponding HTML tags with the same name.

Headings take a listed argument, which is a yes/no plaintext argument. Unless its value is no, headings are numbered and added to the table of contents (§9.9.1. \make_contents — Make table of contents) automatically.

Headings also take a show-number argument, which is a yes/no plaintext argument. Unless this is no, the heading number will be included in the title, in the format 1.2.3. Title. However, even if show-number is no, the number heading is internally numbered as usual, and its number can be seen in the table of contents.

Other arguments to these headings are converted into attributes of the corresponding HTML element. An id argument can be provided explicitly.

If none is provided, an id is synthesized from the content within the heading.

Headings can be referenced using the \ref directive:

\h2{Heading with synthesized id} \h2(id=xyz){Heading with manual id} \comment{These can be referenced as follows} \ref(#heading-with-synthesized-id) \ref(#xzy)

9.9.1. \make_contents — Make table of contents

The \make_contents 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 (§9.9. Headings) as the document is processed.

Since the table of contents should usually not be listed within itself, an unlisted heading may be used:

\h2(listed=no){Contents} \make_contents

A similar effect can be achieved using \cowel_html_element[h2] (§8.3.1. \cowel_html_element — HTML element). However, using \cowel_html_element[h2] will also not emit a link icon in the gutter, and it will not synthesize an id for that heading.

The underlying contents can be obtained with \here(std.contents). \make_contents additionally wraps those contents in HTML elements to chang their visual appearance.

9.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.

9.10.1. \bib — Add bibliography entry

The \bib 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 \ref to the bibliography entry.
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 link. You can also think of it as a "link for pretty printing".
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 id is optional, although you will hardly get meaningful bibliography output if only the id is specified.

9.10.2. \make_bib — Generate bibliography

The \make_bib 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 \make_bib directive is populated by uses of \bib directives in order of use. That is, the bibliography is not automatically sorted for you; the order in which \bib directives are used is also the order in which the bibliography entries are generated.

Similar to \make_contents, it is a wrapper for the underlying std.bib section.

9.11. References

9.11.1. \ref — References

The \ref directive takes a single to argument, which can be a URL, anchor, or something else. It produces an <a> 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:

COWEL markup:

\ref(mail:john@us.gov)

HTML output (<a> tag may have additional attributes):

<a href=mail:john@us.gov>john@us.gov</a>

C++ standard draft links can be synthesized into human-readable descriptions.

\ref(https://eel.is/c++draft/expr#1)

This renders as:

9.11.2. \mail — E-Mail addresses

A \mail directive behaves the same \ref directive that is given a mailto URL. However, the input is provided as content instead of an argument, and the displayed text cannot be customized.

The following two lines produce the same output:

Please contact \mail{john@us.gov}. Please contact \ref(mailto:john@us.gov).

9.11.3. \tel — Telephone numbers

A \tel directive behaves the same \ref directive that is given a tel URL. However, the input is provided as content instead of an argument, and the displayed text cannot be customized.

The following two lines produce the same output:

Please contact \tel{+1234}. Please contact \ref(tel:+1234).

9.12. Foreign languages

9.12.1. \script — JavaScript blocks

The content of a \script directive is a plaintext context, where the input is treated as JavaScript code and surrounded in <script>/*...*/</script> tags.

\script displays as meta content (like \comment).

COWEL markup:

\script{ console.log("hello"); }

Generated HTML:

<script> console.log("hello"); </script>

9.12.2. \noscript — No-JavaScript content

The \noscript directive corresponds to the <noscript> element. Its content is an HTML context, and will only be shown by the browser when JavaScript is disabled.

9.12.3. \style — CSS blocks

The content of a \style directive is a plaintext context, where the input is treated as JavaScript code and surrounded in <style>/*...*/</style> tags.

\style displays as meta content (like \comment).

COWEL markup:

\style{ body { color: red; } }

Generated HTML:

<style> body { color: red; } </style>

9.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 \ref(#id).

9.13.1. \there — Append content to section

The \there directive displays as meta content. Basically, it stashes away its input content (which is an HTML context) somewhere else.

It takes a single section argument which specifies the name of the section. The section argument is a plaintext context.

By default, all document content is placed within a <main> element, inside <body>, inside html. \there allows you to write outside of the <main> element:

You can change the title of the document as follows:

\there(std.head){ \html-title{This is the document title!} }

9.13.2. \here — Copy section content

The \here directive inserts the content from another section at its location. It displays as inline content.

It takes a single section argument which specifies the name of the section. The section argument is a plaintext context.

All references produced by \here are resolved in a post-processing step, which allows forward-references.

COWEL markup:

\there(sec){before/} (\here(sec)) \there(sec){/after}

Generated HTML:

(before//after)

9.13.3. \hereblock — Copy section content in block

The \hereblock directive functions exactly like the \here directive, but displays as block content instead of inline content.

9.14. Miscellaneous

9.14.1. \div — Content division

The \div directive surrounds its contents in <div>...</div> tags. It displays as a block, and its content is an HTML context. \div's named arguments are turned into HTML attributes.

9.14.2. \trim — Trim input

The content of a \text directive is an HTML context (§5.1. Content policies). Its arguments are ignored. \text is a formatting directive.

The process of trimming eliminates leading and trailing whitespace in the input, at the COWEL source level.

Every\trim{ day}

This renders as:

Everyday

\trim 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 \Note macro where the user can optionally provide a number for that note:

\macro(\Note){\trim{Note \put}:} \Note Something something. \Note{1} Something else.

This renders as:

Note: Something something.

Note 1: Something else.

Notice that because \put expands to no content, the trailing space after Note is eliminated. If it wasn't eliminated, we would end up with {Note :}, but there should never be a space before the colon.

9.14.3. \text — Plaintext context

The content of a \text 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 \text is within an HTML context.

9.14.4. \p — Paragraphs

The \p directive surrounds its content in <p>...</p> tags.

9.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.

9.15.1. \Vset — Set a variable

\Vset sets the value of a variable to some provided plaintext. It displays as a meta directive.

It takes a single var argument, which is a plaintext context for the name of the variable. The directive content is also a plaintext context, and provides the value of the variable.

COWEL markup:

\: Sets x = 123. \Vset(x){123} \: Accesses the value of x, which is 123. \Vget(x)

This renders as:

123

9.15.2. \Vget — Get a variable

\Vget obtains the value of a variable, and displays as inline. Its content is ignored.

It takes a single var argument, which is a plaintext context for the name of the variable. See above for an example.

If the variable denoted by the var argument does not exist, \Vget expands to nothing.