jeopi-tui 16.2.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/CHANGELOG.md +1861 -0
  2. package/README.md +705 -0
  3. package/dist/types/autocomplete.d.ts +99 -0
  4. package/dist/types/bracketed-paste.d.ts +51 -0
  5. package/dist/types/components/box.d.ts +31 -0
  6. package/dist/types/components/cancellable-loader.d.ts +21 -0
  7. package/dist/types/components/editor.d.ts +155 -0
  8. package/dist/types/components/image.d.ts +112 -0
  9. package/dist/types/components/input.d.ts +23 -0
  10. package/dist/types/components/loader.d.ts +20 -0
  11. package/dist/types/components/markdown.d.ts +64 -0
  12. package/dist/types/components/scroll-view.d.ts +62 -0
  13. package/dist/types/components/select-list.d.ts +68 -0
  14. package/dist/types/components/settings-list.d.ts +123 -0
  15. package/dist/types/components/spacer.d.ts +11 -0
  16. package/dist/types/components/tab-bar.d.ts +89 -0
  17. package/dist/types/components/text.d.ts +14 -0
  18. package/dist/types/components/truncated-text.d.ts +10 -0
  19. package/dist/types/deccara.d.ts +49 -0
  20. package/dist/types/desktop-notify.d.ts +51 -0
  21. package/dist/types/editor-component.d.ts +38 -0
  22. package/dist/types/fuzzy.d.ts +32 -0
  23. package/dist/types/index.d.ts +32 -0
  24. package/dist/types/keybindings.d.ts +191 -0
  25. package/dist/types/keys.d.ts +208 -0
  26. package/dist/types/kill-ring.d.ts +20 -0
  27. package/dist/types/kitty-graphics.d.ts +79 -0
  28. package/dist/types/latex-block.d.ts +7 -0
  29. package/dist/types/latex-to-unicode.d.ts +33 -0
  30. package/dist/types/loop-watchdog.d.ts +39 -0
  31. package/dist/types/mouse.d.ts +67 -0
  32. package/dist/types/stdin-buffer.d.ts +60 -0
  33. package/dist/types/symbols.d.ts +25 -0
  34. package/dist/types/terminal-capabilities.d.ts +284 -0
  35. package/dist/types/terminal.d.ts +107 -0
  36. package/dist/types/ttyid.d.ts +9 -0
  37. package/dist/types/tui.d.ts +423 -0
  38. package/dist/types/utils.d.ts +95 -0
  39. package/package.json +73 -0
  40. package/src/autocomplete.ts +1026 -0
  41. package/src/bracketed-paste.ts +123 -0
  42. package/src/components/box.ts +194 -0
  43. package/src/components/cancellable-loader.ts +40 -0
  44. package/src/components/editor.ts +3092 -0
  45. package/src/components/image.ts +444 -0
  46. package/src/components/input.ts +474 -0
  47. package/src/components/loader.ts +103 -0
  48. package/src/components/markdown.ts +2068 -0
  49. package/src/components/scroll-view.ts +227 -0
  50. package/src/components/select-list.ts +531 -0
  51. package/src/components/settings-list.ts +793 -0
  52. package/src/components/spacer.ts +32 -0
  53. package/src/components/tab-bar.ts +300 -0
  54. package/src/components/text.ts +122 -0
  55. package/src/components/truncated-text.ts +69 -0
  56. package/src/deccara.ts +314 -0
  57. package/src/desktop-notify.ts +186 -0
  58. package/src/editor-component.ts +74 -0
  59. package/src/fuzzy.ts +356 -0
  60. package/src/index.ts +51 -0
  61. package/src/keybindings.ts +337 -0
  62. package/src/keys.ts +561 -0
  63. package/src/kill-ring.ts +51 -0
  64. package/src/kitty-graphics.ts +171 -0
  65. package/src/latex-block.ts +461 -0
  66. package/src/latex-to-unicode.ts +1994 -0
  67. package/src/loop-watchdog.ts +106 -0
  68. package/src/mouse.ts +105 -0
  69. package/src/stdin-buffer.ts +669 -0
  70. package/src/symbols.ts +26 -0
  71. package/src/terminal-capabilities.ts +1152 -0
  72. package/src/terminal.ts +1463 -0
  73. package/src/ttyid.ts +84 -0
  74. package/src/tui.ts +3901 -0
  75. package/src/utils.ts +570 -0
