Skip to main content

ghostty_web_umd_bindgen/
lib.rs

1//! `wasm-bindgen` bindings for the [`ghostty-web`](https://github.com/coder/ghostty-web) UMD global `GhosttyWeb`.
2//!
3//! Tries to mirror the definitions from `ghostty-web/dist/index.d.ts`.
4//! Created from the `ghostty-web` version `0.4.0`.
5
6#![allow(non_snake_case)]
7#![allow(clippy::too_many_arguments)]
8#![allow(clippy::new_without_default)]
9
10pub mod builders;
11
12use js_sys::Array;
13use js_sys::Boolean;
14use js_sys::Function;
15use js_sys::JsOption;
16use js_sys::JsString;
17use js_sys::Number;
18use js_sys::Object;
19use js_sys::Promise;
20use js_sys::Set;
21use js_sys::Uint8Array;
22use js_sys::Undefined;
23use js_sys::WebAssembly;
24pub use wasm_bindgen::JsGeneric;
25use wasm_bindgen::prelude::*;
26use web_sys::HtmlCanvasElement;
27use web_sys::HtmlElement;
28use web_sys::HtmlTextAreaElement;
29use web_sys::KeyboardEvent;
30use web_sys::MouseEvent;
31use web_sys::WheelEvent;
32
33/// Opaque terminal pointer (WASM memory address).
34pub type TerminalHandle = f64;
35
36/// `IEvent<T> = (listener: (arg: T) => void) => IDisposable`
37pub type IEvent<T> = Function<fn(Function<fn(T) -> Undefined>) -> IDisposable>;
38
39/// Void-payload event: `(listener: () => void) => IDisposable`
40pub type IEventVoid = Function<fn(Function<fn() -> Undefined>) -> IDisposable>;
41
42/// Cell style flags (bitfield)
43#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
44#[repr(transparent)]
45pub struct CellFlags(pub u32);
46
47impl CellFlags
48{
49    pub const BOLD: Self = Self(1);
50    pub const ITALIC: Self = Self(2);
51    pub const UNDERLINE: Self = Self(4);
52    pub const STRIKETHROUGH: Self = Self(8);
53    pub const INVERSE: Self = Self(16);
54    pub const INVISIBLE: Self = Self(32);
55    pub const BLINK: Self = Self(64);
56    pub const FAINT: Self = Self(128);
57
58    #[inline]
59    pub const fn bits(self) -> u32 { self.0 }
60
61    #[inline]
62    pub const fn contains(self, other: Self) -> bool { (self.0 & other.0) == other.0 }
63}
64
65impl core::ops::BitOr for CellFlags
66{
67    type Output = Self;
68    #[inline]
69    fn bitor(self, rhs: Self) -> Self { Self(self.0 | rhs.0) }
70}
71
72impl core::ops::BitAnd for CellFlags
73{
74    type Output = Self;
75    #[inline]
76    fn bitand(self, rhs: Self) -> Self { Self(self.0 & rhs.0) }
77}
78
79/// Dirty state from RenderState
80#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
81#[repr(u32)]
82pub enum DirtyState
83{
84    None = 0,
85    Partial = 1,
86    Full = 2,
87}
88
89impl DirtyState
90{
91    pub fn from_u32(value: u32) -> Self
92    {
93        match value
94        {
95            1 => Self::Partial,
96            2 => Self::Full,
97            _ => Self::None,
98        }
99    }
100}
101
102/// Key action
103#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
104#[repr(u32)]
105pub enum KeyAction
106{
107    Release = 0,
108    Press = 1,
109    Repeat = 2,
110}
111
112/// Key encoder options
113#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
114#[repr(u32)]
115pub enum KeyEncoderOption
116{
117    /// DEC mode 1
118    CursorKeyApplication = 0,
119    /// DEC mode 66
120    KeypadKeyApplication = 1,
121    /// DEC mode 1035
122    IgnoreKeypadWithNumlock = 2,
123    /// DEC mode 1036
124    AltEscPrefix = 3,
125    /// xterm modifyOtherKeys
126    ModifyOtherKeysState2 = 4,
127    KittyKeyboardFlags = 5,
128}
129
130/// Kitty keyboard protocol flags
131///
132/// From `include/ghostty/vt/key/encoder.h`
133#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
134#[repr(transparent)]
135pub struct KittyKeyFlags(pub u32);
136
137impl KittyKeyFlags
138{
139    pub const DISABLED: Self = Self(0);
140    /// Disambiguate escape codes
141    pub const DISAMBIGUATE: Self = Self(1);
142    /// Report press and release
143    pub const REPORT_EVENTS: Self = Self(2);
144    /// Report alternate key codes
145    pub const REPORT_ALTERNATES: Self = Self(4);
146    /// Report all events
147    pub const REPORT_ALL: Self = Self(8);
148    /// Report associated text
149    pub const REPORT_ASSOCIATED: Self = Self(16);
150    pub const ALL: Self = Self(31);
151
152    #[inline]
153    pub const fn bits(self) -> u32 { self.0 }
154}
155
156impl core::ops::BitOr for KittyKeyFlags
157{
158    type Output = Self;
159    #[inline]
160    fn bitor(self, rhs: Self) -> Self { Self(self.0 | rhs.0) }
161}
162
163/// Modifier keys
164#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
165#[repr(transparent)]
166pub struct Mods(pub u32);
167
168impl Mods
169{
170    pub const NONE: Self = Self(0);
171    pub const SHIFT: Self = Self(1);
172    pub const CTRL: Self = Self(2);
173    pub const ALT: Self = Self(4);
174    /// Windows/Command key
175    pub const SUPER: Self = Self(8);
176    pub const CAPSLOCK: Self = Self(16);
177    pub const NUMLOCK: Self = Self(32);
178
179    #[inline]
180    pub const fn bits(self) -> u32 { self.0 }
181
182    #[inline]
183    pub const fn contains(self, other: Self) -> bool { (self.0 & other.0) == other.0 }
184}
185
186impl core::ops::BitOr for Mods
187{
188    type Output = Self;
189    #[inline]
190    fn bitor(self, rhs: Self) -> Self { Self(self.0 | rhs.0) }
191}
192
193impl core::ops::BitAnd for Mods
194{
195    type Output = Self;
196    #[inline]
197    fn bitand(self, rhs: Self) -> Self { Self(self.0 & rhs.0) }
198}
199
200/// Physical key codes matching Ghostty's internal Key enum.
201///
202/// These values are used by Ghostty's key encoder to produce correct escape
203/// sequences. Reference: `ghostty/src/input/key.zig`
204#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
205#[repr(u32)]
206pub enum Key
207{
208    Unidentified = 0,
209    /// `` ` `` and `~`
210    Grave = 1,
211    /// `\` and `|`
212    Backslash = 2,
213    /// `[` and `{`
214    BracketLeft = 3,
215    /// `]` and `}`
216    BracketRight = 4,
217    /// `,` and `<`
218    Comma = 5,
219    Zero = 6,
220    One = 7,
221    Two = 8,
222    Three = 9,
223    Four = 10,
224    Five = 11,
225    Six = 12,
226    Seven = 13,
227    Eight = 14,
228    Nine = 15,
229    /// `=` and `+`
230    Equal = 16,
231    IntlBackslash = 17,
232    IntlRo = 18,
233    IntlYen = 19,
234    A = 20,
235    B = 21,
236    C = 22,
237    D = 23,
238    E = 24,
239    F = 25,
240    G = 26,
241    H = 27,
242    I = 28,
243    J = 29,
244    K = 30,
245    L = 31,
246    M = 32,
247    N = 33,
248    O = 34,
249    P = 35,
250    Q = 36,
251    R = 37,
252    S = 38,
253    T = 39,
254    U = 40,
255    V = 41,
256    W = 42,
257    X = 43,
258    Y = 44,
259    Z = 45,
260    /// `-` and `_`
261    Minus = 46,
262    /// `.` and `>`
263    Period = 47,
264    /// `'` and `"`
265    Quote = 48,
266    /// `;` and `:`
267    Semicolon = 49,
268    /// `/` and `?`
269    Slash = 50,
270    AltLeft = 51,
271    AltRight = 52,
272    Backspace = 53,
273    CapsLock = 54,
274    ContextMenu = 55,
275    ControlLeft = 56,
276    ControlRight = 57,
277    Enter = 58,
278    MetaLeft = 59,
279    MetaRight = 60,
280    ShiftLeft = 61,
281    ShiftRight = 62,
282    Space = 63,
283    Tab = 64,
284    Convert = 65,
285    KanaMode = 66,
286    NonConvert = 67,
287    Delete = 68,
288    End = 69,
289    Help = 70,
290    Home = 71,
291    Insert = 72,
292    PageDown = 73,
293    PageUp = 74,
294    Down = 75,
295    Left = 76,
296    Right = 77,
297    Up = 78,
298    NumLock = 79,
299    Kp0 = 80,
300    Kp1 = 81,
301    Kp2 = 82,
302    Kp3 = 83,
303    Kp4 = 84,
304    Kp5 = 85,
305    Kp6 = 86,
306    Kp7 = 87,
307    Kp8 = 88,
308    Kp9 = 89,
309    /// Keypad `+`
310    KpPlus = 90,
311    KpBackspace = 91,
312    KpClear = 92,
313    KpClearEntry = 93,
314    KpComma = 94,
315    /// Keypad `.`
316    KpPeriod = 95,
317    /// Keypad `/`
318    KpDivide = 96,
319    /// Keypad Enter
320    KpEnter = 97,
321    KpEqual = 98,
322    KpMemoryAdd = 99,
323    KpMemoryClear = 100,
324    KpMemoryRecall = 101,
325    KpMemoryStore = 102,
326    KpMemorySubtract = 103,
327    /// Keypad `*`
328    KpMultiply = 104,
329    KpParenLeft = 105,
330    KpParenRight = 106,
331    /// Keypad `-`
332    KpMinus = 107,
333    KpSeparator = 108,
334    NumpadUp = 109,
335    NumpadDown = 110,
336    NumpadRight = 111,
337    NumpadLeft = 112,
338    NumpadBegin = 113,
339    NumpadHome = 114,
340    NumpadEnd = 115,
341    NumpadInsert = 116,
342    NumpadDelete = 117,
343    NumpadPageUp = 118,
344    NumpadPageDown = 119,
345    Escape = 120,
346    F1 = 121,
347    F2 = 122,
348    F3 = 123,
349    F4 = 124,
350    F5 = 125,
351    F6 = 126,
352    F7 = 127,
353    F8 = 128,
354    F9 = 129,
355    F10 = 130,
356    F11 = 131,
357    F12 = 132,
358    F13 = 133,
359    F14 = 134,
360    F15 = 135,
361    F16 = 136,
362    F17 = 137,
363    F18 = 138,
364    F19 = 139,
365    F20 = 140,
366    F21 = 141,
367    F22 = 142,
368    F23 = 143,
369    F24 = 144,
370    F25 = 145,
371    FnLock = 146,
372    PrintScreen = 147,
373    ScrollLock = 148,
374    Pause = 149,
375    BrowserBack = 150,
376    BrowserFavorites = 151,
377    BrowserForward = 152,
378    BrowserHome = 153,
379    BrowserRefresh = 154,
380    BrowserSearch = 155,
381    BrowserStop = 156,
382    Eject = 157,
383    LaunchApp1 = 158,
384    LaunchApp2 = 159,
385    LaunchMail = 160,
386    MediaPlayPause = 161,
387    MediaSelect = 162,
388    MediaStop = 163,
389    MediaTrackNext = 164,
390    MediaTrackPrevious = 165,
391    Power = 166,
392    Sleep = 167,
393    AudioVolumeDown = 168,
394    AudioVolumeMute = 169,
395    AudioVolumeUp = 170,
396    WakeUp = 171,
397    Copy = 172,
398    Cut = 173,
399    Paste = 174,
400}
401
402#[wasm_bindgen]
403extern "C" {
404    #[wasm_bindgen(extends = Object)]
405    #[derive(Clone, Debug)]
406    pub type ITheme;
407
408    #[wasm_bindgen(method, setter, js_name = foreground)]
409    pub fn set_foreground(this: &ITheme, value: &str);
410    #[wasm_bindgen(method, setter, js_name = background)]
411    pub fn set_background(this: &ITheme, value: &str);
412    #[wasm_bindgen(method, setter, js_name = cursor)]
413    pub fn set_cursor(this: &ITheme, value: &str);
414    #[wasm_bindgen(method, setter, js_name = cursorAccent)]
415    pub fn set_cursor_accent(this: &ITheme, value: &str);
416    #[wasm_bindgen(method, setter, js_name = selectionBackground)]
417    pub fn set_selection_background(this: &ITheme, value: &str);
418    #[wasm_bindgen(method, setter, js_name = selectionForeground)]
419    pub fn set_selection_foreground(this: &ITheme, value: &str);
420    #[wasm_bindgen(method, setter)]
421    pub fn set_black(this: &ITheme, value: &str);
422    #[wasm_bindgen(method, setter)]
423    pub fn set_red(this: &ITheme, value: &str);
424    #[wasm_bindgen(method, setter)]
425    pub fn set_green(this: &ITheme, value: &str);
426    #[wasm_bindgen(method, setter)]
427    pub fn set_yellow(this: &ITheme, value: &str);
428    #[wasm_bindgen(method, setter)]
429    pub fn set_blue(this: &ITheme, value: &str);
430    #[wasm_bindgen(method, setter)]
431    pub fn set_magenta(this: &ITheme, value: &str);
432    #[wasm_bindgen(method, setter)]
433    pub fn set_cyan(this: &ITheme, value: &str);
434    #[wasm_bindgen(method, setter)]
435    pub fn set_white(this: &ITheme, value: &str);
436    #[wasm_bindgen(method, setter, js_name = brightBlack)]
437    pub fn set_bright_black(this: &ITheme, value: &str);
438    #[wasm_bindgen(method, setter, js_name = brightRed)]
439    pub fn set_bright_red(this: &ITheme, value: &str);
440    #[wasm_bindgen(method, setter, js_name = brightGreen)]
441    pub fn set_bright_green(this: &ITheme, value: &str);
442    #[wasm_bindgen(method, setter, js_name = brightYellow)]
443    pub fn set_bright_yellow(this: &ITheme, value: &str);
444    #[wasm_bindgen(method, setter, js_name = brightBlue)]
445    pub fn set_bright_blue(this: &ITheme, value: &str);
446    #[wasm_bindgen(method, setter, js_name = brightMagenta)]
447    pub fn set_bright_magenta(this: &ITheme, value: &str);
448    #[wasm_bindgen(method, setter, js_name = brightCyan)]
449    pub fn set_bright_cyan(this: &ITheme, value: &str);
450    #[wasm_bindgen(method, setter, js_name = brightWhite)]
451    pub fn set_bright_white(this: &ITheme, value: &str);
452}
453
454impl ITheme
455{
456    pub fn new() -> Self { Object::new().unchecked_into() }
457}
458
459#[wasm_bindgen]
460extern "C" {
461    #[wasm_bindgen(extends = Object)]
462    #[derive(Clone, Debug)]
463    pub type ITerminalOptions;
464
465    #[wasm_bindgen(method, setter)]
466    pub fn set_cols(this: &ITerminalOptions, value: u32);
467    #[wasm_bindgen(method, setter)]
468    pub fn set_rows(this: &ITerminalOptions, value: u32);
469    #[wasm_bindgen(method, setter, js_name = cursorBlink)]
470    pub fn set_cursor_blink(this: &ITerminalOptions, value: bool);
471    /// One of `"block"`, `"underline"`, or `"bar"`.
472    #[wasm_bindgen(method, setter, js_name = cursorStyle)]
473    pub fn set_cursor_style(this: &ITerminalOptions, value: &str);
474    #[wasm_bindgen(method, setter)]
475    pub fn set_theme(this: &ITerminalOptions, value: &ITheme);
476    #[wasm_bindgen(method, setter)]
477    pub fn set_scrollback(this: &ITerminalOptions, value: u32);
478    #[wasm_bindgen(method, setter, js_name = fontSize)]
479    pub fn set_font_size(this: &ITerminalOptions, value: f64);
480    #[wasm_bindgen(method, setter, js_name = fontFamily)]
481    pub fn set_font_family(this: &ITerminalOptions, value: &str);
482    #[wasm_bindgen(method, setter, js_name = allowTransparency)]
483    pub fn set_allow_transparency(this: &ITerminalOptions, value: bool);
484    #[wasm_bindgen(method, setter, js_name = convertEol)]
485    pub fn set_convert_eol(this: &ITerminalOptions, value: bool);
486    #[wasm_bindgen(method, setter, js_name = disableStdin)]
487    pub fn set_disable_stdin(this: &ITerminalOptions, value: bool);
488    #[wasm_bindgen(method, setter, js_name = smoothScrollDuration)]
489    pub fn set_smooth_scroll_duration(this: &ITerminalOptions, value: f64);
490    #[wasm_bindgen(method, setter)]
491    pub fn set_ghostty(this: &ITerminalOptions, value: &Ghostty);
492}
493
494impl ITerminalOptions
495{
496    pub fn new() -> Self { Object::new().unchecked_into() }
497}
498
499#[wasm_bindgen]
500extern "C" {
501    #[wasm_bindgen(extends = Object)]
502    #[derive(Clone, Debug)]
503    pub type RendererOptions;
504
505    #[wasm_bindgen(method, setter, js_name = fontSize)]
506    pub fn set_font_size(this: &RendererOptions, value: f64);
507    #[wasm_bindgen(method, setter, js_name = fontFamily)]
508    pub fn set_font_family(this: &RendererOptions, value: &str);
509    /// One of `"block"`, `"underline"`, or `"bar"`.
510    #[wasm_bindgen(method, setter, js_name = cursorStyle)]
511    pub fn set_cursor_style(this: &RendererOptions, value: &str);
512    #[wasm_bindgen(method, setter, js_name = cursorBlink)]
513    pub fn set_cursor_blink(this: &RendererOptions, value: bool);
514    #[wasm_bindgen(method, setter)]
515    pub fn set_theme(this: &RendererOptions, value: &ITheme);
516    #[wasm_bindgen(method, setter, js_name = devicePixelRatio)]
517    pub fn set_device_pixel_ratio(this: &RendererOptions, value: f64);
518}
519
520impl RendererOptions
521{
522    pub fn new() -> Self { Object::new().unchecked_into() }
523}
524
525#[wasm_bindgen]
526extern "C" {
527    /// Terminal configuration (passed to `ghostty_terminal_new_with_config`).
528    ///
529    /// All color values use `0xRRGGBB` format. A value of `0` means "use
530    /// default".
531    #[wasm_bindgen(extends = Object)]
532    #[derive(Clone, Debug)]
533    pub type GhosttyTerminalConfig;
534
535    #[wasm_bindgen(method, setter, js_name = scrollbackLimit)]
536    pub fn set_scrollback_limit(this: &GhosttyTerminalConfig, value: u32);
537    #[wasm_bindgen(method, setter, js_name = fgColor)]
538    pub fn set_fg_color(this: &GhosttyTerminalConfig, value: u32);
539    #[wasm_bindgen(method, setter, js_name = bgColor)]
540    pub fn set_bg_color(this: &GhosttyTerminalConfig, value: u32);
541    #[wasm_bindgen(method, setter, js_name = cursorColor)]
542    pub fn set_cursor_color(this: &GhosttyTerminalConfig, value: u32);
543    #[wasm_bindgen(method, setter)]
544    pub fn set_palette(this: &GhosttyTerminalConfig, value: &Array<Number>);
545}
546
547impl GhosttyTerminalConfig
548{
549    pub fn new() -> Self { Object::new().unchecked_into() }
550}
551
552#[wasm_bindgen]
553extern "C" {
554    /// Key event structure
555    #[wasm_bindgen(extends = Object)]
556    #[derive(Clone, Debug)]
557    pub type KeyEvent;
558
559    #[wasm_bindgen(method, setter)]
560    pub fn set_action(this: &KeyEvent, value: u32);
561    #[wasm_bindgen(method, setter)]
562    pub fn set_key(this: &KeyEvent, value: u32);
563    #[wasm_bindgen(method, setter)]
564    pub fn set_mods(this: &KeyEvent, value: u32);
565    #[wasm_bindgen(method, setter, js_name = consumedMods)]
566    pub fn set_consumed_mods(this: &KeyEvent, value: u32);
567    #[wasm_bindgen(method, setter)]
568    pub fn set_composing(this: &KeyEvent, value: bool);
569    #[wasm_bindgen(method, setter)]
570    pub fn set_utf8(this: &KeyEvent, value: &str);
571    #[wasm_bindgen(method, setter, js_name = unshiftedCodepoint)]
572    pub fn set_unshifted_codepoint(this: &KeyEvent, value: u32);
573}
574
575impl KeyEvent
576{
577    pub fn new() -> Self { Object::new().unchecked_into() }
578}
579
580#[wasm_bindgen]
581extern "C" {
582    #[wasm_bindgen(extends = Object)]
583    #[derive(Clone, Debug)]
584    pub type IDisposable;
585
586    #[wasm_bindgen(method)]
587    pub fn dispose(this: &IDisposable);
588}
589
590#[wasm_bindgen]
591extern "C" {
592    /// RGB color
593    #[wasm_bindgen(extends = Object)]
594    #[derive(Clone, Debug)]
595    pub type RGB;
596
597    #[wasm_bindgen(method, getter)]
598    pub fn r(this: &RGB) -> u8;
599    #[wasm_bindgen(method, getter)]
600    pub fn g(this: &RGB) -> u8;
601    #[wasm_bindgen(method, getter)]
602    pub fn b(this: &RGB) -> u8;
603}
604
605#[wasm_bindgen]
606extern "C" {
607    #[wasm_bindgen(extends = Object)]
608    #[derive(Clone, Debug)]
609    pub type FontMetrics;
610
611    #[wasm_bindgen(method, getter)]
612    pub fn width(this: &FontMetrics) -> f64;
613    #[wasm_bindgen(method, getter)]
614    pub fn height(this: &FontMetrics) -> f64;
615    #[wasm_bindgen(method, getter)]
616    pub fn baseline(this: &FontMetrics) -> f64;
617}
618
619#[wasm_bindgen]
620extern "C" {
621    /// Cursor position and visibility
622    #[wasm_bindgen(extends = Object)]
623    #[derive(Clone, Debug)]
624    pub type Cursor;
625
626    #[wasm_bindgen(method, getter)]
627    pub fn x(this: &Cursor) -> u32;
628    #[wasm_bindgen(method, getter)]
629    pub fn y(this: &Cursor) -> u32;
630    #[wasm_bindgen(method, getter)]
631    pub fn visible(this: &Cursor) -> bool;
632}
633
634#[wasm_bindgen]
635extern "C" {
636    /// Cell structure matching `ghostty_cell_t` in C (16 bytes)
637    #[wasm_bindgen(extends = Object)]
638    #[derive(Clone, Debug)]
639    pub type GhosttyCell;
640
641    #[wasm_bindgen(method, getter)]
642    pub fn codepoint(this: &GhosttyCell) -> u32;
643    #[wasm_bindgen(method, getter)]
644    pub fn fg_r(this: &GhosttyCell) -> u8;
645    #[wasm_bindgen(method, getter)]
646    pub fn fg_g(this: &GhosttyCell) -> u8;
647    #[wasm_bindgen(method, getter)]
648    pub fn fg_b(this: &GhosttyCell) -> u8;
649    #[wasm_bindgen(method, getter)]
650    pub fn bg_r(this: &GhosttyCell) -> u8;
651    #[wasm_bindgen(method, getter)]
652    pub fn bg_g(this: &GhosttyCell) -> u8;
653    #[wasm_bindgen(method, getter)]
654    pub fn bg_b(this: &GhosttyCell) -> u8;
655    #[wasm_bindgen(method, getter)]
656    pub fn flags(this: &GhosttyCell) -> u32;
657    #[wasm_bindgen(method, getter)]
658    pub fn width(this: &GhosttyCell) -> u8;
659    #[wasm_bindgen(method, getter)]
660    pub fn hyperlink_id(this: &GhosttyCell) -> u32;
661    #[wasm_bindgen(method, getter)]
662    pub fn grapheme_len(this: &GhosttyCell) -> u8;
663}
664
665#[wasm_bindgen]
666extern "C" {
667    /// Cursor state from RenderState (8 bytes packed)
668    ///
669    /// Layout: `x(u16) + y(u16) + viewport_x(i16) + viewport_y(i16) +
670    /// visible(bool)
671    /// + blinking(bool) + style(u8) + _pad(u8)`
672    #[wasm_bindgen(extends = Object)]
673    #[derive(Clone, Debug)]
674    pub type RenderStateCursor;
675
676    #[wasm_bindgen(method, getter)]
677    pub fn x(this: &RenderStateCursor) -> u32;
678    #[wasm_bindgen(method, getter)]
679    pub fn y(this: &RenderStateCursor) -> u32;
680    #[wasm_bindgen(method, getter, js_name = viewportX)]
681    pub fn viewport_x(this: &RenderStateCursor) -> i32;
682    #[wasm_bindgen(method, getter, js_name = viewportY)]
683    pub fn viewport_y(this: &RenderStateCursor) -> i32;
684    #[wasm_bindgen(method, getter)]
685    pub fn visible(this: &RenderStateCursor) -> bool;
686    #[wasm_bindgen(method, getter)]
687    pub fn blinking(this: &RenderStateCursor) -> bool;
688    /// One of `"block"`, `"underline"`, or `"bar"`.
689    #[wasm_bindgen(method, getter)]
690    pub fn style(this: &RenderStateCursor) -> JsString;
691}
692
693#[wasm_bindgen]
694extern "C" {
695    /// Colors from RenderState (12 bytes packed)
696    #[wasm_bindgen(extends = Object)]
697    #[derive(Clone, Debug)]
698    pub type RenderStateColors;
699
700    #[wasm_bindgen(method, getter)]
701    pub fn background(this: &RenderStateColors) -> RGB;
702    #[wasm_bindgen(method, getter)]
703    pub fn foreground(this: &RenderStateColors) -> RGB;
704    #[wasm_bindgen(method, getter)]
705    pub fn cursor(this: &RenderStateColors) -> Option<RGB>;
706}
707
708#[wasm_bindgen]
709extern "C" {
710    /// Represents a coordinate in the terminal buffer
711    #[wasm_bindgen(extends = Object)]
712    #[derive(Clone, Debug)]
713    pub type IBufferCellPosition;
714
715    #[wasm_bindgen(method, getter)]
716    pub fn x(this: &IBufferCellPosition) -> u32;
717    #[wasm_bindgen(method, getter)]
718    pub fn y(this: &IBufferCellPosition) -> u32;
719}
720
721#[wasm_bindgen]
722extern "C" {
723    /// Buffer range for selection coordinates
724    #[wasm_bindgen(extends = Object)]
725    #[derive(Clone, Debug)]
726    pub type IBufferRange;
727
728    #[wasm_bindgen(method, getter)]
729    pub fn start(this: &IBufferRange) -> IBufferCellPosition;
730    #[wasm_bindgen(method, getter)]
731    pub fn end(this: &IBufferRange) -> IBufferCellPosition;
732}
733
734#[wasm_bindgen]
735extern "C" {
736    #[wasm_bindgen(extends = Object)]
737    #[derive(Clone, Debug)]
738    pub type SelectionCoordinates;
739
740    #[wasm_bindgen(method, getter, js_name = startCol)]
741    pub fn start_col(this: &SelectionCoordinates) -> u32;
742    #[wasm_bindgen(method, getter, js_name = startRow)]
743    pub fn start_row(this: &SelectionCoordinates) -> u32;
744    #[wasm_bindgen(method, getter, js_name = endCol)]
745    pub fn end_col(this: &SelectionCoordinates) -> u32;
746    #[wasm_bindgen(method, getter, js_name = endRow)]
747    pub fn end_row(this: &SelectionCoordinates) -> u32;
748}
749
750#[wasm_bindgen]
751extern "C" {
752    #[wasm_bindgen(extends = Object)]
753    #[derive(Clone, Debug)]
754    pub type ITerminalDimensions;
755
756    #[wasm_bindgen(method, getter)]
757    pub fn cols(this: &ITerminalDimensions) -> u32;
758    #[wasm_bindgen(method, getter)]
759    pub fn rows(this: &ITerminalDimensions) -> u32;
760}
761
762#[wasm_bindgen]
763extern "C" {
764    #[wasm_bindgen(extends = Object)]
765    #[derive(Clone, Debug)]
766    pub type ResizeEvent;
767
768    #[wasm_bindgen(method, getter)]
769    pub fn cols(this: &ResizeEvent) -> u32;
770    #[wasm_bindgen(method, getter)]
771    pub fn rows(this: &ResizeEvent) -> u32;
772}
773
774#[wasm_bindgen]
775extern "C" {
776    #[wasm_bindgen(extends = Object)]
777    #[derive(Clone, Debug)]
778    pub type RenderEvent;
779
780    #[wasm_bindgen(method, getter)]
781    pub fn start(this: &RenderEvent) -> u32;
782    #[wasm_bindgen(method, getter)]
783    pub fn end(this: &RenderEvent) -> u32;
784}
785
786#[wasm_bindgen]
787extern "C" {
788    #[wasm_bindgen(extends = Object)]
789    #[derive(Clone, Debug)]
790    pub type Dimensions;
791
792    #[wasm_bindgen(method, getter)]
793    pub fn cols(this: &Dimensions) -> u32;
794    #[wasm_bindgen(method, getter)]
795    pub fn rows(this: &Dimensions) -> u32;
796}
797
798#[wasm_bindgen]
799extern "C" {
800    /// Keyboard event with key and DOM event
801    #[wasm_bindgen(extends = Object)]
802    #[derive(Clone, Debug)]
803    pub type IKeyEvent;
804
805    #[wasm_bindgen(method, getter)]
806    pub fn key(this: &IKeyEvent) -> JsString;
807    #[wasm_bindgen(method, getter, js_name = domEvent)]
808    pub fn dom_event(this: &IKeyEvent) -> KeyboardEvent;
809}
810
811#[wasm_bindgen]
812extern "C" {
813    #[wasm_bindgen(extends = Object)]
814    #[derive(Clone, Debug)]
815    pub type HoveredLinkRange;
816
817    #[wasm_bindgen(method, getter, js_name = startX)]
818    pub fn start_x(this: &HoveredLinkRange) -> u32;
819    #[wasm_bindgen(method, getter, js_name = startY)]
820    pub fn start_y(this: &HoveredLinkRange) -> u32;
821    #[wasm_bindgen(method, getter, js_name = endX)]
822    pub fn end_x(this: &HoveredLinkRange) -> u32;
823    #[wasm_bindgen(method, getter, js_name = endY)]
824    pub fn end_y(this: &HoveredLinkRange) -> u32;
825}
826
827#[wasm_bindgen]
828extern "C" {
829    /// Represents a detected link in the terminal
830    #[wasm_bindgen(extends = Object)]
831    #[derive(Clone, Debug)]
832    pub type ILink;
833
834    /// The URL or text of the link
835    #[wasm_bindgen(method, getter)]
836    pub fn text(this: &ILink) -> JsString;
837    /// The range of the link in the buffer (may span multiple lines)
838    #[wasm_bindgen(method, getter)]
839    pub fn range(this: &ILink) -> IBufferRange;
840    /// Called when the link is activated (clicked with modifier)
841    #[wasm_bindgen(method)]
842    pub fn activate(this: &ILink, event: &MouseEvent);
843    /// Optional: called when mouse enters/leaves the link
844    #[wasm_bindgen(method)]
845    pub fn hover(this: &ILink, is_hovered: bool);
846    /// Optional: called to clean up resources
847    #[wasm_bindgen(method)]
848    pub fn dispose(this: &ILink);
849}
850
851#[wasm_bindgen]
852extern "C" {
853    /// Provides link detection for a specific type of link
854    ///
855    /// Examples: OSC 8 hyperlinks, URL regex detection
856    #[wasm_bindgen(extends = Object)]
857    #[derive(Clone, Debug)]
858    pub type ILinkProvider;
859
860    /// Provide links for a given row
861    ///
862    /// - `y`: Absolute row in buffer (0-based)
863    /// - `callback`: Called with detected links (or undefined if none)
864    #[wasm_bindgen(method, js_name = provideLinks)]
865    pub fn provide_links(
866        this: &ILinkProvider,
867        y: u32,
868        callback: &Function<fn(JsOption<Array<ILink>>) -> Undefined>,
869    );
870    /// Optional: called when terminal is disposed
871    #[wasm_bindgen(method)]
872    pub fn dispose(this: &ILinkProvider);
873}
874
875#[wasm_bindgen]
876extern "C" {
877    /// A single cell in the buffer
878    #[wasm_bindgen(extends = Object)]
879    #[derive(Clone, Debug)]
880    pub type IBufferCell;
881
882    /// Character(s) in this cell (may be empty, single char, or emoji)
883    #[wasm_bindgen(method, js_name = getChars)]
884    pub fn get_chars(this: &IBufferCell) -> JsString;
885    /// Unicode codepoint (0 for null cell)
886    #[wasm_bindgen(method, js_name = getCode)]
887    pub fn get_code(this: &IBufferCell) -> u32;
888    /// Character width (1 = normal, 2 = wide/emoji, 0 = combining)
889    #[wasm_bindgen(method, js_name = getWidth)]
890    pub fn get_width(this: &IBufferCell) -> u8;
891    /// Foreground color index (for palette colors) or -1 for RGB
892    #[wasm_bindgen(method, js_name = getFgColorMode)]
893    pub fn get_fg_color_mode(this: &IBufferCell) -> i32;
894    /// Background color index (for palette colors) or -1 for RGB
895    #[wasm_bindgen(method, js_name = getBgColorMode)]
896    pub fn get_bg_color_mode(this: &IBufferCell) -> i32;
897    /// Foreground RGB color (or 0 for default)
898    #[wasm_bindgen(method, js_name = getFgColor)]
899    pub fn get_fg_color(this: &IBufferCell) -> u32;
900    /// Background RGB color (or 0 for default)
901    #[wasm_bindgen(method, js_name = getBgColor)]
902    pub fn get_bg_color(this: &IBufferCell) -> u32;
903    /// Whether cell has bold style
904    #[wasm_bindgen(method, js_name = isBold)]
905    pub fn is_bold(this: &IBufferCell) -> u32;
906    /// Whether cell has italic style
907    #[wasm_bindgen(method, js_name = isItalic)]
908    pub fn is_italic(this: &IBufferCell) -> u32;
909    /// Whether cell has underline style
910    #[wasm_bindgen(method, js_name = isUnderline)]
911    pub fn is_underline(this: &IBufferCell) -> u32;
912    /// Whether cell has strikethrough style
913    #[wasm_bindgen(method, js_name = isStrikethrough)]
914    pub fn is_strikethrough(this: &IBufferCell) -> u32;
915    /// Whether cell has blink style
916    #[wasm_bindgen(method, js_name = isBlink)]
917    pub fn is_blink(this: &IBufferCell) -> u32;
918    /// Whether cell has inverse video style
919    #[wasm_bindgen(method, js_name = isInverse)]
920    pub fn is_inverse(this: &IBufferCell) -> u32;
921    /// Whether cell has invisible style
922    #[wasm_bindgen(method, js_name = isInvisible)]
923    pub fn is_invisible(this: &IBufferCell) -> u32;
924    /// Whether cell has faint/dim style
925    #[wasm_bindgen(method, js_name = isFaint)]
926    pub fn is_faint(this: &IBufferCell) -> u32;
927    /// Get hyperlink ID for this cell (0 = no link)
928    #[wasm_bindgen(method, js_name = getHyperlinkId)]
929    pub fn get_hyperlink_id(this: &IBufferCell) -> u32;
930    /// Get the Unicode codepoint for this cell
931    #[wasm_bindgen(method, js_name = getCodepoint)]
932    pub fn get_codepoint(this: &IBufferCell) -> u32;
933    /// Whether cell has dim/faint attribute (boolean version)
934    #[wasm_bindgen(method, js_name = isDim)]
935    pub fn is_dim(this: &IBufferCell) -> bool;
936}
937
938#[wasm_bindgen]
939extern "C" {
940    /// A single line in the buffer
941    #[wasm_bindgen(extends = Object)]
942    #[derive(Clone, Debug)]
943    pub type IBufferLine;
944
945    /// Length of the line (in columns)
946    #[wasm_bindgen(method, getter)]
947    pub fn length(this: &IBufferLine) -> u32;
948    /// Whether this line wraps to the next line
949    #[wasm_bindgen(method, getter, js_name = isWrapped)]
950    pub fn is_wrapped(this: &IBufferLine) -> bool;
951    /// Get a cell from this line
952    ///
953    /// - `x`: Column index (0-indexed)
954    ///
955    /// Returns cell object or undefined if out of bounds
956    #[wasm_bindgen(method, js_name = getCell)]
957    pub fn get_cell(this: &IBufferLine, x: u32) -> Option<IBufferCell>;
958    /// Translate the line to a string
959    ///
960    /// - `trim_right`: Whether to trim trailing whitespace (default: false)
961    /// - `start_column`: Start column (default: 0)
962    /// - `end_column`: End column (default: length)
963    #[wasm_bindgen(method, js_name = translateToString)]
964    pub fn translate_to_string(
965        this: &IBufferLine,
966        trim_right: Option<bool>,
967        start_column: Option<u32>,
968        end_column: Option<u32>,
969    ) -> JsString;
970}
971
972#[wasm_bindgen]
973extern "C" {
974    /// A terminal buffer (normal or alternate screen)
975    #[wasm_bindgen(extends = Object)]
976    #[derive(Clone, Debug)]
977    pub type IBuffer;
978
979    /// Buffer type: `'normal'` or `'alternate'`
980    #[wasm_bindgen(method, getter, js_name = type)]
981    pub fn type_(this: &IBuffer) -> JsString;
982    /// Cursor X position (0-indexed)
983    #[wasm_bindgen(method, getter, js_name = cursorX)]
984    pub fn cursor_x(this: &IBuffer) -> u32;
985    /// Cursor Y position (0-indexed, relative to viewport)
986    #[wasm_bindgen(method, getter, js_name = cursorY)]
987    pub fn cursor_y(this: &IBuffer) -> u32;
988    /// Viewport Y position (scroll offset, 0 = bottom of scrollback)
989    #[wasm_bindgen(method, getter, js_name = viewportY)]
990    pub fn viewport_y(this: &IBuffer) -> u32;
991    /// Base Y position (always 0 for normal buffer, may vary for alternate)
992    #[wasm_bindgen(method, getter, js_name = baseY)]
993    pub fn base_y(this: &IBuffer) -> u32;
994    /// Total buffer length (rows + scrollback for normal, just rows for
995    /// alternate)
996    #[wasm_bindgen(method, getter)]
997    pub fn length(this: &IBuffer) -> u32;
998    /// Get a line from the buffer
999    ///
1000    /// - `y`: Line index (0 = top of scrollback for normal buffer)
1001    ///
1002    /// Returns line object or undefined if out of bounds
1003    #[wasm_bindgen(method, js_name = getLine)]
1004    pub fn get_line(this: &IBuffer, y: u32) -> Option<IBufferLine>;
1005    /// Get the null cell (used for empty/uninitialized cells)
1006    #[wasm_bindgen(method, js_name = getNullCell)]
1007    pub fn get_null_cell(this: &IBuffer) -> IBufferCell;
1008}
1009
1010#[wasm_bindgen]
1011extern "C" {
1012    /// Top-level buffer API namespace
1013    ///
1014    /// Provides access to active, normal, and alternate screen buffers
1015    #[wasm_bindgen(extends = Object)]
1016    #[derive(Clone, Debug)]
1017    pub type IBufferNamespace;
1018
1019    /// The currently active buffer (normal or alternate)
1020    #[wasm_bindgen(method, getter)]
1021    pub fn active(this: &IBufferNamespace) -> IBuffer;
1022    /// The normal buffer (primary screen)
1023    #[wasm_bindgen(method, getter)]
1024    pub fn normal(this: &IBufferNamespace) -> IBuffer;
1025    /// The alternate buffer (used by full-screen apps like vim)
1026    #[wasm_bindgen(method, getter)]
1027    pub fn alternate(this: &IBufferNamespace) -> IBuffer;
1028    /// Event fired when buffer changes (normal ↔ alternate)
1029    #[wasm_bindgen(method, getter, js_name = onBufferChange)]
1030    pub fn on_buffer_change(this: &IBufferNamespace) -> IEvent<IBuffer>;
1031}
1032
1033#[wasm_bindgen]
1034extern "C" {
1035    /// Unicode version provider (xterm.js compatibility)
1036    #[wasm_bindgen(extends = Object)]
1037    #[derive(Clone, Debug)]
1038    pub type IUnicodeVersionProvider;
1039
1040    #[wasm_bindgen(method, getter, js_name = activeVersion)]
1041    pub fn active_version(this: &IUnicodeVersionProvider) -> JsString;
1042}
1043
1044#[wasm_bindgen]
1045extern "C" {
1046    #[wasm_bindgen(extends = Object)]
1047    #[derive(Clone, Debug)]
1048    pub type IRenderable;
1049
1050    #[wasm_bindgen(method, js_name = getLine)]
1051    pub fn get_line(this: &IRenderable, y: u32) -> Option<Array<GhosttyCell>>;
1052    #[wasm_bindgen(method, js_name = getCursor)]
1053    pub fn get_cursor(this: &IRenderable) -> Cursor;
1054    #[wasm_bindgen(method, js_name = getDimensions)]
1055    pub fn get_dimensions(this: &IRenderable) -> Dimensions;
1056    #[wasm_bindgen(method, js_name = isRowDirty)]
1057    pub fn is_row_dirty(this: &IRenderable, y: u32) -> bool;
1058    /// Returns true if a full redraw is needed (e.g., screen change)
1059    #[wasm_bindgen(method, js_name = needsFullRedraw)]
1060    pub fn needs_full_redraw(this: &IRenderable) -> bool;
1061    #[wasm_bindgen(method, js_name = clearDirty)]
1062    pub fn clear_dirty(this: &IRenderable);
1063    /// Get the full grapheme string for a cell at (row, col).
1064    ///
1065    /// For cells with `grapheme_len > 0`, this returns all codepoints combined.
1066    /// For simple cells, returns the single character.
1067    #[wasm_bindgen(method, js_name = getGraphemeString)]
1068    pub fn get_grapheme_string(this: &IRenderable, row: u32, col: u32) -> JsString;
1069}
1070
1071#[wasm_bindgen]
1072extern "C" {
1073    #[wasm_bindgen(extends = Object)]
1074    #[derive(Clone, Debug)]
1075    pub type IScrollbackProvider;
1076
1077    #[wasm_bindgen(method, js_name = getScrollbackLine)]
1078    pub fn get_scrollback_line(
1079        this: &IScrollbackProvider,
1080        offset: u32,
1081    ) -> Option<Array<GhosttyCell>>;
1082    #[wasm_bindgen(method, js_name = getScrollbackLength)]
1083    pub fn get_scrollback_length(this: &IScrollbackProvider) -> u32;
1084}
1085
1086#[wasm_bindgen]
1087extern "C" {
1088    #[wasm_bindgen(extends = Object)]
1089    #[derive(Clone, Debug)]
1090    pub type ITerminalAddon;
1091
1092    #[wasm_bindgen(method)]
1093    pub fn activate(this: &ITerminalAddon, terminal: &ITerminalCore);
1094    #[wasm_bindgen(method)]
1095    pub fn dispose(this: &ITerminalAddon);
1096}
1097
1098#[wasm_bindgen]
1099extern "C" {
1100    #[wasm_bindgen(extends = Object)]
1101    #[derive(Clone, Debug)]
1102    pub type ITerminalCore;
1103
1104    #[wasm_bindgen(method, getter)]
1105    pub fn cols(this: &ITerminalCore) -> u32;
1106    #[wasm_bindgen(method, getter)]
1107    pub fn rows(this: &ITerminalCore) -> u32;
1108    #[wasm_bindgen(method, getter)]
1109    pub fn element(this: &ITerminalCore) -> Option<HtmlElement>;
1110    #[wasm_bindgen(method, getter)]
1111    pub fn textarea(this: &ITerminalCore) -> Option<HtmlTextAreaElement>;
1112}
1113
1114#[wasm_bindgen(js_namespace = GhosttyWeb)]
1115extern "C" {
1116    /// Initialize the ghostty-web library by loading the WASM module.
1117    ///
1118    /// Must be called before creating any [`Terminal`] instances.
1119    ///
1120    /// This creates a shared WASM instance that all [`Terminal`] instances will
1121    /// use. For test isolation, pass a [`Ghostty`] instance directly to the
1122    /// [`Terminal`] constructor.
1123    #[wasm_bindgen]
1124    pub async fn init();
1125
1126    #[wasm_bindgen(js_name = EventEmitter)]
1127    pub type EventEmitter<T>;
1128
1129    #[wasm_bindgen(constructor, js_class = "EventEmitter")]
1130    pub fn new<T: JsGeneric>() -> EventEmitter<T>;
1131
1132    #[wasm_bindgen(method)]
1133    pub fn fire<T: JsGeneric>(this: &EventEmitter<T>, arg: T);
1134
1135    /// `event` is a plain property in TS (`event: IEvent<T>`), not a getter.
1136    #[wasm_bindgen(method, js_name = event)]
1137    pub fn event<T: JsGeneric>(this: &EventEmitter<T>) -> IEvent<T>;
1138
1139    #[wasm_bindgen(method)]
1140    pub fn dispose<T>(this: &EventEmitter<T>);
1141
1142    /// Main Ghostty WASM wrapper class
1143    #[wasm_bindgen(js_name = Ghostty)]
1144    pub type Ghostty;
1145
1146    #[wasm_bindgen(constructor, js_class = "Ghostty")]
1147    pub fn new(wasm_instance: &WebAssembly::Instance) -> Ghostty;
1148
1149    #[wasm_bindgen(method, js_name = createKeyEncoder)]
1150    pub fn create_key_encoder(this: &Ghostty) -> KeyEncoder;
1151
1152    #[wasm_bindgen(method, js_name = createTerminal)]
1153    pub fn create_terminal(
1154        this: &Ghostty,
1155        cols: Option<u32>,
1156        rows: Option<u32>,
1157        config: Option<&GhosttyTerminalConfig>,
1158    ) -> GhosttyTerminal;
1159
1160    #[wasm_bindgen(static_method_of = Ghostty, js_class = "Ghostty")]
1161    pub fn load(wasm_path: Option<&str>) -> Promise<Ghostty>;
1162
1163    /// GhosttyTerminal - High-performance terminal emulator
1164    ///
1165    /// Uses Ghostty's native RenderState for optimal performance:
1166    /// - ONE call to update all state (`renderStateUpdate`)
1167    /// - ONE call to get all cells (`getViewport`)
1168    /// - No per-row WASM boundary crossings!
1169    #[wasm_bindgen(js_name = GhosttyTerminal)]
1170    pub type GhosttyTerminal;
1171
1172    #[wasm_bindgen(method, getter)]
1173    pub fn cols(this: &GhosttyTerminal) -> u32;
1174    #[wasm_bindgen(method, getter)]
1175    pub fn rows(this: &GhosttyTerminal) -> u32;
1176
1177    #[wasm_bindgen(method, js_name = write)]
1178    pub fn write_str(this: &GhosttyTerminal, data: &str);
1179    #[wasm_bindgen(method, js_name = write)]
1180    pub fn write_u8_array(this: &GhosttyTerminal, data: &Uint8Array);
1181
1182    #[wasm_bindgen(method)]
1183    pub fn resize(this: &GhosttyTerminal, cols: u32, rows: u32);
1184    #[wasm_bindgen(method)]
1185    pub fn free(this: &GhosttyTerminal);
1186
1187    /// Update render state from terminal.
1188    ///
1189    /// This syncs the RenderState with the current Terminal state. The dirty
1190    /// state (full/partial/none) is stored in the WASM RenderState and can be
1191    /// queried via [`GhosttyTerminal::is_row_dirty`]. When dirty==full,
1192    /// `is_row_dirty()` returns true for ALL rows.
1193    ///
1194    /// The WASM layer automatically detects screen switches (normal ↔
1195    /// alternate) and returns FULL dirty state when switching screens
1196    /// (e.g., vim exit).
1197    ///
1198    /// Safe to call multiple times - dirty state persists until
1199    /// [`GhosttyTerminal::mark_clean`].
1200    #[wasm_bindgen(method, js_name = update)]
1201    pub fn update_raw(this: &GhosttyTerminal) -> u32;
1202
1203    /// Get cursor state from render state.
1204    ///
1205    /// Ensures render state is fresh by calling [`GhosttyTerminal::update`].
1206    #[wasm_bindgen(method, js_name = getCursor)]
1207    pub fn get_cursor(this: &GhosttyTerminal) -> RenderStateCursor;
1208    /// Get default colors from render state
1209    #[wasm_bindgen(method, js_name = getColors)]
1210    pub fn get_colors(this: &GhosttyTerminal) -> RenderStateColors;
1211    /// Check if a specific row is dirty
1212    #[wasm_bindgen(method, js_name = isRowDirty)]
1213    pub fn is_row_dirty(this: &GhosttyTerminal, y: u32) -> bool;
1214    /// Mark render state as clean (call after rendering)
1215    #[wasm_bindgen(method, js_name = markClean)]
1216    pub fn mark_clean(this: &GhosttyTerminal);
1217    /// Get ALL viewport cells in ONE WASM call - the key performance
1218    /// optimization!
1219    ///
1220    /// Returns a reusable cell array (zero allocation after warmup).
1221    #[wasm_bindgen(method, js_name = getViewport)]
1222    pub fn get_viewport(this: &GhosttyTerminal) -> Array<GhosttyCell>;
1223    /// Get line - for compatibility, extracts from viewport.
1224    ///
1225    /// Ensures render state is fresh by calling [`GhosttyTerminal::update`].
1226    /// Returns a COPY of the cells to avoid pool reference issues.
1227    #[wasm_bindgen(method, js_name = getLine)]
1228    pub fn get_line(this: &GhosttyTerminal, y: u32) -> Option<Array<GhosttyCell>>;
1229    /// For compatibility with old API
1230    #[wasm_bindgen(method, js_name = isDirty)]
1231    pub fn is_dirty(this: &GhosttyTerminal) -> bool;
1232    /// Check if a full redraw is needed (screen change, resize, etc.)
1233    ///
1234    /// Note: This calls [`GhosttyTerminal::update`] to ensure fresh state. Safe
1235    /// to call multiple times.
1236    #[wasm_bindgen(method, js_name = needsFullRedraw)]
1237    pub fn needs_full_redraw(this: &GhosttyTerminal) -> bool;
1238    /// Mark render state as clean after rendering
1239    #[wasm_bindgen(method, js_name = clearDirty)]
1240    pub fn clear_dirty(this: &GhosttyTerminal);
1241    #[wasm_bindgen(method, js_name = isAlternateScreen)]
1242    pub fn is_alternate_screen(this: &GhosttyTerminal) -> bool;
1243    #[wasm_bindgen(method, js_name = hasBracketedPaste)]
1244    pub fn has_bracketed_paste(this: &GhosttyTerminal) -> bool;
1245    #[wasm_bindgen(method, js_name = hasFocusEvents)]
1246    pub fn has_focus_events(this: &GhosttyTerminal) -> bool;
1247    #[wasm_bindgen(method, js_name = hasMouseTracking)]
1248    pub fn has_mouse_tracking(this: &GhosttyTerminal) -> bool;
1249    /// Get dimensions - for compatibility
1250    #[wasm_bindgen(method, js_name = getDimensions)]
1251    pub fn get_dimensions(this: &GhosttyTerminal) -> Dimensions;
1252    /// Get number of scrollback lines (history, not including active screen)
1253    #[wasm_bindgen(method, js_name = getScrollbackLength)]
1254    pub fn get_scrollback_length(this: &GhosttyTerminal) -> u32;
1255    /// Get a line from the scrollback buffer.
1256    ///
1257    /// Ensures render state is fresh by calling [`GhosttyTerminal::update`].
1258    ///
1259    /// - `offset`: 0 = oldest line, (length-1) = most recent scrollback line
1260    #[wasm_bindgen(method, js_name = getScrollbackLine)]
1261    pub fn get_scrollback_line(this: &GhosttyTerminal, offset: u32) -> Option<Array<GhosttyCell>>;
1262    /// Check if a row in the active screen is wrapped (soft-wrapped to next
1263    /// line)
1264    #[wasm_bindgen(method, js_name = isRowWrapped)]
1265    pub fn is_row_wrapped(this: &GhosttyTerminal, row: u32) -> bool;
1266    /// Hyperlink URI not yet exposed in simplified API
1267    #[wasm_bindgen(method, js_name = getHyperlinkUri)]
1268    pub fn get_hyperlink_uri(this: &GhosttyTerminal, id: u32) -> Option<JsString>;
1269    /// Check if there are pending responses from the terminal.
1270    ///
1271    /// Responses are generated by escape sequences like DSR (Device Status
1272    /// Report).
1273    #[wasm_bindgen(method, js_name = hasResponse)]
1274    pub fn has_response(this: &GhosttyTerminal) -> bool;
1275    /// Read pending responses from the terminal.
1276    ///
1277    /// Returns the response string, or null if no responses pending.
1278    ///
1279    /// Responses are generated by escape sequences that require replies:
1280    /// - DSR 6 (cursor position): Returns `\x1b[row;colR`
1281    /// - DSR 5 (operating status): Returns `\x1b[0n`
1282    #[wasm_bindgen(method, js_name = readResponse)]
1283    pub fn read_response(this: &GhosttyTerminal) -> Option<JsString>;
1284    /// Query arbitrary terminal mode by number
1285    ///
1286    /// - `mode`: Mode number (e.g., 25 for cursor visibility, 2004 for
1287    ///   bracketed paste)
1288    /// - `is_ansi`: True for ANSI modes, false for DEC modes (default: false)
1289    #[wasm_bindgen(method, js_name = getMode)]
1290    pub fn get_mode(this: &GhosttyTerminal, mode: u32, is_ansi: Option<bool>) -> bool;
1291    /// Get all codepoints for a grapheme cluster at the given position.
1292    ///
1293    /// For most cells this returns a single codepoint, but for complex scripts
1294    /// (Hindi, emoji with ZWJ, etc.) it returns multiple codepoints.
1295    ///
1296    /// Returns array of codepoints, or null on error.
1297    #[wasm_bindgen(method, js_name = getGrapheme)]
1298    pub fn get_grapheme(this: &GhosttyTerminal, row: u32, col: u32) -> Option<Array<Number>>;
1299    /// Get a string representation of the grapheme at the given position.
1300    ///
1301    /// This properly handles complex scripts like Hindi, emoji with ZWJ, etc.
1302    #[wasm_bindgen(method, js_name = getGraphemeString)]
1303    pub fn get_grapheme_string(this: &GhosttyTerminal, row: u32, col: u32) -> JsString;
1304    /// Get all codepoints for a grapheme cluster in the scrollback buffer.
1305    ///
1306    /// - `offset`: Scrollback line offset (0 = oldest)
1307    /// - `col`: Column index
1308    ///
1309    /// Returns array of codepoints, or null on error.
1310    #[wasm_bindgen(method, js_name = getScrollbackGrapheme)]
1311    pub fn get_scrollback_grapheme(
1312        this: &GhosttyTerminal,
1313        offset: u32,
1314        col: u32,
1315    ) -> Option<Array<Number>>;
1316    /// Get a string representation of a grapheme in the scrollback buffer.
1317    #[wasm_bindgen(method, js_name = getScrollbackGraphemeString)]
1318    pub fn get_scrollback_grapheme_string(
1319        this: &GhosttyTerminal,
1320        offset: u32,
1321        col: u32,
1322    ) -> JsString;
1323}
1324
1325impl GhosttyTerminal
1326{
1327    /// Update render state from terminal.
1328    ///
1329    /// Typed wrapper around [`GhosttyTerminal::update_raw`]. See that method
1330    /// for full documentation.
1331    pub fn update(&self) -> DirtyState { DirtyState::from_u32(self.update_raw()) }
1332}
1333
1334#[wasm_bindgen(js_namespace = GhosttyWeb)]
1335extern "C" {
1336    /// Key Encoder - converts keyboard events into terminal escape sequences
1337    #[wasm_bindgen(js_name = KeyEncoder)]
1338    pub type KeyEncoder;
1339
1340    #[wasm_bindgen(method, js_name = setOption)]
1341    pub fn set_option(this: &KeyEncoder, option: u32, value: &JsValue);
1342    #[wasm_bindgen(method, js_name = setKittyFlags)]
1343    pub fn set_kitty_flags(this: &KeyEncoder, flags: u32);
1344    #[wasm_bindgen(method)]
1345    pub fn encode(this: &KeyEncoder, event: &KeyEvent) -> Uint8Array;
1346    #[wasm_bindgen(method)]
1347    pub fn dispose(this: &KeyEncoder);
1348
1349    #[wasm_bindgen(js_name = CanvasRenderer)]
1350    pub type CanvasRenderer;
1351
1352    #[wasm_bindgen(constructor, js_class = "CanvasRenderer")]
1353    pub fn new(canvas: &HtmlCanvasElement, options: Option<&RendererOptions>) -> CanvasRenderer;
1354
1355    /// Remeasure font metrics (call after font loads or changes)
1356    #[wasm_bindgen(method, js_name = remeasureFont)]
1357    pub fn remeasure_font(this: &CanvasRenderer);
1358    /// Resize canvas to fit terminal dimensions
1359    #[wasm_bindgen(method)]
1360    pub fn resize(this: &CanvasRenderer, cols: u32, rows: u32);
1361    /// Render the terminal buffer to canvas
1362    #[wasm_bindgen(method)]
1363    pub fn render(
1364        this: &CanvasRenderer,
1365        buffer: &IRenderable,
1366        force_all: Option<bool>,
1367        viewport_y: Option<f64>,
1368        scrollback_provider: Option<&IScrollbackProvider>,
1369        scrollbar_opacity: Option<f64>,
1370    );
1371    /// Update theme colors
1372    #[wasm_bindgen(method, js_name = setTheme)]
1373    pub fn set_theme(this: &CanvasRenderer, theme: &ITheme);
1374    /// Update font size
1375    #[wasm_bindgen(method, js_name = setFontSize)]
1376    pub fn set_font_size(this: &CanvasRenderer, size: f64);
1377    /// Update font family
1378    #[wasm_bindgen(method, js_name = setFontFamily)]
1379    pub fn set_font_family(this: &CanvasRenderer, family: &str);
1380    /// Update cursor style
1381    ///
1382    /// One of `"block"`, `"underline"`, or `"bar"`.
1383    #[wasm_bindgen(method, js_name = setCursorStyle)]
1384    pub fn set_cursor_style(this: &CanvasRenderer, style: &str);
1385    /// Enable/disable cursor blinking
1386    #[wasm_bindgen(method, js_name = setCursorBlink)]
1387    pub fn set_cursor_blink(this: &CanvasRenderer, enabled: bool);
1388    /// Get current font metrics
1389    #[wasm_bindgen(method, js_name = getMetrics)]
1390    pub fn get_metrics(this: &CanvasRenderer) -> FontMetrics;
1391    /// Get canvas element (needed by SelectionManager)
1392    #[wasm_bindgen(method, js_name = getCanvas)]
1393    pub fn get_canvas(this: &CanvasRenderer) -> HtmlCanvasElement;
1394    /// Set selection manager (for rendering selection)
1395    #[wasm_bindgen(method, js_name = setSelectionManager)]
1396    pub fn set_selection_manager(this: &CanvasRenderer, manager: &SelectionManager);
1397    /// Set the currently hovered hyperlink ID for rendering underlines
1398    #[wasm_bindgen(method, js_name = setHoveredHyperlinkId)]
1399    pub fn set_hovered_hyperlink_id(this: &CanvasRenderer, hyperlink_id: u32);
1400    /// Set the currently hovered link range for rendering underlines (for
1401    /// regex-detected URLs)
1402    ///
1403    /// Pass null to clear the hover state
1404    #[wasm_bindgen(method, js_name = setHoveredLinkRange)]
1405    pub fn set_hovered_link_range(this: &CanvasRenderer, range: Option<&HoveredLinkRange>);
1406    /// Get character cell width (for coordinate conversion)
1407    #[wasm_bindgen(method, getter, js_name = charWidth)]
1408    pub fn char_width(this: &CanvasRenderer) -> f64;
1409    /// Get character cell height (for coordinate conversion)
1410    #[wasm_bindgen(method, getter, js_name = charHeight)]
1411    pub fn char_height(this: &CanvasRenderer) -> f64;
1412    /// Clear entire canvas
1413    #[wasm_bindgen(method)]
1414    pub fn clear(this: &CanvasRenderer);
1415    /// Cleanup resources
1416    #[wasm_bindgen(method)]
1417    pub fn dispose(this: &CanvasRenderer);
1418
1419    #[wasm_bindgen(js_name = FitAddon, extends = ITerminalAddon)]
1420    pub type FitAddon;
1421
1422    #[wasm_bindgen(constructor, js_class = "FitAddon")]
1423    pub fn new() -> FitAddon;
1424
1425    /// Activate the addon (called by [`Terminal::load_addon`])
1426    #[wasm_bindgen(method)]
1427    pub fn activate(this: &FitAddon, terminal: &ITerminalCore);
1428    /// Dispose the addon and clean up resources
1429    #[wasm_bindgen(method)]
1430    pub fn dispose(this: &FitAddon);
1431    /// Fit the terminal to its container
1432    ///
1433    /// Calculates optimal dimensions and resizes the terminal. Does nothing if
1434    /// dimensions cannot be calculated or haven't changed.
1435    #[wasm_bindgen(method)]
1436    pub fn fit(this: &FitAddon);
1437    /// Propose dimensions to fit the terminal to its container
1438    ///
1439    /// Calculates cols and rows based on:
1440    /// - Terminal container element dimensions (`clientWidth`/`Height`)
1441    /// - Terminal element padding
1442    /// - Font metrics (character cell size)
1443    /// - Scrollbar width reservation
1444    ///
1445    /// Returns proposed dimensions or undefined if cannot calculate.
1446    #[wasm_bindgen(method, js_name = proposeDimensions)]
1447    pub fn propose_dimensions(this: &FitAddon) -> Option<ITerminalDimensions>;
1448    /// Observe the terminal's container for resize events
1449    ///
1450    /// Sets up a `ResizeObserver` to automatically call [`FitAddon::fit`] when
1451    /// the container size changes. Resize events are debounced to avoid
1452    /// excessive calls during window drag operations.
1453    ///
1454    /// Call [`FitAddon::dispose`] to stop observing.
1455    #[wasm_bindgen(method, js_name = observeResize)]
1456    pub fn observe_resize(this: &FitAddon);
1457
1458    /// InputHandler class
1459    ///
1460    /// Attaches keyboard event listeners to a container and converts keyboard
1461    /// events to terminal input data
1462    #[wasm_bindgen(js_name = InputHandler)]
1463    pub type InputHandler;
1464
1465    /// Create a new InputHandler
1466    ///
1467    /// - `ghostty` - Ghostty instance (for creating KeyEncoder)
1468    /// - `container` - DOM element to attach listeners to
1469    /// - `on_data` - Callback for terminal data (escape sequences to send to
1470    ///   PTY)
1471    /// - `on_bell` - Callback for bell/beep event
1472    /// - `on_key` - Optional callback for raw key events
1473    /// - `custom_key_event_handler` - Optional custom key event handler
1474    /// - `get_mode` - Optional callback to query terminal mode state (for
1475    ///   application cursor mode)
1476    #[wasm_bindgen(constructor, js_class = "InputHandler")]
1477    pub fn new(
1478        ghostty: &Ghostty,
1479        container: &HtmlElement,
1480        on_data: &Function<fn(JsString) -> Undefined>,
1481        on_bell: &Function<fn() -> Undefined>,
1482        on_key: Option<&Function<fn(IKeyEvent) -> Undefined>>,
1483        custom_key_event_handler: Option<&Function<fn(KeyboardEvent) -> Boolean>>,
1484        get_mode: Option<&Function<fn(Number) -> Boolean>>,
1485    ) -> InputHandler;
1486
1487    /// Set custom key event handler (for runtime updates)
1488    #[wasm_bindgen(method, js_name = setCustomKeyEventHandler)]
1489    pub fn set_custom_key_event_handler(
1490        this: &InputHandler,
1491        handler: &Function<fn(KeyboardEvent) -> Boolean>,
1492    );
1493    /// Dispose the InputHandler and remove event listeners
1494    #[wasm_bindgen(method)]
1495    pub fn dispose(this: &InputHandler);
1496    /// Check if handler is disposed
1497    #[wasm_bindgen(method, js_name = isActive)]
1498    pub fn is_active(this: &InputHandler) -> bool;
1499
1500    /// Manages link detection across multiple providers with intelligent
1501    /// caching
1502    #[wasm_bindgen(js_name = LinkDetector)]
1503    pub type LinkDetector;
1504
1505    #[wasm_bindgen(constructor, js_class = "LinkDetector")]
1506    pub fn new(terminal: &JsValue) -> LinkDetector;
1507
1508    /// Register a link provider
1509    #[wasm_bindgen(method, js_name = registerProvider)]
1510    pub fn register_provider(this: &LinkDetector, provider: &ILinkProvider);
1511    /// Get link at the specified buffer position
1512    ///
1513    /// - `col`: Column (0-based)
1514    /// - `row`: Absolute row in buffer (0-based)
1515    ///
1516    /// Returns link at position, or undefined if none.
1517    #[wasm_bindgen(method, js_name = getLinkAt)]
1518    pub fn get_link_at(this: &LinkDetector, col: u32, row: u32) -> Promise<JsOption<ILink>>;
1519    /// Invalidate cache when terminal content changes
1520    ///
1521    /// Should be called on terminal write, resize, or clear
1522    #[wasm_bindgen(method, js_name = invalidateCache)]
1523    pub fn invalidate_cache(this: &LinkDetector);
1524    /// Invalidate cache for specific rows
1525    ///
1526    /// Used when only part of the terminal changed
1527    #[wasm_bindgen(method, js_name = invalidateRows)]
1528    pub fn invalidate_rows(this: &LinkDetector, start_row: u32, end_row: u32);
1529    /// Dispose and cleanup
1530    #[wasm_bindgen(method)]
1531    pub fn dispose(this: &LinkDetector);
1532
1533    /// OSC 8 Hyperlink Provider
1534    ///
1535    /// Detects OSC 8 hyperlinks by scanning for `hyperlink_id` in cells.
1536    /// Automatically handles multi-line links since Ghostty WASM preserves
1537    /// `hyperlink_id` across wrapped lines.
1538    #[wasm_bindgen(js_name = OSC8LinkProvider)]
1539    pub type Osc8LinkProvider;
1540
1541    #[wasm_bindgen(constructor, js_class = "OSC8LinkProvider")]
1542    pub fn new(terminal: &JsValue) -> Osc8LinkProvider;
1543
1544    /// Provide all OSC 8 links on the given row
1545    ///
1546    /// Note: This may return links that span multiple rows
1547    #[wasm_bindgen(method, js_name = provideLinks)]
1548    pub fn provide_links(
1549        this: &Osc8LinkProvider,
1550        y: u32,
1551        callback: &Function<fn(JsOption<Array<ILink>>) -> Undefined>,
1552    );
1553    #[wasm_bindgen(method)]
1554    pub fn dispose(this: &Osc8LinkProvider);
1555
1556    /// URL Regex Provider
1557    ///
1558    /// Detects plain text URLs on a single line using regex. Does not support
1559    /// multi-line URLs or file paths.
1560    ///
1561    /// Supported protocols:
1562    /// - `https://`, `http://`
1563    /// - `mailto:`
1564    /// - `ftp://`, `ssh://`, `git://`
1565    /// - `tel:`, `magnet:`
1566    /// - `gemini://`, `gopher://`, `news:`
1567    #[wasm_bindgen(js_name = UrlRegexProvider)]
1568    pub type UrlRegexProvider;
1569
1570    #[wasm_bindgen(constructor, js_class = "UrlRegexProvider")]
1571    pub fn new(terminal: &JsValue) -> UrlRegexProvider;
1572
1573    /// Provide all regex-detected URLs on the given row
1574    #[wasm_bindgen(method, js_name = provideLinks)]
1575    pub fn provide_links(
1576        this: &UrlRegexProvider,
1577        y: u32,
1578        callback: &Function<fn(JsOption<Array<ILink>>) -> Undefined>,
1579    );
1580    #[wasm_bindgen(method)]
1581    pub fn dispose(this: &UrlRegexProvider);
1582
1583    #[wasm_bindgen(js_name = SelectionManager)]
1584    pub type SelectionManager;
1585
1586    #[wasm_bindgen(constructor, js_class = "SelectionManager")]
1587    pub fn new(
1588        terminal: &Terminal,
1589        renderer: &CanvasRenderer,
1590        wasm_term: &GhosttyTerminal,
1591        textarea: &HtmlTextAreaElement,
1592    ) -> SelectionManager;
1593
1594    /// Get the selected text as a string
1595    #[wasm_bindgen(method, js_name = getSelection)]
1596    pub fn get_selection(this: &SelectionManager) -> JsString;
1597    /// Check if there's an active selection
1598    #[wasm_bindgen(method, js_name = hasSelection)]
1599    pub fn has_selection(this: &SelectionManager) -> bool;
1600    /// Clear the selection
1601    #[wasm_bindgen(method, js_name = clearSelection)]
1602    pub fn clear_selection(this: &SelectionManager);
1603    /// Select all text in the terminal
1604    #[wasm_bindgen(method, js_name = selectAll)]
1605    pub fn select_all(this: &SelectionManager);
1606    /// Select text at specific column and row with length
1607    ///
1608    /// xterm.js compatible API
1609    #[wasm_bindgen(method)]
1610    pub fn select(this: &SelectionManager, column: u32, row: u32, length: u32);
1611    /// Select entire lines from start to end
1612    ///
1613    /// xterm.js compatible API
1614    #[wasm_bindgen(method, js_name = selectLines)]
1615    pub fn select_lines(this: &SelectionManager, start: u32, end: u32);
1616    /// Get selection position as buffer range
1617    ///
1618    /// xterm.js compatible API
1619    #[wasm_bindgen(method, js_name = getSelectionPosition)]
1620    pub fn get_selection_position(this: &SelectionManager) -> Option<IBufferRange>;
1621    /// Deselect all text
1622    ///
1623    /// xterm.js compatible API
1624    #[wasm_bindgen(method)]
1625    pub fn deselect(this: &SelectionManager);
1626    /// Focus the terminal (make it receive keyboard input)
1627    #[wasm_bindgen(method)]
1628    pub fn focus(this: &SelectionManager);
1629    /// Get current selection coordinates (for rendering)
1630    #[wasm_bindgen(method, js_name = getSelectionCoords)]
1631    pub fn get_selection_coords(this: &SelectionManager) -> Option<SelectionCoordinates>;
1632    /// Get dirty selection rows that need redraw (for clearing old highlight)
1633    #[wasm_bindgen(method, js_name = getDirtySelectionRows)]
1634    pub fn get_dirty_selection_rows(this: &SelectionManager) -> Set<Number>;
1635    /// Clear the dirty selection rows tracking (after redraw)
1636    #[wasm_bindgen(method, js_name = clearDirtySelectionRows)]
1637    pub fn clear_dirty_selection_rows(this: &SelectionManager);
1638    /// Get selection change event accessor
1639    #[wasm_bindgen(method, getter, js_name = onSelectionChange)]
1640    pub fn on_selection_change(this: &SelectionManager) -> IEventVoid;
1641    /// Cleanup resources
1642    #[wasm_bindgen(method)]
1643    pub fn dispose(this: &SelectionManager);
1644
1645    #[wasm_bindgen(js_name = Terminal)]
1646    pub type Terminal;
1647
1648    #[wasm_bindgen(constructor, js_class = "Terminal")]
1649    pub fn new(options: Option<&ITerminalOptions>) -> Terminal;
1650
1651    #[wasm_bindgen(method, getter)]
1652    pub fn cols(this: &Terminal) -> u32;
1653    #[wasm_bindgen(method, setter)]
1654    pub fn set_cols(this: &Terminal, value: u32);
1655    #[wasm_bindgen(method, getter)]
1656    pub fn rows(this: &Terminal) -> u32;
1657    #[wasm_bindgen(method, setter)]
1658    pub fn set_rows(this: &Terminal, value: u32);
1659    #[wasm_bindgen(method, getter)]
1660    pub fn element(this: &Terminal) -> Option<HtmlElement>;
1661    #[wasm_bindgen(method, getter)]
1662    pub fn textarea(this: &Terminal) -> Option<HtmlTextAreaElement>;
1663    #[wasm_bindgen(method, getter)]
1664    pub fn buffer(this: &Terminal) -> IBufferNamespace;
1665    #[wasm_bindgen(method, getter)]
1666    pub fn unicode(this: &Terminal) -> IUnicodeVersionProvider;
1667    #[wasm_bindgen(method, getter)]
1668    pub fn options(this: &Terminal) -> ITerminalOptions;
1669    #[wasm_bindgen(method, getter, js_name = wasmTerm)]
1670    pub fn wasm_term(this: &Terminal) -> Option<GhosttyTerminal>;
1671    #[wasm_bindgen(method, getter)]
1672    pub fn renderer(this: &Terminal) -> Option<CanvasRenderer>;
1673    #[wasm_bindgen(method, getter, js_name = viewportY)]
1674    pub fn viewport_y(this: &Terminal) -> f64;
1675    #[wasm_bindgen(method, setter, js_name = viewportY)]
1676    pub fn set_viewport_y(this: &Terminal, value: f64);
1677
1678    #[wasm_bindgen(method, js_name = onData)]
1679    pub fn on_data(this: &Terminal, listener: &Function<fn(JsString) -> Undefined>) -> IDisposable;
1680    #[wasm_bindgen(method, js_name = onResize)]
1681    pub fn on_resize(
1682        this: &Terminal,
1683        listener: &Function<fn(ResizeEvent) -> Undefined>,
1684    ) -> IDisposable;
1685    #[wasm_bindgen(method, js_name = onBell)]
1686    pub fn on_bell(this: &Terminal, listener: &Function<fn() -> Undefined>) -> IDisposable;
1687    #[wasm_bindgen(method, js_name = onSelectionChange)]
1688    pub fn on_selection_change(
1689        this: &Terminal,
1690        listener: &Function<fn() -> Undefined>,
1691    ) -> IDisposable;
1692    #[wasm_bindgen(method, js_name = onKey)]
1693    pub fn on_key(this: &Terminal, listener: &Function<fn(IKeyEvent) -> Undefined>) -> IDisposable;
1694    #[wasm_bindgen(method, js_name = onTitleChange)]
1695    pub fn on_title_change(
1696        this: &Terminal,
1697        listener: &Function<fn(JsString) -> Undefined>,
1698    ) -> IDisposable;
1699    #[wasm_bindgen(method, js_name = onScroll)]
1700    pub fn on_scroll(this: &Terminal, listener: &Function<fn(Number) -> Undefined>) -> IDisposable;
1701    #[wasm_bindgen(method, js_name = onRender)]
1702    pub fn on_render(
1703        this: &Terminal,
1704        listener: &Function<fn(RenderEvent) -> Undefined>,
1705    ) -> IDisposable;
1706    #[wasm_bindgen(method, js_name = onCursorMove)]
1707    pub fn on_cursor_move(this: &Terminal, listener: &Function<fn() -> Undefined>) -> IDisposable;
1708
1709    /// Open terminal in a parent element
1710    ///
1711    /// Initializes all components and starts rendering. Requires a pre-loaded
1712    /// [`Ghostty`] instance passed to the constructor.
1713    #[wasm_bindgen(method)]
1714    pub fn open(this: &Terminal, parent: &HtmlElement);
1715
1716    /// Write data to terminal
1717    #[wasm_bindgen(method, js_name = write)]
1718    pub fn write_str(this: &Terminal, data: &str, callback: Option<&Function<fn() -> Undefined>>);
1719    /// Write data to terminal
1720    #[wasm_bindgen(method, js_name = write)]
1721    pub fn write_u8_array(
1722        this: &Terminal,
1723        data: &Uint8Array,
1724        callback: Option<&Function<fn() -> Undefined>>,
1725    );
1726
1727    /// Write data with newline
1728    #[wasm_bindgen(method, js_name = writeln)]
1729    pub fn writeln_str(this: &Terminal, data: &str, callback: Option<&Function<fn() -> Undefined>>);
1730    /// Write data with newline
1731    #[wasm_bindgen(method, js_name = writeln)]
1732    pub fn writeln_u8_array(
1733        this: &Terminal,
1734        data: &Uint8Array,
1735        callback: Option<&Function<fn() -> Undefined>>,
1736    );
1737
1738    /// Paste text into terminal (triggers bracketed paste if supported)
1739    #[wasm_bindgen(method)]
1740    pub fn paste(this: &Terminal, data: &str);
1741    /// Input data into terminal (as if typed by user)
1742    ///
1743    /// - `was_user_input`: If true, triggers `onData` event (default: false for
1744    ///   compat with some apps)
1745    #[wasm_bindgen(method)]
1746    pub fn input(this: &Terminal, data: &str, was_user_input: Option<bool>);
1747    /// Resize terminal
1748    #[wasm_bindgen(method)]
1749    pub fn resize(this: &Terminal, cols: u32, rows: u32);
1750    /// Clear terminal screen
1751    #[wasm_bindgen(method)]
1752    pub fn clear(this: &Terminal);
1753    /// Reset terminal state
1754    #[wasm_bindgen(method)]
1755    pub fn reset(this: &Terminal);
1756    /// Focus terminal input
1757    #[wasm_bindgen(method)]
1758    pub fn focus(this: &Terminal);
1759    /// Blur terminal (remove focus)
1760    #[wasm_bindgen(method)]
1761    pub fn blur(this: &Terminal);
1762    /// Load an addon
1763    #[wasm_bindgen(method, js_name = loadAddon)]
1764    pub fn load_addon(this: &Terminal, addon: &ITerminalAddon);
1765
1766    /// Get the selected text as a string
1767    #[wasm_bindgen(method, js_name = getSelection)]
1768    pub fn get_selection(this: &Terminal) -> JsString;
1769    /// Check if there's an active selection
1770    #[wasm_bindgen(method, js_name = hasSelection)]
1771    pub fn has_selection(this: &Terminal) -> bool;
1772    /// Clear the current selection
1773    #[wasm_bindgen(method, js_name = clearSelection)]
1774    pub fn clear_selection(this: &Terminal);
1775    /// Select all text in the terminal
1776    #[wasm_bindgen(method, js_name = selectAll)]
1777    pub fn select_all(this: &Terminal);
1778    /// Select text at specific column and row with length
1779    #[wasm_bindgen(method)]
1780    pub fn select(this: &Terminal, column: u32, row: u32, length: u32);
1781    /// Select entire lines from start to end
1782    #[wasm_bindgen(method, js_name = selectLines)]
1783    pub fn select_lines(this: &Terminal, start: u32, end: u32);
1784    /// Get the current viewport Y position.
1785    ///
1786    /// This is the number of lines scrolled back from the bottom of the
1787    /// scrollback buffer. It may be fractional during smooth scrolling.
1788    #[wasm_bindgen(method, js_name = getViewportY)]
1789    pub fn get_viewport_y(this: &Terminal) -> f64;
1790    /// Get selection position as buffer range
1791    #[wasm_bindgen(method, js_name = getSelectionPosition)]
1792    pub fn get_selection_position(this: &Terminal) -> Option<IBufferRange>;
1793
1794    /// Attach a custom keyboard event handler
1795    ///
1796    /// Returns true to prevent default handling
1797    #[wasm_bindgen(method, js_name = attachCustomKeyEventHandler)]
1798    pub fn attach_custom_key_event_handler(
1799        this: &Terminal,
1800        handler: &Function<fn(KeyboardEvent) -> Boolean>,
1801    );
1802    /// Attach a custom wheel event handler (Phase 2)
1803    ///
1804    /// Returns true to prevent default handling
1805    #[wasm_bindgen(method, js_name = attachCustomWheelEventHandler)]
1806    pub fn attach_custom_wheel_event_handler(
1807        this: &Terminal,
1808        handler: Option<&Function<fn(WheelEvent) -> Boolean>>,
1809    );
1810    /// Register a custom link provider
1811    ///
1812    /// Multiple providers can be registered to detect different types of links
1813    #[wasm_bindgen(method, js_name = registerLinkProvider)]
1814    pub fn register_link_provider(this: &Terminal, provider: &ILinkProvider);
1815
1816    /// Scroll viewport by a number of lines
1817    ///
1818    /// - `amount`: Number of lines to scroll (positive = down, negative = up)
1819    #[wasm_bindgen(method, js_name = scrollLines)]
1820    pub fn scroll_lines(this: &Terminal, amount: i32);
1821    /// Scroll viewport by a number of pages
1822    ///
1823    /// - `amount`: Number of pages to scroll (positive = down, negative = up)
1824    #[wasm_bindgen(method, js_name = scrollPages)]
1825    pub fn scroll_pages(this: &Terminal, amount: i32);
1826    /// Scroll viewport to the top of the scrollback buffer
1827    #[wasm_bindgen(method, js_name = scrollToTop)]
1828    pub fn scroll_to_top(this: &Terminal);
1829    /// Scroll viewport to the bottom (current output)
1830    #[wasm_bindgen(method, js_name = scrollToBottom)]
1831    pub fn scroll_to_bottom(this: &Terminal);
1832    /// Scroll viewport to a specific line in the buffer
1833    ///
1834    /// - `line`: Line number (0 = top of scrollback, scrollbackLength = bottom)
1835    #[wasm_bindgen(method, js_name = scrollToLine)]
1836    pub fn scroll_to_line(this: &Terminal, line: u32);
1837
1838    /// Dispose terminal and clean up resources
1839    #[wasm_bindgen(method)]
1840    pub fn dispose(this: &Terminal);
1841
1842    /// Get a line from native WASM scrollback buffer
1843    ///
1844    /// Implements [`IScrollbackProvider`]
1845    #[wasm_bindgen(method, js_name = getScrollbackLine)]
1846    pub fn get_scrollback_line(this: &Terminal, offset: u32) -> Option<Array<GhosttyCell>>;
1847    /// Get scrollback length from native WASM
1848    ///
1849    /// Implements [`IScrollbackProvider`]
1850    #[wasm_bindgen(method, js_name = getScrollbackLength)]
1851    pub fn get_scrollback_length(this: &Terminal) -> u32;
1852    /// Query terminal mode state
1853    ///
1854    /// - `mode`: Mode number (e.g., 2004 for bracketed paste)
1855    /// - `is_ansi`: True for ANSI modes, false for DEC modes (default: false)
1856    ///
1857    /// Returns true if mode is enabled
1858    #[wasm_bindgen(method, js_name = getMode)]
1859    pub fn get_mode(this: &Terminal, mode: u32, is_ansi: Option<bool>) -> bool;
1860    /// Check if bracketed paste mode is enabled
1861    #[wasm_bindgen(method, js_name = hasBracketedPaste)]
1862    pub fn has_bracketed_paste(this: &Terminal) -> bool;
1863    /// Check if focus event reporting is enabled
1864    #[wasm_bindgen(method, js_name = hasFocusEvents)]
1865    pub fn has_focus_events(this: &Terminal) -> bool;
1866    /// Check if mouse tracking is enabled
1867    #[wasm_bindgen(method, js_name = hasMouseTracking)]
1868    pub fn has_mouse_tracking(this: &Terminal) -> bool;
1869}