Skip to content

Commit

Permalink
More work on text sizing docs
Browse files Browse the repository at this point in the history
  • Loading branch information
kovidgoyal committed Jan 15, 2025
1 parent b67d9c4 commit 40882ef
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 8 deletions.
3 changes: 2 additions & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@

from kitty.conf.types import Definition, expand_opt_references # noqa
from kitty.constants import str_version, website_url # noqa
from kitty.fast_data_types import Shlex # noqa
from kitty.fast_data_types import Shlex, TEXT_SIZE_CODE # noqa

# config {{{
# -- Project information -----------------------------------------------------
Expand Down Expand Up @@ -119,6 +119,7 @@ def go_version(go_mod_path: str) -> str: # {{{
string_replacements = {
'_kitty_install_cmd': 'curl -L https://sw.kovidgoyal.net/kitty/installer.sh | sh /dev/stdin',
'_build_go_version': go_version('../go.mod'),
'_text_size_code': str(TEXT_SIZE_CODE),
}


Expand Down
2 changes: 1 addition & 1 deletion docs/desktop-notifications.rst
Original file line number Diff line number Diff line change
Expand Up @@ -527,7 +527,7 @@ Escape code safe UTF-8

This must be valid UTF-8 as per the spec in :rfc:`3629`. In addition, in order
to make it safe for transmission embedded inside an escape code, it must
contain none of the C0 and C1 control characters, that is, the unicode
contain none of the C0 and C1 control characters, that is, the Unicode
characters: U+0000 (NUL) - U+1F (Unit separator), U+7F (DEL) and U+80 (PAD) - U+9F
(APC). Note that in particular, this means that no newlines, carriage returns,
tabs, etc. are allowed.
Expand Down
66 changes: 64 additions & 2 deletions docs/text-sizing-protocol.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ 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
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
Expand All @@ -16,8 +16,70 @@ 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 grid based character cell fundamental nature of the
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 :code:`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."

"v", "Integer from 0 to 2", "0", "The vertical alignment to use for fractionally scaled text."


How it works
------------------

This protocol works by allowing the client program to tell the terminal
emulator 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.
5 changes: 3 additions & 2 deletions kitty/options/definition.py
Original file line number Diff line number Diff line change
Expand Up @@ -225,8 +225,9 @@
(the parts of letters below the baseline, such as for y, q, p etc.). This option
controls the thickness of the gaps. It can be either a unitless number in which
case it is a fraction of the underline thickness as specified in the font or
it can have a suffix of :code:`px` for pixels or :code:`pt` for points. Changing this
option dynamically via reloading the config or remote control is undefined.
it can have a suffix of :code:`px` for pixels or :code:`pt` for points. Set to zero
to disable the gaps. Changing this option dynamically via reloading the config or remote
control is undefined.
''')


Expand Down
6 changes: 4 additions & 2 deletions kitty/screen.c
Original file line number Diff line number Diff line change
Expand Up @@ -1236,11 +1236,13 @@ screen_handle_multicell_command(Screen *self, const MultiCellCommand *cmd, const
ensure_space_for_chars(self->lc, cmd->payload_sz + 1);
self->lc->count = decode_utf8_safe_string(payload, cmd->payload_sz, self->lc->chars);
if (!self->lc->count) return;
#define M(x) ( (1u << x) - 1u)
CPUCell mcd = {
.width=MIN(cmd->width, (WIDTH_BITS << 1) - 1), .scale=MAX(1u, MIN(cmd->scale, (SCALE_BITS << 1) - 1)),
.subscale_n=MIN(cmd->subscale_n, (SUBSCALE_BITS << 1) - 1), .subscale_d=MIN(cmd->subscale_d, (SUBSCALE_BITS << 1) - 1),
.width=MIN(cmd->width, M(WIDTH_BITS)), .scale=MAX(1u, MIN(cmd->scale, M(SCALE_BITS))),
.subscale_n=MIN(cmd->subscale_n, M(SUBSCALE_BITS)), .subscale_d=MIN(cmd->subscale_d, M(SUBSCALE_BITS)),
.vertical_align=MIN(cmd->vertical_align, 7u), .is_multicell=true
};
#undef M
if (mcd.width) handle_fixed_width_multicell_command(self, mcd, self->lc);
else {
RAII_ListOfChars(lc);
Expand Down

0 comments on commit 40882ef

Please sign in to comment.