The line you are typing
- #interactive
- #readline
- #highlighting
Until now huck's prompt showed you exactly what you typed and nothing else. Type
a command that does not exist, a quote you never closed, or a * you meant to
be literal, and you found out afterwards.
Here is what the terminal actually received while typing one line, before and
after. The escape codes are shown raw — 31 is red, 33 yellow, 1;36 bold
cyan, 34 blue:
# before
huck> nosuchcmd "dq" $HOME *.rs
# after
huck> ^[[31mnosuchcmd^[[0m ^[[33m"dq"^[[0m ^[[1;36m$HOME^[[0m ^[[34m*^[[0m.rsFour separate things, and the one that matters most is the first: nosuchcmd
is red because it will not run. Everything else on the line is information —
the string is one colour, the variable's NAME is bold so your eye finds it, and
the * is coloured on its own so you can see which character is going to
expand and which are just part of the filename.
The colour you do not see
A working command is left alone:
huck> echo hi^[[35m;^[[0m ^[[31mnosuchcmd^[[0m hiecho is plain. That is deliberate, and it is the whole design: if every
command word were coloured, colour would stop meaning anything. The only word
wearing red is the one that is about to fail. fish popularised this restraint
and it is worth copying.
The check is the shell's own resolution order — alias, function, builtin, then
PATH — so a function you defined a minute ago counts, and a program you just
installed is picked up on the next line. It never writes to the command hash
table, so merely typing a name cannot change what hash prints, and it gives up
rather than making you wait if PATH has something slow on it.
One consequence worth knowing: while you are typing echo, the words e, ec
and ech are genuinely not commands, so the word is red until the o lands.
That is the same thing fish does. Waiting for a word boundary would mean the
signal arrives after the mistake.
Brackets
Put the cursor on a bracket and its partner lights up — whole delimiters, not single characters:
huck> echo ^[[7m$(^[[0mdate^[[7m)^[[0m7 is reverse video, so this reads on any colour scheme. And when a construct
is still open, its opener is underlined so you can see what the shell is waiting
for:
huck> echo ^[[4m$(^[[0m^[[31mdat^[[0mThat underline comes from the same machinery that decides which bracket an unexpected end-of-file names — the work described in Which bracket did you forget?. It knows about nesting rather than counting brackets, so it is right inside quotes, inside arithmetic, and inside a substitution within a string.
Structure, not guesswork
The colours come from actually parsing the line, not from pattern-matching it.
That is why 'a*b' has no glob colour while a*b does, why the nosuch inside
echo $(nosuch) is checked as a command in its own right, and why FOO=bar cmd
knows that cmd is the command and FOO is a variable name.
It also means the shell can colour things a regular expression would get wrong.
${ and } are one colour and the name between them is another; a comment is
grey to end of line; an escaped \$ inside a string is marked even though the
backslash disappears before anything downstream could see it.
Turning it off
Three ways, in the order you would reach for them:
shopt -u syntax_highlight # this session, or put it in ~/.huckrc
NO_COLOR=1 huck # the cross-tool convention
huck < script.sh # not a terminal: nothing is ever paintedThe last one is not a courtesy, it is a guarantee: 309 test harnesses compare huck's bytes with bash's, and a single stray escape would break every one of them.
What is still open
Colours are not configurable yet — the palette is fixed (#667).
(When this was written, a continuation line — the part you type after the >
prompt — was barely coloured, because it is parsed on its own and then echo hi
is not a valid command by itself. That is fixed now: see
The second line.) Bracket globs like
f[abc].rs are not marked, because they are not reliably one piece by the time
the highlighter sees them, and colouring some but not others is worse than
colouring none (#668). And
shopt syntax_highlight is a name bash does not have — deliberately, and
deliberately invisible to shopt's listings so that everything else still
matches bash exactly (#669).