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"?
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"?
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.
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.
This works for me.
$ echo -e `echo "this is a strikethrough text" | sed 's/.\{1\}/&\\\u0336/g'`
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).
printf "\e[9m"
printf "Casey"
printf "\e[m\n"
And here is a screenshot of XTerm
That is all you need to know to use it. If you'd like to understand in more detail, read on.
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 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.
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]:
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
.