Skip to main content

Syntax Highlighting

Rune colors code from the parse tree, not from regular expressions. Every color you see in a buffer comes from a rule you can change: editor.highlights decides which parts of the syntax get which attributes, and the active theme decides what those color names look like.

How highlighting works

  1. Rune parses the buffer with the Tree-sitter grammar from the installed language package, and keeps that tree in sync as you type.
  2. The package ships a highlighting query that tags ranges of the tree with capture names: @keyword, @string, @comment, @function.method, and so on.
  3. editor.highlights maps each capture name to a set of terminal attributes — a foreground color, a background color, and text flags.
  4. The theme resolves the color names to actual colors.

The split between the last two steps is the useful mental model: the theme decides what yellow looks like, the highlights decide what is yellow. Switching themes recolors everything without touching your capture rules, and changing a capture rule applies to every theme.

A language package without a highlighting query still parses: the file opens, folds, and is searchable structurally, but it is rendered without colors.

Capture names and inheritance

Capture names are dotted, and they fall back to their prefix. When Rune looks up a capture it tries the full name first, then drops one dotted segment at a time:

keyword.function -> keyword
markup.link.url -> markup.link -> markup

So a single keyword entry colors keyword.function, keyword.operator, and every other refinement, unless you give one of them its own entry.

Any capture name that matches nothing at any prefix renders with your terminal's default colors. That is the usual answer to "why is this not colored?": the grammar emits a capture Rune has no rule for. Real examples with no default entry include constant, constructor, punctuation.special, and embedded. Adding an entry for the name is all it takes:

editor:
highlights:
constant:
fg: red
constructor:
fg: aqua

Configuring highlights

editor.highlights is merged key by key onto Rune's defaults, so you only write the captures you want to change. The merge goes one level deeper than the capture name too: adding flags to a capture keeps the default fg for it.

editor:
highlights:
comment:
fg: silver
flags: italic
string:
fg: green
keyword:
flags: bold

Here comment and string get new colors, and keyword becomes bold while keeping its default yellow foreground.

Attributes

Each capture entry accepts three keys:

KeyValue
fgForeground color
bgBackground color
flagsOne flag name, or a list of them

Colors are the named palette colors described in Themes (red, yellow, aqua, silver, ...), common aliases such as magenta and cyan, any other W3C color name, a hex literal like "#d6a23a", or default to use the terminal's own color. A name Rune does not recognize falls back to default rather than raising an error, so check the spelling if a capture comes out uncolored.

Valid flags are bold, dim, italic, underline, strikethrough, blink, reverse, and none (default is a synonym for none). Pass several at once as a list:

editor:
highlights:
markup.link:
fg: aqua
flags: [underline, italic]

Default highlights

These are the rules a stock Rune install starts from. Anything not listed here — and not reachable through prefix inheritance — renders with terminal defaults.

Code

CaptureForegroundFlags
functiondefault
function.builtinyellow
function.methoddefault
typedefault
propertydefault
variabledefault
operatordefault
keywordyellow
stringmagenta
escapedefault
numberred
constant.builtindefault
commentblue

Markup

Emitted by Markdown and other prose grammars.

CaptureForegroundFlags
markup.headingyellowbold
markup.rawmagenta
markup.raw.delimiteryellow
markup.linkcyanunderline
markup.link.urlcyanunderline
markup.link.labelyellowunderline
markup.link.textcyanunderline
markup.listyellowbold
markup.quoteblueitalic
markup.strongyellowbold
markup.italicyellowitalic
markup.strikethroughbluestrikethrough
markup.underlineyellowunderline
markup.mathmagenta

Legacy prose captures

Older upstream queries use the text.* family instead of markup.*.

CaptureForegroundFlags
text.titleyellowbold
text.literalmagenta
text.uricyanunderline
text.referenceyellowunderline
text.emphasisyellowitalic
text.strongyellowbold

Beyond colors

Capture names are not only about rendering. The same vocabulary drives structural search and navigation: jumptoast and searchast take a query file and a capture name, so learning the capture names your language emits pays off twice.

If a language package ships queries you want to change — or you are adding a language yourself — see the language integration guide for how Rune loads highlights.scm and the other query files.

Ask Rune Agent