ZIm/crates/terminal_view
Michael Sloan 5fafab6e52
Migrate to schemars version 1.0 (#33635)
The major change in schemars 1.0 is that now schemas are represented as
plain json values instead of specialized datatypes. This allows for more
concise construction and manipulation.

This change also improves how settings schemas are generated. Each top
level settings type was being generated as a full root schema including
the definitions it references, and then these were merged. This meant
generating all shared definitions multiple times, and might have bugs in
cases where there are two types with the same names.

Now instead the schemar generator's `definitions` are built up as they
normally are and the `Settings` trait no longer has a special
`json_schema` method. To handle types that have schema that vary at
runtime (`FontFamilyName`, `ThemeName`, etc), values of
`ParameterizedJsonSchema` are collected by `inventory`, and the schema
definitions for these types are replaced.

To help check that this doesn't break anything, I tried to minimize the
overall [schema
diff](https://gist.github.com/mgsloan/1de549def20399d6f37943a3c1583ee7)
with some patches to make the order more consistent + schemas also
sorted with `jq -S .`. A skim of the diff shows that the diffs come
from:

* `enum: ["value"]` turning into `const: "value"`
* Differences in handling of newlines for "description"
* Schemas for generic types no longer including the parameter name, now
all disambiguation is with numeric suffixes
* Enums now using `oneOf` instead of `anyOf`.

Release Notes:

- N/A
2025-06-30 21:07:28 +00:00
..
scripts Fix nix build (#26270) 2025-03-10 01:06:11 -07:00
src Migrate to schemars version 1.0 (#33635) 2025-06-30 21:07:28 +00:00
Cargo.toml chore: Make terminal_view own the TerminalSlashCommand (#31070) 2025-05-21 09:27:54 +00:00
LICENSE-GPL chore: Change AGPL-licensed crates to GPL (except for collab) (#4231) 2024-01-24 00:26:58 +01:00
README.md vim . to replay 2023-09-06 13:49:55 -06:00

Design notes:

This crate is split into two conceptual halves:

  • The terminal.rs file and the src/mappings/ folder, these contain the code for interacting with Alacritty and maintaining the pty event loop. Some behavior in this file is constrained by terminal protocols and standards. The Zed init function is also placed here.
  • Everything else. These other files integrate the Terminal struct created in terminal.rs into the rest of GPUI. The main entry point for GPUI is the terminal_view.rs file and the modal.rs file.

ttys are created externally, and so can fail in unexpected ways. However, GPUI currently does not have an API for models than can fail to instantiate. TerminalBuilder solves this by using Rust's type system to split tty instantiation into a 2 step process: first attempt to create the file handles with TerminalBuilder::new(), check the result, then call TerminalBuilder::subscribe(cx) from within a model context.

The TerminalView struct abstracts over failed and successful terminals, passing focus through to the associated view and allowing clients to build a terminal without worrying about errors.

#Input

There are currently many distinct paths for getting keystrokes to the terminal:

  1. Terminal specific characters and bindings. Things like ctrl-a mapping to ASCII control character 1, ANSI escape codes associated with the function keys, etc. These are caught with a raw key-down handler in the element and are processed immediately. This is done with the try_keystroke() method on Terminal

  2. GPU Action handlers. GPUI clobbers a few vital keys by adding bindings to them in the global context. These keys are synthesized and then dispatched through the same try_keystroke() API as the above mappings

  3. IME text. When the special character mappings fail, we pass the keystroke back to GPUI to hand it to the IME system. This comes back to us in the View::replace_text_in_range() method, and we then send that to the terminal directly, bypassing try_keystroke().

  4. Pasted text has a separate pathway.

Generally, there's a distinction between 'keystrokes that need to be mapped' and 'strings which need to be written'. I've attempted to unify these under the '.try_keystroke()' API and the .input() API (which try_keystroke uses) so we have consistent input handling across the terminal