Add strikethrough TextStyling

Closes #12369
This commit is contained in:
Timen Zandbergen
2026-01-22 19:19:47 +01:00
committed by Johannes Altmanninger
parent 553aa40b34
commit f6936f222a
10 changed files with 61 additions and 5 deletions

View File

@@ -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.

View File

@@ -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**.

View File

@@ -110,6 +110,7 @@ Options accepted by ``set_color`` like
``--dim``,
``--italics``,
``--reverse``,
``--strikethrough``,
``--underline`` and
``--underline-color=``
are also accepted.

View File

@@ -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.

View File

@@ -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

View File

@@ -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'

View File

@@ -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

View File

@@ -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))

View File

@@ -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<TextStyling>) -> &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" {

View File

@@ -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)