OpenTUI 0.6.2

npmGitHub release

In 0.6.1, editors started to show control characters as notation. As a result, an editor offset is no longer the same as a JavaScript string width. The string "\f" has a width of 0, but the editor shows it as ^L in two cells. EditBuffer.measureText() gives the correct offset, but only for a buffer you already have. To get the offset of text that was not in an editor yet, code had to create an EditBuffer only to measure that text.

In 0.6.2, measureEditText() measures text without a buffer. It returns the same value as measureText() on an edit buffer with the same width method and tab width. Pass the settings of the editor that will hold the text. Textarea and Input use the renderer’s width method and the default tab width, which is 2:

import { createCliRenderer, measureEditText } from "@opentui/core"

const renderer = await createCliRenderer()
measureEditText("\f@file", { widthMethod: renderer.widthMethod }) // 7: ^L takes two cells
measureEditText("a\tb", { widthMethod: renderer.widthMethod, tabWidth: 4 }) // 6

C programs get the same measurement from ot_edit_measure_text(). It takes a context, but no edit buffer handle.

Added

  • core: measureEditText(text, { widthMethod, tabWidth }) returns the editor offset at the end of text without an EditBuffer. tabWidth defaults to the tab width of a new edit buffer. See Editing buffers and views. (3ab0b954a)
  • native: ot_edit_measure_text() gives the same measurement through the C interface. A tab_width over 255 fails. See Editing buffers and views. (3ab0b954a)

Fixed

  • native: A bold, dim, italic, underlined, blinking, inverse, hidden, or struck-through cell in the last column of a row no longer gives its attributes to the next cells that the renderer draws. A row that ends in such a cell writes 4 more bytes. See Frames and output. (#1652)
  • native: If you type an emoji with a skin-tone modifier, a ZWJ sequence, Hangul jamo, or U+FE0F in an editor, the editor now stores its correct width. Before, 👍🏽 took 4 cells instead of 2, so the cursor, wrapping, selection, and Right key were wrong. See Textarea. (#1650)
  • native: A combining mark that starts a new text chunk now draws on the character before it, for example U+0301 typed after abc in an editor or added with TextBuffer.append. The renderer drops a mark that would make a 1-cell character 2 cells wide, such as U+FE0F. See Text and terminal cells. (#1651)
  • native: An embedded terminal redraws all rows when the child changes the default foreground or background color (OSC 10, 11, 110, or 111) or sets reverse video on or off (CSI ? 5 h or CSI ? 5 l). Before, rows on the screen kept the old colors. See Embedded terminal. (#1649)
  • core: If the host terminal uses the Kitty keyboard protocol, an embedded terminal now sends keypad Enter, keypad navigation, lock, Print Screen, Pause, and left and right modifier keys to the child. Keypad digits reach a Kitty child as keypad keys, and Ctrl+keypad 0 no longer arrives as a bare 0. See Embedded terminal. (#1648)
  • core: parseKeypress() no longer changes the caller’s Buffer when it decodes a single byte above 127 as a meta key. The input parser of the renderer did not have this problem. See Keyboard input. (#1653)

API changes#

@opentui/core#

Added

  • function measureEditText(text: string, options: { widthMethod: WidthMethod; tabWidth?: number; }): number
  • method FFIRenderLib.editMeasureText(bytes: Uint8Array, widthMethod: WidthMethod, tabWidth: number): number

opentui.h#

Added

  • function ot_edit_measure_text(ot_context *, const uint8_t *bytes, uint32_t byte_count, uint32_t width_method, uint32_t tab_width, uint32_t *out_width): ot_status