12

I have already looked into ANSI escape codes, but it looks like only underlining is supported.

Do I miss something or is there another option?

If it is not possible, is there something equivalent in the meaning of "this is deprecated"?

soc
  • 27,983
  • 20
  • 111
  • 215

5 Answers5

16

According to the ECMA-48 standard for terminals, SGR (Select Graphic Rendition) code number 9 is supposed to enable crossed-out text. However, the ANSI escape code wikipedia page says that it's not widely supported, and I'm not aware of any that do. I'd suspect that's because DEC's VTxxx series didn't support it.

ak2
  • 6,629
  • 31
  • 27
  • 3
    My `libvterm`/`pangoterm` can do it just fine. See the second screenshot in [link](http://leonerds-code.blogspot.com/2011/09/libvtermpangoterm-and-tickit.html) – LeoNerd Mar 13 '12 at 11:13
  • 6
    Actually a good set of the major shell terminal seems to support it (this includes ``guake``, ``terminator``, ``gnome-terminal``, ...). http://misc.flogisoft.com/bash/tip_colors_and_formatting#terminals_compatibility . Quick test: ``echo -e "\e[9mtest\e[0m"``. – vaab Jun 12 '14 at 12:49
  • Kitty supports the SGR code 9 for crossed-out text (along with a bunch of other underused modes). Most of the common linux terminals use the libvterm so at least on Linux, this mode is widely supported. Putty however, doesn't support it. – NoelProf Sep 01 '20 at 22:45
  • I've found that on Windows, the Windows Terminal supports it, and VS Code's terminal emulator supports it. Powershell and CMD can't do escape codes without a terminal emulator, so seems pretty compatible – KetZoomer Aug 08 '21 at 16:31
6

An alternative solution for applications written in C11 or C++11 is to use the Unicode combining long stroke overlay character.

In C++11 you can write code something like this:

#include <iostream>
#include <string>

std::string strikethrough(const std::string& text) {
  std::string result;
  for (auto ch : text) {
    result.append(u8"\u0336");
    result.push_back(ch);
  }
  return result;
}

int main() {
  std::cout << strikethrough("strikethrough") << std::endl;
}

The code prefixes each character in the input text with the stroke overlay \u0336. Note that the function assumes that text is encoded in a singlebyte encoding such as ASCII or Latin. If the input is in UTF-8 it must be converted to UTF-32 first to get the character boundaries.

The output then is s̶t̶r̶i̶k̶e̶t̶h̶r̶o̶u̶g̶h in a UTF-8 capable terminal. I don't know why the first character has no strike-through, must be a terminal issue. I could work around this by printing at least one character before the strikethrough function call.

The Unicode solution also generates a slightly different locking in my terminal (terminator) compared to the ANSI escape sequence mentioned above. The former renders the line exactly in the middle of the text whereas the latter renders it a bit below.

  • 1
    If you add `\u0336` _after_ each character, rather than before, it sometimes has the effect of "straightening out" the characters and should also strike through each character. – jonschlinkert Jun 21 '18 at 06:40
4

This works for me.

$ echo -e `echo "this is a strikethrough text" | sed 's/.\{1\}/&\\\u0336/g'`

Nitin
  • 109
  • 1
  • 5
1

Yes, use SGR(9)

Function Sequence
To start striking text Esc [ 9 m
To stop striking text Esc [ 2 9 m
To return to normal text Esc [ m

You can strike-through text by using the Select Graphic Rendition (SGR) sequence. SGR allows you to specify a number to enable or disable "aspects", such as bold, italic, and underlined. The parameter 9 enables the "crossed-out" aspect.

If you wish to stop crossing-out text but not affect other active aspects, like bold or italic, use SGR(29). However, it is more common to see programs use parameter 0, typically by omitting the number, which resets all styles to the default (normal text).

Example usage

printf "\e[9m"
printf "Casey"
printf "\e[m\n"

And here is a screenshot of XTerm

Screenshot of terminal using SGR aspect 9 to strikeout text

That is all you need to know to use it. If you'd like to understand in more detail, read on.


Full explanation

Back in the olden days, each model of computer terminal had its own idiosyncratic set of "escape sequences" for controlling it. ECMA-48[^1] was an attempt to make a cross-platform standard. The "crossed out" aspect was first included in the 1984 edition of ECMA-48. However, even 24 years later, in 2008, Thomas Dickey — maintainer of terminfo and xterm, and thus one of the most knowledgeable people on the topic — stated he'd never seen a terminal that supported it. Fortunately, in the years since then, software terminal emulation has improved to the point that "crossed out" and many other ideas proposed by ECMA-48 are widely available.

Other text aspects

Other text aspects can be used simultaneously or in place of the crossed-out aspect. Here are the ones which are most likely to be supported on modern terminals.[^2]

    SGR(Ps) ⇐ Esc [ Ps m

    Ps Aspect Ps Aspect
    0 Normal (default)
    1 Bold 21 Doubly-underlined
    2 Faint (dim, low-intensity) 22 Normal (neither bold nor faint)
    3 Italicized 23 Not italicized
    4 Underlined 24 Not underlined
    5 Blink 25 Steady (not blinking)
    7 Inverse 27 Positive (not inverse)
    8 Invisible, i.e., hidden 28 Visible, i.e., not hidden
    9 Crossed-out characters 29 Not crossed-out
    Ps Aspect Ps Aspect
    30 Set foreground color to Black 40 Set background color to Black
    31 Set foreground color to Red 41 Set background color to Red
    32 Set foreground color to Green 42 Set background color to Green
    33 Set foreground color to Yellow 43 Set background color to Yellow
    34 Set foreground color to Blue 44 Set background color to Blue
    35 Set foreground color to Magenta 45 Set background color to Magenta
    36 Set foreground color to Cyan 46 Set background color to Cyan
    37 Set foreground color to White 47 Set background color to White
    39 Set foreground color to default 49 Set background color to default

For the full list of all possible text aspects, including oddities such as Fraktur and slow blink, see section 8.3.117: SGR - Select Graphic Rendition of the ECMA-48 standard.

Terminals known to work

The ncurses terminfo database keeps track of which features are supported by which terminals. Here is the list of terminals which are known to support "ecma+strikeout"[^3]:

    alacritty foot hterm kitty konsole mintty mlterm
    ms-terminal screen st terminology tmux vte xterm

Note that some terminal projects do not keep their terminfo entries up to date. For example, Gnome Terminal is not listed, but it actually does work as it is based on vte.




[^1]: "ECMA-48" is often referred to as "ANSI escape sequences". Either is equally correct as ECMA-48 and ANSI X3.64 are nearly identical and were later merged into ISO 6429. However ANSI and ISO charge fees to see their standards, so I use the ECMA publication which is gratis.

[^2]: This is actually the list of sequences that XTerm supports (as of 2023) as documented in the CSI function m section in Thomas Dickey's Control Sequences for XTerm, see ctlseqs in pdf or html. There is no perfect list of most commonly supported sequences, but XTerm is widely imitated and many other terminals attempt to be "xterm-compatible".

[^3] As of ncurses 6.4-dev 2023, via $ toe -u terminfo.src | grep strike | cut -d: -f1 | sort | column .

hackerb9
  • 1,545
  • 13
  • 14
0

couldn't find anything easier than this:

$ echo -e "\e[9myour text goes here\e"