129 lines
5.5 KiB
ReStructuredText
129 lines
5.5 KiB
ReStructuredText
The text sizing protocol
|
|
==============================================
|
|
|
|
Classically, because the terminal is a grid of equally spaced characters, only
|
|
a single text size was supported in terminals, with one minor exception, some
|
|
characters were allowed to be rendered in two cells, to accommodate East Asian
|
|
square aspect ratio characters and Emoji. Here, by single text size we mean the
|
|
font size of all text on the screen is the same.
|
|
|
|
This protocol allows text to be displayed in the terminal in different sizes
|
|
both larger and smaller than the base text. It also solves the long standing
|
|
problem of robustly determining the width (in cells) a character should have.
|
|
Applications can interleave text of different sizes on the screen allowing for
|
|
typographic niceties like headlines, superscripts, etc.
|
|
|
|
Note that this protocol is fully backwards compatible, terminals that implement
|
|
it will continue to work just the same with applications that do not use it.
|
|
Because of this, it is not fully flexible in the font sizes it allows, as it
|
|
still has to work with the character cell grid based fundamental nature of the
|
|
terminal.
|
|
|
|
Quickstart
|
|
--------------
|
|
|
|
Using this protocol to display different sized text is very simple, let's
|
|
illustrate with a few examples to give us a flavor:
|
|
|
|
.. code-block:: sh
|
|
|
|
printf "\e]_text_size_code;s=2;Double sized text\a\n\n"
|
|
printf "\e]_text_size_code;s=3;Triple sized text\a\n\n\n"
|
|
printf "\e]_text_size_code;n=1:d=2;Half sized text\a\n"
|
|
|
|
Note that the last example, of half sized text, has half height characters, but
|
|
they still each take one cell, this can be fixed with a little more work:
|
|
|
|
.. code-block:: sh
|
|
|
|
printf "\e]_text_size_code;n=1:d=2:w=1;Ha\a\e]66;n=1:d=2:w=1;lf\a\n"
|
|
|
|
The `w=1` mechanism allows the program to tell the terminal what width the text
|
|
should take. This not only fixes using smaller text but also solves the long
|
|
standing terminal ecosystem bugs caused by the client program not knowing how
|
|
many cells the terminal will render some text in.
|
|
|
|
|
|
The escape code
|
|
-----------------
|
|
|
|
There is a single escape code used by this protocol. It is sent by client
|
|
programs to the terminal emulator to tell it to render the specified text
|
|
at the specified size. It is an `OSC` code of the form::
|
|
|
|
<OSC> _text_size_code ; metadata ; text <terminator>
|
|
|
|
Here, `OSC` is the bytes `ESC ] (0x1b 0x5b)`. The `metadata` is a colon
|
|
separated list of `key=value` pairs. The final part of the escape code is the
|
|
text which is simply plain text encoded as :ref:`safe_utf8`. Spaces in this
|
|
definition are for clarity only and should be ignored. The `terminator` is
|
|
either the byte `BEL (0x7)` or the bytes `ESC ST (0x1b 0x5c)`.
|
|
|
|
There are only a handful of metadata keys, defined in the table below:
|
|
|
|
|
|
.. csv-table:: The text sizing metadata keys
|
|
:header: "Key", "Value", "Default", "Description"
|
|
|
|
"s", "Integer from 1 to 7", "1", "The overall scale, the text will be rendered in a block of `s * w` by `s` cells"
|
|
|
|
"w", "Integer from 0 to 7", "0", "The width, in cells, in which the text should be rendered. When zero, the terminal should calculate the width as it would for normal text."
|
|
|
|
"n", "Integer from 0 to 15", "0", "The numerator for the fractional scale."
|
|
|
|
"d", "Integer from 0 to 15", "0", "The denominator for the fractional scale. Must be `> n` when non-zero."
|
|
|
|
"v", "Integer from 0 to 2", "0", "The vertical alignment to use for fractionally scaled text. `0` - top, `1` - bottom, `2` - centered"
|
|
|
|
|
|
How it works
|
|
------------------
|
|
|
|
This protocol works by allowing the client program to tell the terminal to
|
|
render text in multiple cells. The terminal can then adjust the actual font
|
|
size used to render the specified text as appropriate for the specified space.
|
|
|
|
The space to render is controlled by four metadata keys, `s (scale)`, `w (width)`, `n (numerator)`
|
|
and `d (denominator)`. The most important are the `s` and `w` keys. The text
|
|
will be rendered in a block of `s * w` by `s` cells. A special case is `w=0`
|
|
(the default), which means the terminal splits up the text into cells as it
|
|
would normally without this protocol, but now each cell is an `s by s` block of
|
|
cells instead. So, for example, if the text is `abc` and `s=2` the terminal would normally
|
|
split it into three cells::
|
|
|
|
│a│b│c│
|
|
|
|
But, because `s=2` it instead gets split as::
|
|
|
|
│a░│b░│c░│
|
|
│░░│░░│░░│
|
|
|
|
The terminal multiplies the font size by `s` when rendering these
|
|
characters and thus ends up rendering text at twice the base size.
|
|
|
|
|
|
Fractional scaling
|
|
^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
Using the main scale parameter (`s`) gives us only 7 font sizes. Fortunately,
|
|
this protocol allows specifying fractional scaling, fractional scaling is
|
|
applied on top of the main scale specified by `s`. It allows niceties like:
|
|
|
|
* Normal sized text but with half a line of blank space above and half a line below (`s=2:n=1:d=2:v=2`)
|
|
* Superscripts (`n=1:d=2`)
|
|
* Subscripts (`n=1:d=2:v=1`)
|
|
* ...
|
|
|
|
The fraction is specified using an integer numerator and denominator (`n` and
|
|
`d`). In addition, by using the `v` key one can vertically align the
|
|
fractionally scaled text at top, bottom or middle.
|
|
|
|
When using fractional scaling one often wants to fit more than a single
|
|
character per cell. To accommodate that, there is the `w` key. This specifies
|
|
the number of cells in which to render the text. For example, for a superscript
|
|
one would typically split the string into pairs of characters and use the
|
|
following for each pair::
|
|
|
|
OSC _text_size_code ; n=1:d=2:w=1 ; ab <terminator>
|
|
... repeat for each pair of characters
|
|
|