# Highlighters

**URL:** <https://discuss.kakoune.com/t/highlighters/543>\
**Category:** Manual++\
**Created:** [May 8, 2019, 2:18am UTC](https://discuss.kakoune.com/t/highlighters/543 "2019-05-08T02:18:39Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![robertmeta](https://discuss.kakoune.com/user_avatar/discuss.kakoune.com/robertmeta/32/833_2.png) [@robertmeta](https://discuss.kakoune.com/u/robertmeta)\
**Post date:** [May 8, 2019, 2:18am UTC](https://discuss.kakoune.com/t/highlighters/543/1 "2019-05-08T02:18:39Z")

</div>

# Description

Manipulation of the displayed text is done through highlighters, which  
can be added or removed with the following commands:

```
add-highlighter <path>/<name> <type> <parameters> ...

```

and

```
remove-highlighter <path>/<name>

```

**path** is the name of a highlighter group, it is expressed as a **/**  
separated path starting with a scope. Scopes are **global** , **buffer** ,  
**window** and **shared**

**name** is the name of the highlighter, if name is omitted in  
`add-highlighter` (the path ends with a `/`), it will be auto-generated  
from the remaining parameters.

# Convenient highlighters

**show-matching**  
highlight matching char of the character under the selections’ cursor  
using `MatchingChar` face

**show-whitespaces** [options]  
display symbols on top of whitespaces to make them more explicit using  
the `Whitespace` face, with the following **options** :

**-lf** \<separator\>  
a one character long separator that will replace line feeds

**-spc** \<separator\>  
a one character long separator that will replace spaces

**-nbsp** \<separator\>  
a one character long separator that will replace non-breakable spaces

**-tab** \<separator\>  
a one character long separator that will replace tabulations

**-tabpad** \<separator\>  
a one character long separator that will be appended to tabulations to  
honor the **tabstop** option

**number-lines** [options]  
show line numbers using the `LineNumbers`, `LineNumberCursor` and  
`LineNumbersWrapped` faces, with the following **options** :

**-relative**  
show line numbers relative to the main cursor line

**-hlcursor**  
highlight the cursor line with a separate face

**-separator** \<separator text\>  
specify a string to separate the line numbers column with the rest of  
the buffer (default is _|_)

**wrap** [options]  
soft wrap buffer text at window width, with the following **options** :

**-word**  
wrap at word boundaries instead of codepoint boundaries.

**-indent**  
preserve line indent when wrapping.

**-width \<max\_width\>**  
wrap text at **max\_width** if the window is wider.

**-marker \<marker\_text\>**  
prefix wrapped lines with **marker\_text** ; if **-indent** was given,  
the marker\_text is displayed into the indentation if possible.

# General highlighters

**fill** \<face\>  
fill using the given **face** , mostly useful with regions highlighters

**column** \<number\> \<face\>  
highlight column **number** with face **face**

**line** \<number\> \<face\>  
highlight line **number** with face **face**

**regex** \<regex\> \<capture\_id\>:\<face\> …  
highlight a regex, takes the regex as first parameter, followed by any  
number of face parameters. This highlights C++ style comments in cyan,  
with an eventual _TODO:_ in yellow on red background:

```
add-highlighter window/ regex //\h*(TODO:)[^\n]* 0:cyan 1:yellow,red

capture_id can be either the capture number, or its name if a
named capture is used in the regex (See
<<regex#Groups, `:doc regex Groups`>>)

```

**dynregex** \<expression\> \<capture\_id\>:\<face\> …  
similar to regex, but expand (like a command parameter would) the given  
expression before building a regex from the result. This highlights all  
the current search matches in italic:

```
add-highlighter window/ dynregex '%reg{/}' 0:+i

```

# Specs highlighters

The following highlighters are useful to add indicators like lint  
warnings, git blame output or spelling typos. See  
[`:doc options types`](#options#types) for the format of `line-specs`  
and `range-specs`.

**flag-lines** \<face\> \<option\_name\>  
add columns in front of the buffer, and display the flags specified in  
`line-specs` option, using \<face\>. In this example two words will  
be added in the gutter: a blue Foo at line 1 and a bold red/yellow Bar  
on line 3:

```
declare-option line-specs my_flags
set-option window my_flags %val{timestamp} '1|Foo' '3|{red,yellow+b}Bar'
add-highlighter window/ flag-lines blue my_flags

```

**ranges** \<option\_name\>  
use the data in the `range-specs` option of the given name to highlight  
the buffer. The string part of each tuple of the range-specs is  
interpreted as a **face** to apply to the range. In this example the 3  
first chars of the buffer will be colored in red:

```
declare-option range-specs my_range
set-option window my_range %val{timestamp} '1.1,1.3|red'
add-highlighter window/ ranges my_range

```

**replace-ranges** \<option\_name\>  
use the data in the `range-specs` option of the given name to highlight  
the buffer. The string part of each tuple of the range-specs is  
interpreted as a **display line** to display in place of the range.  
Here, the 3 first chars of the buffer will be replaced by the word  
_red_:

```
declare-option range-specs my_range
set-option window my_range %val{timestamp} '1.1,1.3|red'
add-highlighter window/ replace-ranges my_range

```

# Highlighting Groups

The **group** highlighter is a container for other highlighters. A  
subgroup can be added to an existing group or scope using:

```
add-highlighter <path>/<name> group

```

Other highlighters can then be added to that group

```
add-highlighter <path>/<name> <type> <params>...

```

In order to specify which kinds of highlighters can be added to a given  
group, the **-passes** flag set can be passed along with the group name.  
Possible values for this option can be one or several (separated with a  
pipe sign) of **colorize** , **move** or **wrap** (default:  
**colorize** ):

```
add-highlighter window/<name> group -passes colorize|move|wrap

```

# Regions highlighters

A special highlighter provides a way to segment the buffer into regions,  
which are to be highlighted differently.

```
add-highlighter <path>/<name> regions

```

Individual region definitions can then be added to that highlighter

```
add-highlighter <path>/<name>/<region_name> region \
    [-match-capture] [-recurse <recurse>] \
    <opening> <closing> <type> <params>...

```

**opening**  
regex that defines the region start text

**closing**  
regex that defines the region end text

**recurse**  
regex that defines the text that matches recursively an end token into  
the region, every match of **recurse** will consume a following match of  
**end** , preventing it from closing the region.

**type** and **params**  
An highlighter type, and associated params, as they would be passed to  
`add-highlighter` if they were not applied as a region.

If the **-match-capture** switch is passed, then region closing and  
recurse matches are considered valid for a given region opening match  
only if they matched the same content for the capture 1.

The **recurse** option is useful for regions that can be nested, for  
example the following contruct:

```
%sh{ ... }

```

accepts nested braces scopes (_{ … }_) so the following string is valid:

```
%sh{ ... { ... } ... }

```

This region can be defined with:

```
shell_expand -recurse \{ %sh\{ \}

```

Regions are matched using the left-most rule: the left-most region  
opening starts a new region. When a region closes, the closest next  
opening start another region.

That matches the rule governing most programming language parsing.

A default region, that will apply its given highlighter for segments of  
the buffer that are not in any defined region, can be added with the  
**default-region** highlighter type.

```
add-highlighter <path>/<name>/<region_name> default-region <type> <params>...

```

Most programming languages can then be properly highlighted using a  
region highlighter as root:

```
add-highlighter <path>/<lang> regions
add-highlighter <path>/<lang>/string '"' '"' fill string
add-highlighter <path>/<lang>/comment '//' '$' fill comment
add-highlighter <path>/<lang>/code default-region group
add-highlighter <path>/<lang>/code/variable regex ...
add-highlighter <path>/<lang>/code/function regex ...

```

# Shared Highlighters

Highlighters are often defined for a specific filetype, and it makes  
then sense to share the highlighters between all the windows on the same  
filetypes.

Highlighters can be put in the shared scope in order to make them  
reusable.

```
add-highlighter shared/<name> ...

```

The common case would be to create a named shared group, or regions and  
then fill it with highlighters:

```
add-highlighter shared/ group <name>
add-highlighter shared/<name> regex ...

```

It can then be referenced in a window using the ref highlighter.

```
add-highlighter window/ ref <name>

```

The ref can reference any named highlighter in the shared scope.

---

<div class="post-metadata">

**Author:** ![EpocSquadron](https://discuss.kakoune.com/user_avatar/discuss.kakoune.com/epocsquadron/32/78_2.png) [@EpocSquadron](https://discuss.kakoune.com/u/EpocSquadron)\
**Post date:** [October 17, 2020, 1:14am UTC](https://discuss.kakoune.com/t/highlighters/543/2 "2020-10-17T01:14:01Z")

</div>

One thing that isn’t clear here is how to nest regions. Adding another group to a group that has regions declared doesn’t seem to be allowed, but that isn’t obvious from this man page.

By staring at a bunch of the built in language highlighters, I was able to determine that at least one way is to create a group, add regexes to it, then create a new, unrelated group and some regions which then ref the first group. For example, in many templating languages (twig, mustache, etc), there are two kinds of tag regions, one for logical operations, the other for outputting variables. If you want to highlight a strings region within either of those regions, you need to define the two tag types as refs to the language grammar that includes string regions. This seems to be the resolution to the problem I stated here:

> [@Having trouble highlighting strings inside a nested region](https://discuss.kakoune.com/t/having-trouble-highlighting-strings-inside-a-nested-region/870):
>
> I’m attempting to create a syntax highlighter for twig templates, based on the highlighter for django templates in kakoune-extra. The highlighter splits itself into three groups, code, scope and expansion. The first calls out to the html highlighter. The other two handle the two types of tags that are available in twig – one for logic and one for output. add-highlighter shared/twig/code default-region ref html add-highlighter shared/twig/scope region '\{%' '%\}' group add-highlighter shared/twi…

I’m sure there’s more tricks to be learned here. Looking at the JavaScript language kak script is bewildering. It uses recursion in a way I don’t have time to reverse engineer.

---

<div class="post-metadata">

**Author:** ![tgirod](https://discuss.kakoune.com/letter_avatar_proxy/v4/letter/t/35a633/32.png) [@tgirod](https://discuss.kakoune.com/u/tgirod)\
**Post date:** [November 21, 2020, 12:41pm UTC](https://discuss.kakoune.com/t/highlighters/543/3 "2020-11-21T12:41:58Z")

</div>

Hey!

Sorry if I’m being dense, but I think it would help to have a few simple, practical examples.

For example, let’s say I want to highlight a specific word from a file. For example, the word TODO in a markdown file, or a nickname in a chat log …

EDIT: shit sorry I skipped the part where there is an example like that. Sorry for the noise!

---

<div class="post-metadata">

**Author:** ![LobaLuna](https://discuss.kakoune.com/user_avatar/discuss.kakoune.com/lobaluna/32/1043_2.png) [@LobaLuna](https://discuss.kakoune.com/u/LobaLuna)\
**Post date:** [January 16, 2023, 2:39am UTC](https://discuss.kakoune.com/t/highlighters/543/4 "2023-01-16T02:39:04Z")

</div>

It’s not being dense, it’s being pedagogical. Not all of us are that tech savvy, and examples clarifies many things that words take longer.

Please, add examples in every concept.
