diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 972b26ff2..419b2ea64 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -71,7 +71,7 @@ Completions Improved terminal support ^^^^^^^^^^^^^^^^^^^^^^^^^ -- Support for curly underlines in `fish_color_*` variables and :doc:`set_color ` (:issue:`10957`). +- Support for double, curly, dotted and dashed underlines in `fish_color_*` variables and :doc:`set_color ` (:issue:`10957`). - Underlines can now be colored independent of text (:issue:`7619`). - New documentation page `Terminal Compatibility `_ (also accessible via ``man fish-terminal-compatibility``) lists required and optional terminal control sequences used by fish. diff --git a/doc_src/cmds/set_color.rst b/doc_src/cmds/set_color.rst index 21e2b519b..a2a83b3ed 100644 --- a/doc_src/cmds/set_color.rst +++ b/doc_src/cmds/set_color.rst @@ -57,7 +57,7 @@ The following options are available: Sets reverse mode. **-u** or **--underline**, or **-uSTYLE** or **--underline=STYLE** - Set the underline mode; supported styles are **single** (default) and **curly**. + Set the underline mode; supported styles are **single** (default), **double**, **curly**, **dotted** and **dashed**. **-h** or **--help** Displays help about using this command. diff --git a/doc_src/terminal-compatibility.rst b/doc_src/terminal-compatibility.rst index ed8426da2..e8db65262 100644 --- a/doc_src/terminal-compatibility.rst +++ b/doc_src/terminal-compatibility.rst @@ -120,10 +120,22 @@ Optional Commands - smul - Enter underline mode. - + * - ``\e[4:2m`` + - Su + - Enter double underline mode. + - kitty * - ``\e[4:3m`` - Su - Enter curly underline mode. - kitty + * - ``\e[4:4m`` + - Su + - Enter dotted underline mode. + - kitty + * - ``\e[4:5m`` + - Su + - Enter dashed underline mode. + - kitty * - ``\e[7m`` - rev - Enter reverse video mode (swap foreground and background colors). diff --git a/share/completions/set.fish b/share/completions/set.fish index 68b0c6811..9d4848b57 100644 --- a/share/completions/set.fish +++ b/share/completions/set.fish @@ -133,7 +133,7 @@ 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 complete -c set -n '__fish_set_is_color true true' -a --reverse -x complete -c set -n '__fish_set_is_color true false' -a --underline -x -complete -c set -n '__fish_set_is_color true false' -a --underline=curly -x +complete -c set -n '__fish_set_is_color true false' -a--underline={double,curly,dotted,dashed} -x # Locale completions complete -c set -n '__fish_set_is_locale; and not __fish_seen_argument -s e -l erase' -x -a '(command -sq locale; and locale -a)' -d Locale diff --git a/share/completions/set_color.fish b/share/completions/set_color.fish index 2fa24f148..2c476a0f1 100644 --- a/share/completions/set_color.fish +++ b/share/completions/set_color.fish @@ -5,6 +5,6 @@ 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' complete -c set_color -s r -l reverse -d 'Reverse color text' -complete -c set_color -s u -l underline -d 'Underline style' -a 'single curly' +complete -c set_color -s u -l underline -d 'Underline style' -a 'single double curly dotted dashed' complete -c set_color -s h -l help -d 'Display help and exit' complete -c set_color -s c -l print-colors -d 'Print a list of all accepted color names' diff --git a/share/tools/web_config/webconfig.py b/share/tools/web_config/webconfig.py index 14aa7f76b..ab99a00aa 100755 --- a/share/tools/web_config/webconfig.py +++ b/share/tools/web_config/webconfig.py @@ -244,7 +244,7 @@ def parse_color(color_str): underline = "single" elif comp.startswith("--underline="): underline = comp.stripprefix("--underline=") - elif comp.startswith("-u"): # Multiple short options like "-rbcurly" are not yet supported. + elif comp.startswith("-u"): # Multiple short options like "-rucurly" are not yet supported. underline = comp.stripprefix("-u") elif comp == "--italics" or comp == "-i": italics = True diff --git a/src/terminal.rs b/src/terminal.rs index 6f7908c57..ef2d99504 100644 --- a/src/terminal.rs +++ b/src/terminal.rs @@ -55,12 +55,11 @@ pub(crate) enum TerminalCommand<'a> { EnterBoldMode, EnterDimMode, EnterItalicsMode, - EnterUnderlineMode, + EnterUnderlineMode(UnderlineStyle), EnterReverseMode, EnterStandoutMode, ExitItalicsMode, ExitUnderlineMode, - EnterCurlyUnderlineMode, // Screen clearing ClearScreen, @@ -149,12 +148,11 @@ fn write(out: &mut impl Output, sequence: &'static [u8]) -> bool { EnterBoldMode => ti(self, b"\x1b[1m", |t| &t.enter_bold_mode), EnterDimMode => ti(self, b"\x1b[2m", |t| &t.enter_dim_mode), EnterItalicsMode => ti(self, b"\x1b[3m", |t| &t.enter_italics_mode), - EnterUnderlineMode => ti(self, b"\x1b[4m", |t| &t.enter_underline_mode), + EnterUnderlineMode(style) => underline_mode(self, style), EnterReverseMode => ti(self, b"\x1b[7m", |t| &t.enter_reverse_mode), EnterStandoutMode => ti(self, b"\x1b[7m", |t| &t.enter_standout_mode), ExitItalicsMode => ti(self, b"\x1b[23m", |t| &t.exit_italics_mode), ExitUnderlineMode => ti(self, b"\x1b[24m", |t| &t.exit_underline_mode), - EnterCurlyUnderlineMode => write(self, b"\x1b[4:3m"), ClearScreen => ti(self, b"\x1b[H\x1b[2J", |term| &term.clear_screen), ClearToEndOfLine => ti(self, b"\x1b[K", |term| &term.clr_eol), ClearToEndOfScreen => ti(self, b"\x1b[J", |term| &term.clr_eos), @@ -234,6 +232,19 @@ pub(crate) fn use_terminfo() -> bool { !future_feature_flags::test(FeatureFlag::ignore_terminfo) && TERM.lock().unwrap().is_some() } +fn underline_mode(out: &mut impl Output, style: UnderlineStyle) -> bool { + use UnderlineStyle as UL; + let style = match style { + UL::Single => return maybe_terminfo(out, b"\x1b[4m", |t| &t.enter_underline_mode), + UL::Double => 2, + UL::Curly => 3, + UL::Dotted => 4, + UL::Dashed => 5, + }; + write_to_output!(out, "\x1b[4:{}m", style); + true +} + fn palette_color(out: &mut impl Output, paintable: Paintable, mut idx: u8) -> bool { if only_grayscale() && !(Color::Named { idx }).is_grayscale() { return false; @@ -515,9 +526,9 @@ fn set_text_face_internal(&mut self, face: TextFace, salvage_unreadable: bool) { let style = face.style; use TerminalCommand::{ - DefaultBackgroundColor, DefaultUnderlineColor, EnterBoldMode, EnterCurlyUnderlineMode, - EnterDimMode, EnterItalicsMode, EnterReverseMode, EnterStandoutMode, - EnterUnderlineMode, ExitAttributeMode, ExitItalicsMode, ExitUnderlineMode, + DefaultBackgroundColor, DefaultUnderlineColor, EnterBoldMode, EnterDimMode, + EnterItalicsMode, EnterReverseMode, EnterStandoutMode, EnterUnderlineMode, + ExitAttributeMode, ExitItalicsMode, ExitUnderlineMode, }; // Removes all styles that are individually resettable. @@ -587,12 +598,9 @@ fn set_text_face_internal(&mut self, face: TextFace, salvage_unreadable: bool) { self.last.style.underline_style = None; } } - Some(underline) => { - if self.write_command(match underline { - UnderlineStyle::Single => EnterUnderlineMode, - UnderlineStyle::Curly => EnterCurlyUnderlineMode, - }) { - self.last.style.underline_style = Some(underline); + Some(underline_style) => { + if self.write_command(EnterUnderlineMode(underline_style)) { + self.last.style.underline_style = Some(underline_style); } } } diff --git a/src/text_face.rs b/src/text_face.rs index 25c3f88b7..b1e45717b 100644 --- a/src/text_face.rs +++ b/src/text_face.rs @@ -11,7 +11,10 @@ trait StyleSet { #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub(crate) enum UnderlineStyle { Single, + Double, Curly, + Dotted, + Dashed, } impl StyleSet for Option { @@ -234,13 +237,21 @@ pub(crate) fn parse_text_face_and_options<'argarray, 'args>( 'r' => style.reverse = true, 'u' => { let arg = w.woptarg.unwrap_or(L!("single")); - if arg == "single" { - style.underline_style = Some(UnderlineStyle::Single); + style.underline_style = Some(if arg == "single" { + UnderlineStyle::Single + } else if arg == "double" { + UnderlineStyle::Double } else if arg == "curly" { - style.underline_style = Some(UnderlineStyle::Curly); + UnderlineStyle::Curly + } else if arg == "dotted" { + UnderlineStyle::Dotted + } else if arg == "dashed" { + UnderlineStyle::Dashed } else if is_builtin { return Err(UnknownUnderlineStyle(arg)); - } + } else { + continue; + }); } 'c' => { assert!(is_builtin); diff --git a/tests/checks/set_color.fish b/tests/checks/set_color.fish index 9c90024ba..0b0bf46b6 100644 --- a/tests/checks/set_color.fish +++ b/tests/checks/set_color.fish @@ -40,3 +40,10 @@ string escape (set_color --underline-color=red) # CHECK: \e\[58:5:1m string escape (set_color --underline-color=normal) # CHECK: \e\[59m + +string escape (set_color --underline=double) +# CHECK: \e\[4:3m +string escape (set_color --underline=dotted) +# CHECK: \e\[4:4m +string escape (set_color --underline=dashed) +# CHECK: \e\[4:5m