@@ -0,0 +1,68 @@
1
+ import { type MouseRoutable, type SgrMouseEvent } from "../mouse";
2
+ import type { SymbolTheme } from "../symbols";
3
+ import type { Component } from "../tui";
4
+ export interface SelectItem {
5
+ value: string;
6
+ label: string;
7
+ description?: string;
8
+ /** Dim hint text shown inline after cursor when this item is selected */
9
+ hint?: string;
10
+ }
11
+ export interface SelectListTheme {
12
+ selectedPrefix: (text: string) => string;
13
+ selectedText: (text: string) => string;
14
+ description: (text: string) => string;
15
+ scrollInfo: (text: string) => string;
16
+ noMatch: (text: string) => string;
17
+ symbols: SymbolTheme;
18
+ /** Hover band applied to the full row under the mouse pointer. */
19
+ hovered?: (text: string) => string;
20
+ }
21
+ export interface SelectListTruncatePrimaryContext {
22
+ text: string;
23
+ maxWidth: number;
24
+ columnWidth: number;
25
+ item: SelectItem;
26
+ isSelected: boolean;
27
+ }
28
+ export interface SelectListLayoutOptions {
29
+ minPrimaryColumnWidth?: number;
30
+ maxPrimaryColumnWidth?: number;
31
+ truncatePrimary?: (context: SelectListTruncatePrimaryContext) => string;
32
+ /** Enable type-to-filter search when the item count exceeds maxVisible. Defaults to true. */
33
+ overflowSearch?: boolean;
34
+ /**
35
+ * Wrap long descriptions onto continuation rows indented under the
36
+ * description column instead of truncating. Defaults to false so existing
37
+ * single-line consumers are unaffected. Navigation remains item-to-item;
38
+ * the scrollbar tracks visual rows so the thumb stays correct when items
39
+ * wrap unevenly.
40
+ */
41
+ wrapDescription?: boolean;
42
+ }
43
+ export declare class SelectList implements Component, MouseRoutable {
44
+ #private;
45
+ private readonly items;
46
+ private readonly maxVisible;
47
+ private readonly theme;
48
+ private readonly layout;
49
+ onSelect?: (item: SelectItem) => void;
50
+ onCancel?: () => void;
51
+ onSelectionChange?: (item: SelectItem) => void;
52
+ constructor(items: ReadonlyArray<SelectItem>, maxVisible: number, theme: SelectListTheme, layout?: SelectListLayoutOptions);
53
+ setFilter(filter: string): void;
54
+ setSelectedIndex(index: number): void;
55
+ /** Resolve a 0-based rendered-line index to a filtered-item index. */
56
+ hitTest(line: number): number | undefined;
57
+ /** Highlight the item under the pointer (null clears). */
58
+ setHoverIndex(index: number | null): void;
59
+ /** Move the selection one step for a wheel notch. */
60
+ handleWheel(delta: -1 | 1): void;
61
+ /** Mouse click: select the item under the pointer and confirm it. */
62
+ clickItem(index: number): void;
63
+ routeMouse(event: SgrMouseEvent, line: number, _col: number): void;
64
+ invalidate(): void;
65
+ render(width: number): readonly string[];
66
+ handleInput(keyData: string): void;
67
+ getSelectedItem(): SelectItem | null;
68
+ }
@@ -0,0 +1,123 @@
1
+ import type { SgrMouseEvent } from "../mouse";
2
+ import type { Component } from "../tui";
3
+ export interface SettingItem {
4
+ /** Unique identifier for this setting */
5
+ id: string;
6
+ /** Display label (left side) */
7
+ label: string;
8
+ /** Optional description shown when selected */
9
+ description?: string;
10
+ /** Current value to display (right side) */
11
+ currentValue: string;
12
+ /** If provided, Enter/Space cycles through these values */
13
+ values?: string[];
14
+ /** If provided, Enter opens this submenu. Receives current value and done callback. */
15
+ submenu?: (currentValue: string, done: (selectedValue?: string) => void) => Component;
16
+ /** True when the displayed setting differs from its default value. */
17
+ changed?: boolean;
18
+ /** Render as a non-interactive section heading. Skipped by navigation and search. */
19
+ heading?: boolean;
20
+ }
21
+ export interface SettingsListTheme {
22
+ label: (text: string, selected: boolean, changed: boolean) => string;
23
+ value: (text: string, selected: boolean, changed: boolean) => string;
24
+ description: (text: string) => string;
25
+ cursor: string;
26
+ hint: (text: string) => string;
27
+ /** Style for section heading rows (dimmed when outside the active section). Falls back to `hint` when omitted. */
28
+ heading?: (text: string, dimmed: boolean) => string;
29
+ /** Style for sidebar section names in the split layout. Falls back to label/hint. */
30
+ section?: (text: string, active: boolean) => string;
31
+ /** Hover band applied to the full row under the mouse pointer. */
32
+ hovered?: (text: string) => string;
33
+ }
34
+ /** Optional behavior overrides for {@link SettingsList}. */
35
+ export interface SettingsListOptions {
36
+ /**
37
+ * "auto" (default) renders the section sidebar layout when headings exist
38
+ * and the width allows; "flat" always renders inline heading rows.
39
+ */
40
+ layout?: "auto" | "flat";
41
+ /**
42
+ * When false, printable input is ignored (no internal type-to-filter) and
43
+ * the search status line is never rendered. Use when a parent component
44
+ * owns the query. Default true.
45
+ */
46
+ typeToSearch?: boolean;
47
+ /** Text shown when the list has no items at all. */
48
+ emptyText?: string;
49
+ /**
50
+ * Footer hint line (hint-styled, replaces the default navigation hint).
51
+ * An empty string removes the hint row and its leading blank entirely —
52
+ * use when the host renders its own footer.
53
+ */
54
+ hint?: string;
55
+ /** Fixed split-sidebar width (columns incl. indent+gap); default derives from section names. */
56
+ sidebarWidth?: number;
57
+ }
58
+ /** Searchable text for a setting item: label, id, value, description, and cycle values. */
59
+ export declare function getSettingItemFilterText(item: SettingItem): string;
60
+ export declare class SettingsList implements Component {
61
+ #private;
62
+ /** Fired when the selected item changes (navigation, filtering, or setItems). */
63
+ onSelectionChange?: (item: SettingItem | undefined) => void;
64
+ constructor(items: SettingItem[], maxVisible: number, theme: SettingsListTheme, onChange: (id: string, newValue: string) => void, onCancel: () => void, options?: SettingsListOptions);
65
+ /** The currently selected item, or undefined when empty or on a heading. */
66
+ getSelectedItem(): SettingItem | undefined;
67
+ /** Move selection to the item with `id`. Returns false when it is not visible. */
68
+ selectItem(id: string): boolean;
69
+ /** True while keyboard focus is on the section headings instead of the setting rows. */
70
+ get sectionFocused(): boolean;
71
+ /** Whether section focus has anywhere to go: 2+ derived sections in the current view. */
72
+ hasSectionFocusTargets(): boolean;
73
+ /**
74
+ * Toggle keyboard focus between section headings and setting rows. While
75
+ * focused, Up/Down jump whole sections and Enter/Esc return to the rows.
76
+ * Engages only when {@link hasSectionFocusTargets}; returns the new state.
77
+ */
78
+ toggleSectionFocus(): boolean;
79
+ /** True while an item submenu owns input. */
80
+ hasOpenSubmenu(): boolean;
81
+ /** Resize the visible viewport (fullscreen hosts call this every render). */
82
+ setMaxVisible(rows: number): void;
83
+ /** Move the selection one step for a wheel notch. */
84
+ handleWheel(delta: -1 | 1): void;
85
+ /** Move the selection one step for a wheel notch if the pointer is within the settings pane. */
86
+ handleWheelAt(delta: -1 | 1, _line: number, col: number): boolean;
87
+ /** Highlight the item under the pointer (null clears). */
88
+ setHoverItem(id: string | null): void;
89
+ /**
90
+ * Resolve a pointer position against the last rendered frame. `line` is the
91
+ * 0-based content-line index within this component's render output, `col`
92
+ * the 0-based column. Sidebar rows resolve to the section's first item.
93
+ */
94
+ hitTest(line: number, col: number): string | undefined;
95
+ /**
96
+ * Like {@link hitTest}, but only rows the pointer is visually on: sidebar
97
+ * jump targets are excluded so hovering section names does not light up
98
+ * pane rows.
99
+ */
100
+ hoverTest(line: number, col: number): string | undefined;
101
+ /**
102
+ * Route a mouse event into an open submenu (coordinates are local to this
103
+ * list's rendered lines). Returns false when no submenu is open; submenus
104
+ * that do not implement {@link MouseRoutable} consume the event silently.
105
+ */
106
+ routeSubmenuMouse(event: SgrMouseEvent, line: number, col: number): boolean;
107
+ getSearchQuery(): string;
108
+ hasSearchQuery(): boolean;
109
+ clearSearch(): void;
110
+ /** Update an item's currentValue */
111
+ updateValue(id: string, newValue: string): void;
112
+ /**
113
+ * Replace the entire items array. Selection is preserved by item id when
114
+ * the previous selection still survives the active filter, otherwise
115
+ * clamped to the last filtered item (or 0 if there are no matches).
116
+ * An open submenu is left untouched — its lifetime is bounded by its own
117
+ * done callback, and `#closeSubmenu` re-resolves the restored item on exit.
118
+ */
119
+ setItems(items: SettingItem[]): void;
120
+ invalidate(): void;
121
+ render(width: number): readonly string[];
122
+ handleInput(data: string): void;
123
+ }
@@ -0,0 +1,11 @@
1
+ import type { Component } from "../tui";
2
+ /**
3
+ * Spacer component that renders empty lines
4
+ */
5
+ export declare class Spacer implements Component {
6
+ #private;
7
+ constructor(lines?: number);
8
+ setLines(lines: number): void;
9
+ invalidate(): void;
10
+ render(_width: number): readonly string[];
11
+ }
@@ -0,0 +1,89 @@
1
+ import type { Component } from "../tui";
2
+ /** Tab definition */
3
+ export interface Tab {
4
+ /** Unique identifier for the tab */
5
+ id: string;
6
+ /** Display label shown in the tab bar */
7
+ label: string;
8
+ /** Compact form (e.g. just the icon) used when the bar must shrink to fit one line. */
9
+ short?: string;
10
+ /** Render with the muted style and skip during keyboard navigation. */
11
+ muted?: boolean;
12
+ }
13
+ /** Theme for styling the tab bar */
14
+ export interface TabBarTheme {
15
+ /** Style for the label prefix (e.g., "Settings:") */
16
+ label: (text: string) => string;
17
+ /** Style for the currently active tab */
18
+ activeTab: (text: string) => string;
19
+ /** Style for inactive tabs */
20
+ inactiveTab: (text: string) => string;
21
+ /** Style for the hint text (e.g., "(tab to cycle)") */
22
+ hint: (text: string) => string;
23
+ /** Style for muted tabs. Falls back to `inactiveTab` when omitted. */
24
+ mutedTab?: (text: string) => string;
25
+ /** Style for the tab under the mouse pointer. Falls back to `inactiveTab` when omitted. */
26
+ hoverTab?: (text: string) => string;
27
+ }
28
+ /**
29
+ * Horizontal tab bar component.
30
+ *
31
+ * @example
32
+ * ```ts
33
+ * const tabs = [
34
+ * { id: "config", label: "Config" },
35
+ * { id: "tools", label: "Tools" },
36
+ * ];
37
+ * const tabBar = new TabBar("Settings", tabs, theme);
38
+ * tabBar.onTabChange = (tab) => console.log(`Switched to ${tab.id}`);
39
+ * ```
40
+ */
41
+ export declare class TabBar implements Component {
42
+ #private;
43
+ /** Callback fired when the active tab changes */
44
+ onTabChange?: (tab: Tab, index: number) => void;
45
+ /** Render the trailing "(tab to cycle)" hint. Disable when the host folds the hint into its own footer. */
46
+ showHint: boolean;
47
+ constructor(label: string, tabs: Tab[], theme: TabBarTheme, initialIndex?: number);
48
+ /** Get the currently active tab */
49
+ getActiveTab(): Tab;
50
+ /** Get the index of the currently active tab */
51
+ getActiveIndex(): number;
52
+ /** Set the active tab by index (clamped to valid range) */
53
+ setActiveIndex(index: number): void;
54
+ /**
55
+ * Replace the tab set without firing onTabChange. The active tab is
56
+ * preserved by id when it survives the swap (or forced via `activeId`);
57
+ * otherwise the index is clamped.
58
+ */
59
+ setTabs(tabs: Tab[], activeId?: string): void;
60
+ /** Set the active tab by id without firing onTabChange. Returns false when the id is unknown. */
61
+ setActiveById(id: string): boolean;
62
+ /** Activate the tab with `id`, firing onTabChange when it changes. Muted tabs are ignored. */
63
+ selectTab(id: string): boolean;
64
+ /** Move to the next non-muted tab (wraps to first tab after last) */
65
+ nextTab(): void;
66
+ /** Move to the previous non-muted tab (wraps to last tab before first) */
67
+ prevTab(): void;
68
+ invalidate(): void;
69
+ /**
70
+ * Handle keyboard input for tab navigation.
71
+ * @returns true if the input was handled, false otherwise
72
+ */
73
+ handleInput(data: string): boolean;
74
+ /**
75
+ * Render the tab bar. When the full labels overflow the width, tabs are
76
+ * collapsed to their `short` form one by one — starting with the tabs
77
+ * farthest from the active one — until the bar fits on a single line.
78
+ * Wrapping to multiple lines is the last resort.
79
+ */
80
+ render(width: number): readonly string[];
81
+ /**
82
+ * Resolve a pointer position against the last rendered frame. `line` is the
83
+ * 0-based line index within this component's render output, `col` the
84
+ * 0-based column.
85
+ */
86
+ tabAt(line: number, col: number): Tab | undefined;
87
+ /** Highlight the tab under the pointer (null clears). */
88
+ setHoverTab(id: string | null): void;
89
+ }
@@ -0,0 +1,14 @@
1
+ import type { Component } from "../tui";
2
+ /**
3
+ * Text component - displays multi-line text with word wrapping
4
+ */
5
+ export declare class Text implements Component {
6
+ #private;
7
+ setIgnoreTight(ignore: boolean): this;
8
+ constructor(text?: string, paddingX?: number, paddingY?: number, customBgFn?: (text: string) => string);
9
+ getText(): string;
10
+ setText(text: string): boolean;
11
+ setCustomBgFn(customBgFn?: (text: string) => string): void;
12
+ invalidate(): void;
13
+ render(width: number): readonly string[];
14
+ }
@@ -0,0 +1,10 @@
1
+ import type { Component } from "../tui";
2
+ /**
3
+ * Text component that truncates to fit viewport width
4
+ */
5
+ export declare class TruncatedText implements Component {
6
+ #private;
7
+ constructor(text: string, paddingX?: number, paddingY?: number);
8
+ invalidate(): void;
9
+ render(width: number): readonly string[];
10
+ }
@@ -0,0 +1,49 @@
1
+ /** DECSACE — select the rectangle change extent so DECCARA fills a rectangle. */
2
+ export declare const DECSACE_RECT = "\u001B[2*x";
3
+ /** DECSACE — restore the default (stream) change extent. */
4
+ export declare const DECSACE_DEFAULT = "\u001B[*x";
5
+ /**
6
+ * Encode a single DECCARA rectangle. `top`/`bottom` are 1-based inclusive screen
7
+ * rows, `left`/`right` 1-based inclusive columns, `sgr` the raw SGR parameter
8
+ * list to apply (e.g. `48;2;10;20;30`, `48;5;4`, `41`).
9
+ */
10
+ export declare function encodeDeccara(top: number, left: number, bottom: number, right: number, sgr: string): string;
11
+ /** Where to cut a fillable line and the background to paint over the remainder. */
12
+ export interface BgFillAnalysis {
13
+ /** Byte index where droppable trailing background padding begins (0 = whole line). */
14
+ cut: number;
15
+ /** 0-based column where the trailing padding begins (DECCARA left = leftCol + 1). */
16
+ leftCol: number;
17
+ /** SGR parameter list of the background covering the trailing region. */
18
+ bg: string;
19
+ }
20
+ /**
21
+ * Decide whether `line` (a final, width-fit, reset-terminated ANSI string) is a
22
+ * full-width background fill whose trailing padding can be replaced by a DECCARA
23
+ * rectangle. Returns `null` unless it can *prove* the dropped bytes are literal
24
+ * trailing spaces under a single, constant, non-default background span (or the
25
+ * entire row is background-styled spaces).
26
+ *
27
+ * Conservative by construction: any OSC sequence (hyperlinks/images), any
28
+ * non-SGR CSI, a partial row, an inconsistent or default trailing background, or
29
+ * a malformed escape all yield `null` so the caller keeps the exact original.
30
+ */
31
+ export declare function analyzeBgFillLine(line: string, width: number): BgFillAnalysis | null;
32
+ /** Per-frame plan: the (possibly shortened) row strings and the DECCARA batch. */
33
+ export interface DeccaraPlan {
34
+ /** Row strings to write, parallel to the input. Optimized rows are shortened. */
35
+ texts: string[];
36
+ /** DECSACE-wrapped rectangle batch to emit after the rows, or `""` if none. */
37
+ sequence: string;
38
+ }
39
+ /**
40
+ * Plan DECCARA rectangles for a contiguous block of visible rows.
41
+ *
42
+ * `lines[k]` is the final ANSI string for screen row `firstScreenRow + k`
43
+ * (0-based). For each fillable row the trailing background padding is removed
44
+ * (the row's cells are cleared/erased by the caller, then repainted by the
45
+ * rectangle), and vertically adjacent rows with an identical left/right/bg span
46
+ * coalesce into one rectangle. Rectangles are emitted only when they save more
47
+ * bytes than they cost, so the result never exceeds the original byte count.
48
+ */
49
+ export declare function planDeccaraFills(lines: string[], width: number, firstScreenRow?: number): DeccaraPlan;
@@ -0,0 +1,51 @@
1
+ import type { TerminalId, TerminalNotification } from "./terminal-capabilities";
2
+ /** Resolved notifier binary used to fan a notification out to D-Bus. */
3
+ export type DesktopNotifierKind = "notify-send" | "gdbus";
4
+ export interface DesktopNotifier {
5
+ kind: DesktopNotifierKind;
6
+ path: string;
7
+ }
8
+ /**
9
+ * Whether the current process can reach a freedesktop notification daemon:
10
+ * Linux platform + a session bus address in env. Caller is still responsible
11
+ * for resolving a delivery binary via {@link resolveDesktopNotifier}.
12
+ */
13
+ export declare function hasLinuxDesktopSession(platform?: NodeJS.Platform, env?: NodeJS.ProcessEnv): boolean;
14
+ /**
15
+ * Whether `sendNotification` should also dispatch a D-Bus toast for this
16
+ * terminal. Returns true only when (1) the chosen `notifyProtocol` is BEL,
17
+ * which cannot carry arbitrary toast text, (2) the host exposes a Linux desktop
18
+ * session, and (3) the user has not opted out via `PI_NO_DESKTOP_NOTIFY=1`.
19
+ * Terminals that genuinely speak OSC 9 / OSC 99 pass
20
+ * `notifyProtocolIsBell=false` and are filtered before the D-Bus fallback can
21
+ * run. Pure helper for tests and the singleton path.
22
+ */
23
+ export declare function shouldDeliverDesktopNotification(_terminalId: TerminalId, notifyProtocolIsBell: boolean, platform?: NodeJS.Platform, env?: NodeJS.ProcessEnv): boolean;
24
+ /** Reset the cached notifier resolution. Tests only. */
25
+ export declare function resetDesktopNotifierCache(): void;
26
+ /**
27
+ * Locate a libnotify-compatible delivery binary on `PATH`, preferring
28
+ * `notify-send` (one-shot, no marshalling) and falling back to `gdbus call`
29
+ * for hosts where libnotify is not installed but GLib is. Result is cached so
30
+ * repeated notifications do not hit `$which` again.
31
+ */
32
+ export declare function resolveDesktopNotifier(): DesktopNotifier | null;
33
+ /**
34
+ * Build the argv that delivers `message` through the resolved notifier. Pure
35
+ * helper so tests assert exact wire shape without spawning a child. Notes:
36
+ * - `notify-send` accepts title + body positionally and a numeric expire
37
+ * timeout (`-t`); urgency is a flag.
38
+ * - `gdbus call ... Notify` takes the freedesktop signature
39
+ * `s u s s s as a{sv} i`: app_name, replaces_id, app_icon, summary, body,
40
+ * actions, hints, expire_timeout. We feed hints with the urgency byte so
41
+ * the daemon classifies the toast identically to `notify-send`.
42
+ */
43
+ export declare function buildDesktopNotifyCommand(notifier: DesktopNotifier, message: string | TerminalNotification): string[];
44
+ /**
45
+ * Fire-and-forget D-Bus desktop notification. Resolves a notifier, spawns it
46
+ * with stdio fully detached, and never throws — terminal notifications are
47
+ * best-effort and must not block the renderer or interleave bytes onto
48
+ * stdout. Caller is responsible for the gating check
49
+ * ({@link shouldDeliverDesktopNotification}).
50
+ */
51
+ export declare function sendDesktopNotification(message: string | TerminalNotification): void;
@@ -0,0 +1,38 @@
1
+ import type { AutocompleteProvider } from "./autocomplete";
2
+ import type { Component } from "./tui";
3
+ /**
4
+ * Interface for custom editor components.
5
+ *
6
+ * This allows extensions to provide their own editor implementation
7
+ * (e.g., vim mode, emacs mode, custom keybindings) while maintaining
8
+ * compatibility with the core application.
9
+ */
10
+ export interface EditorComponent extends Component {
11
+ /** Get the current text content */
12
+ getText(): string;
13
+ /** Set the text content */
14
+ setText(text: string): void;
15
+ /** Handle raw terminal input (key presses, paste sequences, etc.) */
16
+ handleInput(data: string): void;
17
+ /** Called when user submits (e.g., Enter key) */
18
+ onSubmit?: (text: string) => void;
19
+ /** Programmatically trigger submission (optional, e.g. for voice submit). */
20
+ submit?(): void;
21
+ /** Called when text changes */
22
+ onChange?: (text: string) => void;
23
+ /** Add text to history for up/down navigation */
24
+ addToHistory?(text: string): void;
25
+ /** Insert text at current cursor position */
26
+ insertTextAtCursor?(text: string): void;
27
+ /**
28
+ * Get text with any markers expanded (e.g., paste markers).
29
+ * Falls back to getText() if not implemented.
30
+ */
31
+ getExpandedText?(): string;
32
+ /** Set the autocomplete provider */
33
+ setAutocompleteProvider?(provider: AutocompleteProvider): void;
34
+ /** Border color function */
35
+ borderColor?: (str: string) => string;
36
+ /** Set horizontal padding */
37
+ setPaddingX?(padding: number): void;
38
+ }
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Fuzzy matching utilities.
3
+ *
4
+ * Matching is deliberately word-local for normal words. This keeps a query like
5
+ * "image provider" from matching a long setting description only because the
6
+ * letters i-m-a-g-e appear somewhere in order across unrelated words.
7
+ *
8
+ * Lower score = better match.
9
+ */
10
+ export interface FuzzyMatch {
11
+ matches: boolean;
12
+ score: number;
13
+ }
14
+ export interface FuzzyFilterResult<T> {
15
+ item: T;
16
+ score: number;
17
+ }
18
+ export declare function fuzzyMatch(query: string, text: string): FuzzyMatch;
19
+ /**
20
+ * Filter and sort items by fuzzy match quality (best matches first).
21
+ * Supports space-separated tokens: all tokens must match.
22
+ */
23
+ export declare function fuzzyRank<T>(items: T[], query: string, getText: (item: T) => string): FuzzyFilterResult<T>[];
24
+ export declare function fuzzyFilter<T>(items: T[], query: string, getText: (item: T) => string): T[];
25
+ /**
26
+ * Clear the fuzzy search-index cache. Intended for tests/benchmarks so a fresh
27
+ * cold-start typing session can be measured on demand; not part of the supported
28
+ * TUI API.
29
+ *
30
+ * @internal
31
+ */
32
+ export declare function resetFuzzyIndexCache(): void;
@@ -0,0 +1,32 @@
1
+ export * from "./autocomplete";
2
+ export * from "./components/box";
3
+ export * from "./components/cancellable-loader";
4
+ export * from "./components/editor";
5
+ export * from "./components/image";
6
+ export * from "./components/input";
7
+ export * from "./components/loader";
8
+ export * from "./components/markdown";
9
+ export * from "./components/scroll-view";
10
+ export * from "./components/select-list";
11
+ export * from "./components/settings-list";
12
+ export * from "./components/spacer";
13
+ export * from "./components/tab-bar";
14
+ export * from "./components/text";
15
+ export * from "./components/truncated-text";
16
+ export * from "./deccara";
17
+ export * from "./desktop-notify";
18
+ export type * from "./editor-component";
19
+ export * from "./fuzzy";
20
+ export * from "./keybindings";
21
+ export * from "./keys";
22
+ export * from "./kitty-graphics";
23
+ export * from "./latex-block";
24
+ export * from "./latex-to-unicode";
25
+ export * from "./mouse";
26
+ export * from "./stdin-buffer";
27
+ export type * from "./symbols";
28
+ export * from "./terminal";
29
+ export * from "./terminal-capabilities";
30
+ export * from "./ttyid";
31
+ export * from "./tui";
32
+ export * from "./utils";