Skip to content

Syntax Highlighting

pagedmov edited this page Sep 24, 2026 · 3 revisions

shed highlights the command line as you type it. Highlighting colors commands, keywords, strings, variables, operators, and more, and flags things like unknown commands in red before you ever hit enter. Every color is configurable through the highlight.* shopt namespace. The highlighter uses shed's lexer and parser internally, so it can be used to see exactly how shed will interpret the line before you submit it.

Enabling

Highlighting is on by default. Two toggles control it:

Option Effect
highlight.enable master on/off switch for syntax highlighting (default true)
highlight.check_files check the filesystem so that arguments naming a real file are styled (see argument_file below), and command-position directories are recognized. Involves a stat per candidate, so it can be slow on network mounts - set false to skip it (default true)
shopt highlight.enable=false      # turn highlighting off entirely

Color Descriptions

Every highlight.* color takes a style description: a space-separated list of style words that combine into one style. This is the exact same grammar used by the prompt's \c{...} escape (see Prompt), so anything you learn here works there too.

A description is built from these pieces, in any order:

  • Attributes - any of bold, dim, italic, underline, strikethrough, blink, inverted, hidden.
  • A foreground color - one of black, red, green, yellow, blue, magenta, cyan, white.
  • bright - prefix that selects the bright variant of the color that follows it, e.g. bright black (a common "gray") or bright cyan.
  • A hex color - #rrggbb for a truecolor foreground, e.g. #89b4fa.
  • A background - on followed by a color: on blue, on bright black, or on #1e1e2e.
  • reset - clears styling back to the terminal default.

So all of these are valid:

shopt highlight.string="yellow"
shopt highlight.comment="italic bright black"
shopt highlight.operator="bold magenta"
shopt highlight.variable="#89b4fa"
shopt highlight.invalid_command="bold underline red on black"

An invalid description is rejected when you set the option (for highlight.*) with an error explaining what didn't parse, so you'll know immediately if you typo a color name.

Highlight Categories

Each category below is a highlight.* option. Setting it changes the color of that syntax element in the line editor.

Commands (the word in command position):

Option Colors Default
highlight.external_command commands found on $PATH green
highlight.builtin builtin commands green
highlight.function shell functions green
highlight.alias aliases green
highlight.directory a directory in command position (with core.autocd) green
highlight.invalid_command a command name that doesn't resolve to anything bold red

Syntax:

Option Colors Default
highlight.keyword keywords like if and for yellow
highlight.control_flow_keyword control-flow words like break and return magenta
highlight.operator pipes, redirects, and other operators bold magenta
highlight.string quoted strings yellow
highlight.variable variable expansions cyan
highlight.glob glob characters bright cyan
highlight.comment comments italic bright black

Arguments:

Option Colors Default
highlight.argument ordinary command arguments white
highlight.argument_file an argument that names an existing file underline white

The argument_file styling depends on highlight.check_files being enabled - it's what lets shed know an argument points at a real file. Likewise, highlight.directory (command-position directories) relies on both check_files and core.autocd. If you turn check_files off for speed, both fall back to the plain argument/invalid_command styling.

Since every value is a full color description, you can restyle the whole editor to match a theme by dropping a block of shopt highlight.* lines into your rc file (see Configuration) - or snapshot your live colors into one with genrc -s.

Command Wrappers

Some commands run another command passed as their argument, for instance: sudo ls, env FOO=bar make, nice -n10 build. For highlighting, the wrapped word (ls, make, build) is still in command position, so shed highlights and validates it as a command rather than as a plain argument. Without this, a typo like sudo lx would be painted as an ordinary argument instead of being flagged with highlight.invalid_command.

shed recognizes a built-in set of these wrappers out of the box: sudo, doas, pkexec, run0, env, nice, ionice, nohup, setsid, unshare, strace, valgrind, command, builtin, exec, and more. The word immediately following any of them is treated and validated as the command.

If you have your own wrapper that ultimately execs its argument, add it to the SHED_EXEC_WRAPPERS array and the highlighter treats it the same way:

SHED_EXEC_WRAPPERS+=(invoke)
invoke ls        # `ls` is highlighted as a command, not an argument

Your entries extend the built-in list rather than replacing it.

Clone this wiki locally