Skip to content

Code blocks

Nacara treats a code block as a list of lines, each a list of tokens, with annotations on top, so highlighting, markers and line numbers compose.

The meta syntax follows Expressive Code.

Title

You can give a code block a title:

```fsharp title="Program.fs"
let main argv = 0
```
Program.fs
let main argv = 0

Frames

frame=terminal draws it as a terminal instead:

```bash frame=terminal
dotnet run -- build
```
Terminal
dotnet run -- build

frame=none removes the chrome:

```bash frame=none
dotnet run -- build
```
dotnet run -- build

Marking lines

{2,4-5} marks lines, ins={3} and del={4} mark insertions and deletions:

```fsharp showLineNumbers {1} ins={3} del={4}
let site =
    Site.create "Docs"
    |> Markdown.register
    |> Legacy.register
```
let site =
    Site.create "Docs"
    |> Markdown.register
    |> Legacy.register

Writing a diff

If you would rather write the changes than count the lines, fence the block as diff and put + or - in front of each line. The markers are read off and never reach the page, so what you copy is code you can paste:

```diff
Site.create "Docs"
-|> Legacy.register
+|> Markdown.register
```
Site.create "Docs"
|> Legacy.register
|> Markdown.register

That colours it as a diff, though - the code underneath is F# and nothing knows it. Say so with lang=:

```diff lang="fsharp"
Site.create "Docs"
-|> Legacy.register
+|> Markdown.register
```
Site.create "Docs"
|> Legacy.register
|> Markdown.register

Write the markers the same way down the block: -printfn and +printfn, or a space after every one of them. Only the marker comes off, so a space after - on one line and none after + on the next leaves the two a column apart.

A diff pasted from git diff is left exactly as it is: the --- and +++ headers are kept, filenames and all.

A deleted line is drawn but left out of what the block gives you, so copying returns the code after the change. The same goes for a line del= names, and for live examples: Run compiles what survives.

Marking words

A quoted string or a /regular expression/ marks text inside the lines.

ins= and del= take the same, and colour what they mark:

```fsharp /Site\.\w+/ ins="Markdown" del="register"
let site = Site.create "Docs" |> Site.baseUrl "/" |> Markdown.register
```
let site = Site.create "Docs" |> Site.baseUrl "/" |> Markdown.register

Line numbers and collapsing

showLineNumbers, with startLineNumber= when the excerpt starts further down, and collapse={3-5} to fold a range behind a summary:

```json showLineNumbers collapse={3-5}
{
  "name": "example",
  "hidden": "one",
  "hidden": "two",
  "hidden": "three",
  "visible": true
}
```
{
  "name": "example",
3 collapsed lines
  "hidden": "one",
  "hidden": "two",
  "hidden": "three",
  "visible": true
}

Height

maxHeight= caps a block and scrolls it, for a listing too long to run down the page:

```json maxHeight=8rem
{
  "name": "example",
  "one": 1,
  "two": 2,
  "three": 3,
  "four": 4,
  "five": 5,
  "six": 6
}
```
{
  "name": "example",
  "one": 1,
  "two": 2,
  "three": 3,
  "four": 4,
  "five": 5,
  "six": 6
}

Takes a CSS length: 30rem, 400px, 50vh. Anything else is ignored.

A live example caps its editor with it too, so the block is the same height before and after Run.

Set --nacara-code-max-height in your own stylesheet to cap every block of the site:

:root {
  --nacara-code-max-height: 30rem;
}

Highlighting

Colours come from CSS classes, never inline styles, so one rendering serves light and dark and switching theme costs no rebuild. See the highlight plugin.

Inline code

Code in a sentence is coloured too, once it says what language it is:

Call `Site.baseUrl "/"{:fsharp}` before anything else.

Call Site.baseUrl "/" before anything else.

The marker goes inside the backticks, where it is part of the snippet and gets stripped before the page is written - nothing to copy by accident. This is the spelling rehype-pretty-code uses, so it may already be familiar.

The attribute form works too, and reads better when the snippet itself ends in a brace:

Call `Site.baseUrl "/"`{fsharp} before anything else.

Call `Site.baseUrl "/"`{lang=fsharp} before anything else.

Call Site.baseUrl "/" before anything else.

Call Site.baseUrl "/" before anything else.

A bare {word} is only read as a language when a highlighter claims it, so `x`{disabled} stays the attribute you wrote. A language nobody covers is reported the same way a fence naming one is, and the snippet renders without colour.

Who does what

Three things meet in a code block. Knowing which is which tells you where to go when one of them is wrong:

PartOwnerChange it by
The meta after the language - titles, frames, {1,3}, ins=, collapse=The engineNothing to configure; it is the same in markdown and in literate F#
The colours of the tokensA highlighter pluginHighlighting, or a plugin taking one language
The markup around it - the frame, the copy button, the foldThe themeRegistering your own ICodeBlockRenderer; the last one wins

The meta is the engine's, not the markdown plugin's: literate F# writes the same annotations as (*** title="Greeting.fs" {2} ***). So a fence with no highlighter still gets its title, its markers and its copy button.

Edit this page