1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
//! A terminal on libghostty-vt, the terminal emulation library from
//! [Ghostty](https://ghostty.org), behind the `ghostty` feature.
//!
//! The pieces:
//!
//! - [`TerminalState`] is the entity: it holds the latest [`TerminalFrame`],
//! the program's [`TerminalStatus`], the selection and the focus, and it
//! sends [`TerminalInput`] to its source.
//! - [`Terminal`] is the element that paints a state and routes keys, the
//! pointer and the input method to it.
//! - A [`FrameSource`] produces frames. [`Engine`] runs a [`ByteSource`]
//! through a Ghostty terminal on an owner thread; [`LocalPty`] (feature
//! desktop targets) is the byte source for a local program; [`StreamSource`]
//! is one the application feeds itself, such as a remote session or its
//! own pty; [`FixtureSource`] parses canned bytes for tests and galleries.
//! - [`crate::shell`] resolves the user's shell, its login command and
//! the environment the way Ghostty does, for applications that start the
//! program themselves.
//!
//! # Use it
//!
//! Enable the `ghostty` feature, with `cargo add gpui-cn --features ghostty`
//! or in `Cargo.toml`:
//!
//! ```toml
//! gpui-cn = { version = "0.5", features = ["ghostty", "jetbrains-mono"] }
//! ```
//!
//! Building it needs Zig 0.16 on `PATH`; the first build downloads
//! Ghostty's pinned source. Whether a terminal runs a local shell or another
//! source, and whether idle terminals park, are runtime choices.
//! After `gpui_cn::init`, a view holds a [`TerminalState`] and renders a
//! [`Terminal`] for it:
//!
//! ```no_run
//! # #[cfg(not(any(target_os = "ios", target_os = "android")))]
//! # mod example {
//! use gpui_cn::terminal::{LocalTerminalOptions, Terminal, TerminalConfig, TerminalState};
//! use gpui_kit::*;
//!
//! struct Shell {
//! terminal: Entity<TerminalState>,
//! }
//!
//! impl Render for Shell {
//! fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
//! div().size_full().child(Terminal::new("shell", &self.terminal))
//! }
//! }
//!
//! pub fn main() {
//! gpui_kit::application()
//! .with_assets(gpui_kit::assets::Assets)
//! .run(|cx| {
//! gpui_kit::init(cx);
//! gpui_cn::init(cx);
//! gpui_kit::open_window(WindowOptions::default(), cx, |window, cx| {
//! cx.new(|cx| {
//! // The user's login shell, picked as Ghostty picks it.
//! let terminal = cx.new(|cx| {
//! TerminalState::local(
//! LocalTerminalOptions::default(),
//! TerminalConfig::default(),
//! window,
//! cx,
//! )
//! });
//! cx.observe(&terminal, |_, _, cx| cx.notify()).detach();
//! Shell { terminal }
//! })
//! })
//! .expect("failed to open window");
//! });
//! }
//! # }
//! # fn main() {}
//! ```
//!
//! A remote session or an application's own pty feeds a [`StreamSource`]
//! instead of a local pty:
//!
//! ```no_run
//! # use gpui_cn::terminal::*;
//! # fn remote(window: &mut gpui_kit::Window, cx: &mut gpui_kit::Context<TerminalState>) -> TerminalState {
//! let (source, peer) = StreamSource::new();
//! peer.output(b"$ "); // the program's output; input arrives on peer.events()
//! TerminalState::new(Engine::new(source, EngineOptions::default()), TerminalConfig::default(), window, cx)
//! # }
//! ```
//!
//! A host that keeps the terminal elsewhere, such as a server that sends
//! the rows it wants drawn, implements [`FrameSource`] and publishes
//! frames it builds itself to the [`FrameSink`]. The builders on
//! [`TerminalFrame`], [`frame::TerminalRow`], [`frame::Style`],
//! [`frame::CellSpan`], [`frame::StyleRun`], [`frame::Cursor`] and
//! [`TerminalSnapshot`] make them. The [`FrameHandle`] it returns gets the
//! input, the measured grid and the request for the next frame; its `copy`
//! answers a selection that reaches scrollback the frame does not carry.
//! `tests/terminal_hosted.rs` is a small example.
//!
//! A local pty reports the process in the terminal's foreground, such as
//! the shell or an editor it started: [`TerminalState::foreground`] reads
//! it, [`TerminalEvent::ForegroundChanged`] reports a change, and
//! [`TerminalState::needs_confirm_close`] says whether closing would end a
//! program other than the shell. The engine looks after output only, so a
//! quiet terminal costs nothing.
//!
//! # Key bindings
//!
//! `gpui_cn::init` binds no terminal keys. A focused terminal takes the
//! keys a program needs on its own, without a key binding: every key it
//! can encode goes to the program, Tab and Shift-Tab too, which
//! `gpui-base`'s `Root` would otherwise use to move focus, and Ctrl-C,
//! which `Root` binds to copy outside macOS. Escape drops a selection
//! first, when there is one. Cmd-C on macOS copies the selection through
//! `Root`'s copy key.
//!
//! The rest are [`actions`] an application binds in the [`KEY_CONTEXT`]
//! key context. [`default_key_bindings`] holds Ghostty's keys for them:
//! copy and paste (Cmd-C and Cmd-V on macOS, Ctrl-Shift-C and Ctrl-Shift-V
//! elsewhere), select all, clear, Shift with Page Up, Page Down, Home,
//! End, Up and Down to scroll, and the font zoom: Cmd-= or Cmd-+ in, Cmd--
//! out and Cmd-0 back (Ctrl elsewhere), one point a step. An application
//! installs them, all or some, or binds its own:
//!
//! ```no_run
//! use gpui_cn::terminal::{KEY_CONTEXT, actions, default_key_bindings};
//! use gpui_kit::{App, KeyBinding, NoAction};
//!
//! fn keys(cx: &mut App) {
//! cx.bind_keys(default_key_bindings());
//! cx.bind_keys([
//! // Zoom with Cmd-Up instead of Cmd-=.
//! KeyBinding::new("cmd-up", actions::IncreaseFontSize, Some(KEY_CONTEXT)),
//! KeyBinding::new("cmd-=", NoAction, Some(KEY_CONTEXT)),
//! ]);
//! }
//! ```
//!
//! A binding an application adds in [`KEY_CONTEXT`] wins over a key the
//! terminal would take, Tab included. The bindings are per context, not
//! per terminal: every terminal in the application has them, and only
//! the focused one acts on a key.
//!
//! Tabs, splits, pane zoom, a leader key and context menus are the
//! application's to build; the gallery's Terminal story shows one way.
//!
//! The grid uses the theme's code font and code font size unless the
//! [`TerminalAppearance`] names others, so the `jetbrains-mono` feature
//! gives it JetBrains Mono. The colors are Ghostty's defaults;
//! [`TerminalColors::from_ghostty_theme`] reads a Ghostty theme file.
//!
//! The engine never blocks the UI: frames arrive through a latest-wins slot
//! and an async wake, input goes through a bounded queue that Ctrl+C jumps,
//! a hidden terminal keeps parsing but publishes nothing, and synchronized
//! output (mode 2026) holds frames for at most one second. The engine never
//! waits on the program either: a write the pty cannot take yet resumes
//! when it has room, and at most a megabyte of output waits for the parser
//! before the pty holds the program back, so a large paste into a program
//! that is busy writing cannot deadlock.
//!
//! Derived from Herdr (Apache-2.0); the block, decoration and element
//! structure are adapted from Muxy v2 (MIT).
pub use TerminalAppearance;
pub use ;
pub use ;
pub use ;
pub use Geometry;
pub use TerminalInput;
pub use ;
pub use LocalPty;
pub use ;
pub use ;
pub use ;
pub use ThemeError;
/// Actions dispatched in the [`KEY_CONTEXT`] key context.
/// Ghostty's keys for the terminal [`actions`], in the [`KEY_CONTEXT`] key
/// context, for an application to install with `cx.bind_keys(..)`. A
/// terminal works without them; see [Key bindings](self#key-bindings).