From f1452a80dd0f21e0d4bb31b4b3b6f15382f1f792 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 15 Jan 2025 17:07:09 +0530 Subject: [PATCH] More work on text sizing docs --- docs/conf.py | 3 +- docs/desktop-notifications.rst | 2 +- docs/text-sizing-protocol.rst | 66 ++++++++++++++++++++++++++++++++-- kitty/options/definition.py | 5 +-- kitty/screen.c | 6 ++-- 5 files changed, 74 insertions(+), 8 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index c36e7fdff..fa41dda92 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -29,7 +29,7 @@ if kitty_src not in sys.path: 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 ----------------------------------------------------- @@ -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), } diff --git a/docs/desktop-notifications.rst b/docs/desktop-notifications.rst index b893e324c..8eea60d02 100644 --- a/docs/desktop-notifications.rst +++ b/docs/desktop-notifications.rst @@ -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. diff --git a/docs/text-sizing-protocol.rst b/docs/text-sizing-protocol.rst index ba5425aa1..103049820 100644 --- a/docs/text-sizing-protocol.rst +++ b/docs/text-sizing-protocol.rst @@ -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 @@ -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:: + + _text_size_code ; metadata ; text + +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. diff --git a/kitty/options/definition.py b/kitty/options/definition.py index cddfd42fa..d747bdb9b 100644 --- a/kitty/options/definition.py +++ b/kitty/options/definition.py @@ -225,8 +225,9 @@ By default kitty renders gaps in underlines when they overlap with descenders (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. ''') diff --git a/kitty/screen.c b/kitty/screen.c index 7570e4c9f..f45b02b1f 100644 --- a/kitty/screen.c +++ b/kitty/screen.c @@ -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);