Colored underlines in set_color and fish_color_*

Add a new underline-color option to set_color (instead of adding an optional
color argument to --underline); this allows to set the underline color
independently of underline style (line, curly, etc.). I don't think this
flexibility is very important but this approach is probably the least hacky.

Note that there are two variants:
1. \e[58:5:1m
2. \e[58;5;1m

Variant 1 breaks:
breakage from colon-variant for colored underlines
- cool-retro-term makes text blink
- GNU screen (goes into bold mode)
- terminology (goes into bold mode)

Variant 2 would break:
- mintty (Cygwin terminal) -- it enables bold font instead.
- Windows Terminal (where it paints the foreground yellow)
- JetBrains terminals echo the colons instead of consuming them
- putty
- GNU screen (goes into bold mode)
- st
- urxvt
- xterm
- etc.

So choose variant 1.

Closes #11388
Closes #7619
This commit is contained in:
Johannes Altmanninger
2025-04-14 15:36:50 +02:00
parent cc9849c279
commit ce631fd2fb
12 changed files with 196 additions and 83 deletions

View File

@@ -127,6 +127,7 @@ complete -c set -n '__fish_seen_argument -s e -l erase; and __fish_seen_argument
# Color completions
complete -c set -n '__fish_set_is_color true false' -x -a '(set_color --print-colors)' -d 'text color'
complete -c set -n '__fish_set_is_color false true' -a '--background=(set_color --print-colors)'
complete -c set -n '__fish_set_is_color false true' -a '--underline-color=(set_color --print-colors)'
complete -c set -n '__fish_set_is_color true false' -a --bold -x
complete -c set -n '__fish_set_is_color true false' -a --dim -x
complete -c set -n '__fish_set_is_color true false' -a --italics -x

View File

@@ -1,5 +1,6 @@
complete -c set_color -x -d Color -a '(set_color --print-colors)'
complete -c set_color -s b -l background -x -a '(set_color --print-colors)' -d "Change background color"
complete -c set_color -s b -l underline-color -x -a '(set_color --print-colors)' -d "Change underline color"
complete -c set_color -s o -l bold -d 'Make font bold'
complete -c set_color -s i -l italics -d Italicise
complete -c set_color -s d -l dim -d 'Dim text'

View File

@@ -227,6 +227,7 @@ def parse_color(color_str):
comps = color_str.split(" ")
color = ""
background_color = ""
underline_color = ""
bold = False
underline = False
italics = False
@@ -251,37 +252,41 @@ def parse_color(color_str):
dim = True
elif comp == "--reverse" or comp == "-r":
reverse = True
elif comp.startswith("--background"):
# Background color
c = comp[len("--background=") :]
parsed_c = parse_one_color(c)
# We prefer the unparsed version - if it says "brgreen", we use brgreen,
# instead of 00ff00
if better_color(background_color, parsed_c) == parsed_c:
background_color = c
elif comp.startswith("-b"):
# Background color in short.
if comp == "-b":
if i + 1 == len(comps):
c = ""
else:
c = comps[i + 1]
i += 1
else:
c = comp[len("-b"):]
parsed_c = parse_one_color(c)
if better_color(background_color, parsed_c) == parsed_c:
background_color = c
else:
# Regular color
parsed_c = parse_one_color(comp)
if better_color(color, parsed_c) == parsed_c:
color = comp
def parse_opt(current_best: str, i: int, long_opt: str, short_opt: str | None) -> str:
if comp.startswith(long_opt):
c = comp[len(long_opt) :]
parsed_c = parse_one_color(c)
# We prefer the unparsed version - if it says "brgreen", we use brgreen,
# instead of 00ff00
if better_color(current_best, parsed_c) == parsed_c:
return True, c, i
elif short_opt is not None and comp.startswith(short_opt):
if comp == short_opt:
if i + 1 == len(comps):
c = ""
else:
c = comps[i + 1]
i += 1
else:
c = comp[len(short_opt):]
parsed_c = parse_one_color(c)
if better_color(current_best, parsed_c) == parsed_c:
return True, c, i
return False, current_best, i
is_bg, background_color, i = parse_opt(background_color, i, "--background", "-b")
is_ul, underline_color, i = parse_opt(underline_color, i, "--underline-color", None)
if not (is_bg or is_ul):
# Regular color
parsed_c = parse_one_color(comp)
if better_color(color, parsed_c) == parsed_c:
color = comp
i += 1
return {
"color": color,
"background": background_color,
"underline-color": underline_color,
"bold": bold,
"underline": underline,
"italics": italics,
@@ -309,6 +314,8 @@ def unparse_color(col):
ret += " --reverse"
if col["background"]:
ret += " --background=" + col["background"]
if col["underline-color"]:
ret += " --underline-color=" + col["underline-color"]
return ret