diff --git a/CHANGELOG.rst b/CHANGELOG.rst index eba3884ec..e02475244 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -19,6 +19,10 @@ New or improved bindings - Vi mode key bindings now support counts for movement and deletion commands (e.g. `d3w` or `3l`), via a new operator mode (:issue:`2192`). - New ``catpuccin-*`` color themes. +Improved terminal support +------------------------- +- ``set_color`` learned the strikethrough (``--strikethrough`` or ``-s``) modifier. + For distributors and developers ------------------------------- - The CMake option ``WITH_GETTEXT`` has been renamed to ``WITH_MESSAGE_LOCALIZATION``, to reflect that it toggles localization independently of the backend used in the implementation. diff --git a/doc_src/cmds/set_color.rst b/doc_src/cmds/set_color.rst index 586e9bc8a..d868e203e 100644 --- a/doc_src/cmds/set_color.rst +++ b/doc_src/cmds/set_color.rst @@ -54,6 +54,9 @@ The following options are available: **-r** or **--reverse** Sets reverse mode. +**-s** or **--strikethrough** + Sets strikethrough mode. + **-u** or **--underline**, or **-uSTYLE** or **--underline=STYLE** Set the underline mode; supported styles are **single** (default), **double**, **curly**, **dotted** and **dashed**. diff --git a/doc_src/interactive.rst b/doc_src/interactive.rst index 56fbe8c53..a1576f9d0 100644 --- a/doc_src/interactive.rst +++ b/doc_src/interactive.rst @@ -110,6 +110,7 @@ Options accepted by ``set_color`` like ``--dim``, ``--italics``, ``--reverse``, +``--strikethrough``, ``--underline`` and ``--underline-color=`` are also accepted. diff --git a/doc_src/terminal-compatibility.rst b/doc_src/terminal-compatibility.rst index acacc36f3..ea1d081b7 100644 --- a/doc_src/terminal-compatibility.rst +++ b/doc_src/terminal-compatibility.rst @@ -92,7 +92,7 @@ Optional Commands * - ``\e[m`` - sgr0 - - Turn off bold/dim/italic/underline/reverse attribute modes and select default colors. + - Turn off bold/dim/italic/underline/strikethrough/reverse attribute modes and select default colors. * - ``\e[1m`` - bold - Enter bold mode. @@ -120,12 +120,18 @@ Optional Commands * - ``\e[7m`` - rev - Enter reverse video mode (swap foreground and background colors). + * - ``\e[9m`` + - smxx + - Enter strikethrough mode * - ``\e[23m`` - ritm - Exit italic mode. * - ``\e[24m`` - rmul - Exit underline mode. + * - ``\e[29m`` + - rmxx + - Exit strikethrough mode. * - ``\e[38;5; Ps m`` - setaf - Select foreground color Ps from the 256-color-palette. diff --git a/share/completions/set.fish b/share/completions/set.fish index 408b2143a..dcfdc74b1 100644 --- a/share/completions/set.fish +++ b/share/completions/set.fish @@ -139,6 +139,7 @@ complete -c set -n '__fish_set_is_color false true' -a '--underline-color=(set_c 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 +complete -c set -n '__fish_set_is_color true false' -a --strikethrough -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={double,curly,dotted,dashed} -x diff --git a/share/completions/set_color.fish b/share/completions/set_color.fish index 2c476a0f1..6f40b4a9c 100644 --- a/share/completions/set_color.fish +++ b/share/completions/set_color.fish @@ -3,6 +3,7 @@ complete -c set_color -s b -l background -x -a '(set_color --print-colors)' -d " 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 s -l strikethrough -d Strikethrough 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 double curly dotted dashed' diff --git a/share/tools/web_config/webconfig.py b/share/tools/web_config/webconfig.py index c69e09a7d..fcfbc2c15 100755 --- a/share/tools/web_config/webconfig.py +++ b/share/tools/web_config/webconfig.py @@ -233,6 +233,7 @@ def parse_color(comps): bold = False underline = None italics = False + strikethrough = False dim = False reverse = False i = 0 @@ -256,6 +257,8 @@ def parse_color(comps): dim = True elif comp == "--reverse" or comp == "-r": reverse = True + elif comp == "--strikethrough" or comp == "-s": + strikethrough = True elif comp.startswith("--theme="): pass # Not yet supported here. else: @@ -310,6 +313,7 @@ def parse_color(comps): "italics": italics, "dim": dim, "reverse": reverse, + "strikethrough": strikethrough, } @@ -330,6 +334,8 @@ def unparse_color(col): ret += " --dim" if col["reverse"]: ret += " --reverse" + if col["strikethrough"]: + ret += " --strikethrough" if col["background"]: ret += " --background=" + col["background"] if col["underline-color"]: @@ -659,7 +665,7 @@ def append_html_for_ansi_escape(full_val, result, span_open): close_span() return False - # TODO We don't handle bold, underline, italics, dim, or reverse yet + # TODO We don't handle bold, underline, italics, dim, strikethrough, or reverse yet # Do nothing on failure return span_open diff --git a/src/terminal.rs b/src/terminal.rs index 2aa4bddf3..1c451a349 100644 --- a/src/terminal.rs +++ b/src/terminal.rs @@ -55,9 +55,11 @@ pub(crate) enum TerminalCommand<'a> { EnterItalicsMode, EnterUnderlineMode(UnderlineStyle), EnterReverseMode, + EnterStrikethroughMode, EnterStandoutMode, ExitItalicsMode, ExitUnderlineMode, + ExitStrikethroughMode, // Screen clearing ClearScreen, @@ -153,6 +155,8 @@ fn write(out: &mut impl Output, sequence: &'static [u8]) -> bool { 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), + EnterStrikethroughMode => write(self, b"\x1b[9m"), + ExitStrikethroughMode => write(self, b"\x1b[29m"), ExitItalicsMode => ti(self, b"\x1b[23m", |t| &t.exit_italics_mode), ExitUnderlineMode => ti(self, b"\x1b[24m", |t| &t.exit_underline_mode), ClearScreen => ti(self, b"\x1b[H\x1b[2J", |term| &term.clear_screen), @@ -549,8 +553,9 @@ fn set_text_face_internal(&mut self, face: TextFace, salvage_unreadable: bool) { use TerminalCommand::{ DefaultBackgroundColor, DefaultUnderlineColor, EnterBoldMode, EnterDimMode, - EnterItalicsMode, EnterReverseMode, EnterStandoutMode, EnterUnderlineMode, - ExitAttributeMode, ExitItalicsMode, ExitUnderlineMode, + EnterItalicsMode, EnterReverseMode, EnterStandoutMode, EnterStrikethroughMode, + EnterUnderlineMode, ExitAttributeMode, ExitItalicsMode, ExitStrikethroughMode, + ExitUnderlineMode, }; // Removes all styles that are individually resettable. @@ -606,7 +611,7 @@ fn set_text_face_internal(&mut self, face: TextFace, salvage_unreadable: bool) { self.last.underline_color = underline_color; } - // Lastly, we set bold, underline, italics, dim, and reverse modes correctly. + // Lastly, we set bold, underline, italics, dim, reverse, and strikethrough modes correctly. if style.is_bold() && !self.last.style.is_bold() && self.write_command(EnterBoldMode) { self.last.style.bold = true; } @@ -637,6 +642,19 @@ fn set_text_face_internal(&mut self, face: TextFace, salvage_unreadable: bool) { self.last.style.dim = true; } + let was_strikethrough = self.last.style.is_strikethrough(); + if !style.is_strikethrough() + && was_strikethrough + && self.write_command(ExitStrikethroughMode) + { + self.last.style.strikethrough = false; + } else if style.is_strikethrough() + && !was_strikethrough + && self.write_command(EnterStrikethroughMode) + { + self.last.style.strikethrough = true; + } + if style.is_reverse() && !self.last.style.is_reverse() && (self.write_command(EnterReverseMode) || self.write_command(EnterStandoutMode)) diff --git a/src/text_face.rs b/src/text_face.rs index a71e79d43..7f3853b87 100644 --- a/src/text_face.rs +++ b/src/text_face.rs @@ -37,6 +37,7 @@ pub(crate) struct TextStyling { pub(crate) italics: bool, pub(crate) dim: bool, pub(crate) reverse: bool, + pub(crate) strikethrough: bool, } impl TextStyling { @@ -47,6 +48,7 @@ pub(crate) const fn default() -> Self { italics: false, dim: false, reverse: false, + strikethrough: false, } } pub(crate) fn is_empty(&self) -> bool { @@ -61,6 +63,7 @@ pub(crate) fn union_prefer_right(self, other: Self) -> Self { italics: self.is_italics() || other.is_italics(), dim: self.is_dim() || other.is_dim(), reverse: self.is_reverse() || other.is_reverse(), + strikethrough: self.is_strikethrough() || other.is_strikethrough(), } } pub(crate) fn difference_prefer_empty(self, other: Self) -> Self { @@ -72,6 +75,7 @@ pub(crate) fn difference_prefer_empty(self, other: Self) -> Self { italics: self.is_italics() && !other.is_italics(), dim: self.is_dim() && !other.is_dim(), reverse: self.is_reverse() && !other.is_reverse(), + strikethrough: self.is_strikethrough() && !other.is_strikethrough(), } } @@ -104,6 +108,11 @@ pub const fn is_dim(self) -> bool { pub const fn is_reverse(self) -> bool { self.reverse } + + /// Returns whether the text face is strikethrough. + pub const fn is_strikethrough(self) -> bool { + self.strikethrough + } } #[derive(Clone, Copy, Debug, Eq, PartialEq)] @@ -197,6 +206,7 @@ pub(crate) fn parse_text_face_and_options<'argarray, 'args>( wopt(L!("underline"), ArgType::OptionalArgument, 'u'), wopt(L!("italics"), ArgType::NoArgument, 'i'), wopt(L!("dim"), ArgType::NoArgument, 'd'), + wopt(L!("strikethrough"), ArgType::NoArgument, 's'), wopt(L!("reverse"), ArgType::NoArgument, 'r'), wopt(L!("theme"), ArgType::RequiredArgument, '\x01'), wopt(L!("help"), ArgType::NoArgument, 'h'), @@ -248,6 +258,7 @@ fn init_style(style: &mut Option) -> &mut TextStyling { 'i' => init_style(&mut style).italics = true, 'd' => init_style(&mut style).dim = true, 'r' => init_style(&mut style).reverse = true, + 's' => init_style(&mut style).strikethrough = true, 'u' => { let arg = w.woptarg.unwrap_or(L!("single")); init_style(&mut style).underline_style = Some(if arg == "single" { diff --git a/tests/checks/set_color.fish b/tests/checks/set_color.fish index 0154fb660..07de1b37f 100644 --- a/tests/checks/set_color.fish +++ b/tests/checks/set_color.fish @@ -22,6 +22,11 @@ string escape (set_color --bold=red) #CHECKERR: called on line {{\d+}} of file {{.*}}checks/set_color.fish #CHECKERR: (Type 'help set_color' for related documentation) +string escape (set_color --strikethrough red --background=normal) +# CHECK: \e\[31m\e\[49m\e\[9m +string escape (set_color --strikethrough red --background=blue) +# CHECK: \e\[31m\e\[44m\e\[9m + string escape (set_color --bold red --background=normal) # CHECK: \e\[31m\e\[49m\e\[1m string escape (set_color --bold red --background=blue)