Commit Graph

7795 Commits

Author SHA1 Message Date
Mitchell Hashimoto
fd0f9bb843 terminal: device attributes 2025-10-24 07:17:44 -07:00
Mitchell Hashimoto
a4a37534d7 terminal: missed some invoke charsets 2025-10-24 07:11:09 -07:00
Mitchell Hashimoto
e347ab6915 terminal: device attributes 2025-10-24 07:08:34 -07:00
Mitchell Hashimoto
109376115b terminal: convert dcs 2025-10-23 21:29:18 -07:00
Mitchell Hashimoto
6902d89d91 terminal: convert APC 2025-10-23 21:24:31 -07:00
Mitchell Hashimoto
b91149f0fe terminal: simple esc dispatch 2025-10-23 21:18:51 -07:00
Mitchell Hashimoto
9cd4594356 terminal: active status display 2025-10-23 21:14:21 -07:00
Mitchell Hashimoto
f68ea7c907 terminal: many more conversions 2025-10-23 21:10:25 -07:00
Mitchell Hashimoto
2520e27aef terminal: kitty keyboard actions 2025-10-23 20:55:08 -07:00
Mitchell Hashimoto
b7ea979f38 terminal: zero-arg actions 2025-10-23 20:47:02 -07:00
Mitchell Hashimoto
0df4d5c5a4 terminal: margins 2025-10-23 20:37:34 -07:00
Mitchell Hashimoto
c1e57dd330 terminal: setprotectedmode 2025-10-23 20:31:17 -07:00
Mitchell Hashimoto
25eee9379d terminal: request mode 2025-10-23 20:26:14 -07:00
Mitchell Hashimoto
b6ac4c764f terminal: modify_other_keys 2025-10-23 20:26:11 -07:00
Mitchell Hashimoto
94a8fa05cb terminal: convert modes 2025-10-23 20:07:45 -07:00
Mitchell Hashimoto
dc5406781f terminal: many more conversions 2025-10-23 19:56:13 -07:00
Mitchell Hashimoto
37016d8b89 terminal: erase/insert lines, characters, etc. 2025-10-23 16:44:49 -07:00
Mitchell Hashimoto
b0fb3ef9a9 terminal: erase display conversion 2025-10-23 16:38:10 -07:00
Mitchell Hashimoto
b5da54d925 terminal: horizontal tab 2025-10-23 16:28:38 -07:00
Mitchell Hashimoto
ccd821a0ff terminal: convert cursor movements 2025-10-23 16:22:43 -07:00
Mitchell Hashimoto
2ef89c153a terminal: convert C0 2025-10-23 15:52:42 -07:00
Mitchell Hashimoto
f7189d14b9 terminal: convert Stream to use Action tagged union 2025-10-23 15:50:56 -07:00
Mitchell Hashimoto
099dcbe04d lib: add a TaggedUnion helper to create C ABI compatible tagged unions 2025-10-23 15:50:54 -07:00
Mitchell Hashimoto
fb5b8d7968 input: command palette actions must use formatter, not tag (#9325)
Regression from our Zig 0.15 migration.
2025-10-23 12:49:55 -07:00
Mitchell Hashimoto
bdbda2fd83 input: accidentally merged a loud log line 2025-10-22 15:36:21 -07:00
Mitchell Hashimoto
c133fac7e7 lib-vt: wasm convenience functions and a simple example (#9309)
This adds a set of Wasm convenience functions to ease memory management.
These are all prefixed with `ghostty_wasm` and are documented as part of
the standard Doxygen docs.

I also added a very simple single-page HTML example that demonstrates
how to use the Wasm module for key encoding.

This also adds a bunch of safety checks to the C API to verify that
valid values are actually passed to the function. This is an easy to hit
bug.

**AI disclosure:** The example is AI-written with Amp. I read through
all the code and understand it but I can't claim there isn't a better
way, I'm far from a JS expert. It is simple and works currently though.
Happy to see improvements if anyone wants to contribute.
2025-10-22 14:25:52 -07:00
Mitchell Hashimoto
9dc2e5978f lib-vt: enable freestanding wasm builds (#9301)
This makes `libghostty-vt` build for freestanding wasm targets (aka a
browser) and produce a `ghostty-vt.wasm` file. This exports the same C
API that libghostty-vt does.

This commit specifically makes the changes necessary for the build to
build properly and for us to run the build in CI. We don't yet actually
try using it...
2025-10-21 20:55:54 -07:00
Jared Gizersky
3548acfac6 os: handle nil languageCode/countryCode in setLangFromCocoa (#9290)
Fixes a crash when NSLocale returns nil for languageCode or countryCode
properties. This can happen when the app launches without locale
environment variables set.

The crash occurs at `src/os/locale.zig:87-88` when trying to call
`getProperty()` on a nil object. The fix adds a null check and falls
back to `en_US.UTF-8` instead of dereferencing null.

## Testing
Tested by running with locale variables unset:
```bash
unset LC_ALL && ./zig-out/Ghostty.app/Contents/MacOS/ghostty
```

Before: segmentation fault  
After: launches successfully with fallback locale
2025-10-20 20:27:04 -07:00
Mitchell Hashimoto
da165fc3cf input: modify other keys 2 should use all mods, ignore consumed mods (#9289)
Fixes #8900

Our xterm modify other keys state 2 encoding was stripped consumed mods
from the keyboard event. This doesn't match xterm or other popular
terminal emulators (but most importantly: xterm). Use the full set of
mods and add a test to verify this.

Reproduction:

```
printf '\033[>4;2m' 
cat
```

Then press `ctrl+shift+h` and compare across terminals.
2025-10-20 14:41:35 -07:00
Mitchell Hashimoto
0546606e05 build: add -Demit-themes option to emit/omit theme resources (#9288)
We'll backport this to 1.2.x for distros that would prefer this.
2025-10-20 13:14:42 -07:00
Matthew Hrehirchuk
2696d50ca4 feat: added mouse-reporting / toggle-mouse-reporting (#9282)
Closes #8430

A few questions:
* Should I set a default keybind for `toggle-mouse-reporting`? The issue
mentioned one, it's currently unset.
* Am I handling the `toggle-mouse-reporting` action properly in
`performAction` (gtk) / `action` (macos)?

Copilot was used to understand the codebase, but code was authored
manually.
2025-10-19 20:45:37 -07:00
Mitchell Hashimoto
1b86691896 termio: use a union to represent how a process is started (#9278)
This cleans up some of our termio exec code by unifying process launch
state into a single union type. This makes it easier to distinguish
between the current two mutually exclusive modes of launching a process:
fork/exec and flatpak dbus commands.

It also ensures everyplace we touch related to process launching is
forced to address every case (exhaustive switch handling). I did find
one resource cleanup bug based on this cleanup, which is also fixed
here. This just improves memory slightly so it's not a big deal.

If we add future ways to launch processes, we can add a new union case.
For example, I originally had a `posix_spawn` option while I was
experimenting with that before abandoning it (see #9274).
2025-10-19 20:43:28 -07:00
Jon Parise
e522482710 cli: fix +ssh-cache IPv6 address validation
The host validation code previously expected IPv6 addresses to be
enclosed in [brackets], but that's not how ssh(1) expects them.

This change removes that requirement and reimplements the host
validation routine to check for valid hostnames and IP addresses (IPv4
and IPv6) using standard routines rather than custom logic.
2025-10-19 20:31:32 -04:00
Mitchell Hashimoto
40e558f953 os: remove unused UrlParsingError (#9275)
This is no longer used as of e5247f6d.
2025-10-19 15:16:45 -07:00
Jon Parise
010cbce220 os: add RFC 1123-compliant hostname.isValid
std.net.isValidHostname is currently too generous. It considers strings
like ".example.com", "exa..mple.com", and "-example.com" to be valid
hostnames, which is incorrect according to RFC 1123 (the currently
accepted standard).

Until the standard library function is improved, we can use this local
implementation that does follow the RFC 1123 standard.

I asked Claude to perform an audit of the code based on its understand
of the RFC. It suggested some additional test cases and considers the
overall implementation to be robust (its words) and standards compliant.

Ref: https://www.rfc-editor.org/rfc/rfc1123
2025-10-19 14:36:02 -04:00
Jon Parise
73da748390 os: remove unused UrlParsingError
This is no longer used as of e5247f6d.
2025-10-19 13:12:32 -04:00
Sola
c6788dd178 fix: fish shell integration should not modify universal path variable
`fish_add_path` by default updates the `fish_user_paths` universal
variable which makes the modification persist across shell sessions.

The integration also tries to update the `fish_user_paths` when the
desired path already appears in the `PATH` environment variable but
not in `fish_user_paths`. Because `fish_user_paths` will always be
inserted before the inherited `PATH` env. This makes the added path
unintentionally has a higher priority.

This patch makes the above issues by adding `--global` and `--path`
options to `fish_user_paths` which limits the modification scope and
ensures that the path won't be added if it already exists in `PATH`.
2025-10-19 20:46:48 +08:00
Mitchell Hashimoto
be608ea2d1 renderer: don't allow the scrollbar state to block the renderer (#9270)
This fixes the source of a deadlock that some tip users have hit. If our
surface mailbox is full and there is a dirty scrollbar state, then
drawFrame would block forever trying to queue to the surface mailbox.

We now fail instantly if the queue is full and keep the scrollbar state
dirty. We can try again on the next frame, it's not a critical thing to
get updated.
2025-10-18 21:34:27 -07:00
Mitchell Hashimoto
3a9eedcd15 renderer: don't allow the scrollbar state to block the renderer
This fixes the source of a deadlock that some tip users have hit. If our 
surface mailbox is full and there is a dirty scrollbar state, then
drawFrame would block forever trying to queue to the surface mailbox.

We now fail instantly if the queue is full and keep the scrollbar state
dirty. We can try again on the next frame, it's not a critical thing to
get updated.
2025-10-18 21:30:11 -07:00
tdslot
be0da4845c 🌐 i18n(locale): add lithuanian language support (#8711)
Co-authored-by: Andrius Budvytis <154380884+abudvytis@users.noreply.github.com>
2025-10-18 19:27:39 +02:00
Daniel Wennberg
ad9f9dc11e font: Default to light hinting in FreeType 2025-10-17 15:04:04 -07:00
Mitchell Hashimoto
1cc22f93ca renderer: force a full rebuild on any font grid change
Fixes #2731 (again)

This regressed in 1.2 due to the renderer rework missing porting this. I
believe this issue is still valid even with the rework since the font
grid changes the atlas and if there are still cached cells that
reference the old atlas coordinates it will produce garbage.
2025-10-17 14:46:58 -07:00
Mitchell Hashimoto
ed443bc6ed gtk: Scrollbars 2025-10-17 09:19:02 -07:00
Mitchell Hashimoto
4b34b2389a config: add scrollbar config to control when scrollbars appear 2025-10-16 14:06:48 -07:00
Mitchell Hashimoto
2937aff513 gtk: mark scrollbar as unimplemented 2025-10-16 09:36:47 -07:00
Mitchell Hashimoto
c86266cd90 input: scroll_to_row action 2025-10-16 09:11:03 -07:00
Mitchell Hashimoto
135136f733 terminal: PageList scroll to absolute row function 2025-10-16 09:11:03 -07:00
Mitchell Hashimoto
da7736cd44 renderer: emit scrollbar apprt event when scrollbar changes 2025-10-15 21:45:01 -07:00
Mitchell Hashimoto
e1b527fb9a core: PageList tracks minimum metadata for rendering a scrollbar (#9225)
Related to #111

This adds the necessary logic and data for the `PageList` data structure
to keep track of **total length** of the screen, **offset** into the
viewport, and **length** of the viewport. These three values are
necessary to _render_ a scrollbar. This PR updates the renderer to grab
this information but stops short of actually drawing a scrollbar (which
we'll do with native UI), in the interest of having a PR that doesn't
contain too many changes.

**This doesn't yet draw a scrollbar, these are just the internal changes
necessary to support it.**

## Background

The `PageList` structure is very core to how we represent terminal
state. It maintains a doubly linked list of "pages" (not literally
virtual memory pages, but close). Each page stores cell information,
styles, hyperlinks, etc fully self-contained in a contiguous sets of VM
pages using offset addresses rather than full pointers. **Pages are not
guaranteed to be equal sizes.** (This is where scrollbars get difficult)

Because it is a linked list structure of non-equal sized nodes, it isn't
amenable to typical scrollbar behavior. A scrollbar needs to know: full
size, offset, and length in order to draw the scrollbar properly.
Getting these values naively is `O(N)` within the data structure that is
on the hottest IO performance path in all of Ghostty.

## Implementation

### PageList

We now maintain two cached values for **total length** and **viewport
offset**.

The total length is relatively straightforward, we just have to be
careful to update it in every operation that could add or remove rows.
I've done this and ensured that every place we update it is covered with
unit test coverage.

The viewport offset is nasty, but I came up with what I believe is a
good solution. The viewport when arbitrarily scrolled is defined as a
direct pointer to the linked list node plus a row offset into that node.
The only way to calculate offset from the top is `O(N)`.

But we have a couple shortcuts:

1. If the viewport is at the bottom (most common) or top, calculating
the offset is `O(1)`: bottom is `total_rows - active_rows`, both readily
available. And top is `0` by definition.

2. Operations on the PageList typically add or remove rows. We don't do
arbitrary linked list surgery. If we instrument those areas with delta
updates to our cache, we can avoid the `O(N)` cost for most operations,
including scrolling a scrollbar. The only expensive operation is a full,
arbitrary jump (new node pointer).

Point 1 was quick to implement, so I focused all the complexity on point
2. Whenever we have an operation that adds or removes rows (for example
pruning the scroll back, adding more, erase rows within the active area,
etc.) then I do the math to calculate the delta change required for the
offset if we've already calculated it, and apply that directly.

### Renderer

The other issue was how to notify the apprts of scrollbar state. Sending
messages on any terminal change within the IO thread is a non-option
because (1) sending messages is slow (2) the terminal changes a lot and
(3) any slowness in the IO thread slows down overall terminal
throughput.

The solution was to **trigger scrollbar notifications with the renderer
vsync**. We read the scrollbar information when we render a frame,
compare it to renderer previous state, and if the scrollbar changed,
send a message to the apprt _after the frame is GPU-renderer_.

The renderer spends _most_ of its time sleeping compared to the IO
thread, and has more opportunities for optimizing its awake time.
Additionally, there's no reason to update the scrollbar information if
the renderer hasn't rendered the new frames because the user can't even
see the stuff the scrollbar wants to scroll to. We're talking about
millisecond scale stuff here at worst but it adds up.

## Performance

No noticeable performance impact for the additional metrics:

<img width="1012" height="738" alt="image"
src="https://github.com/user-attachments/assets/4ed0a3e8-6d76-40c1-b249-e34041c2f6fd"
/>

## AI Usage

I used Amp to help audit the codebase and write tests. I wrote all the
main implementation code manually. I came up with the main design
myself. Relevant threads:

-
https://ampcode.com/threads/T-95fff686-75bb-4553-a2fb-e41fe4cd4b77#message-0-block-0
-
https://ampcode.com/threads/T-48e9a288-b280-4eec-83b7-ca73d029b4ef#message-91-block-0

## Future

This is just the internal changes necessary to _draw_ a scrollbar. There
will be other changes we'll need to add to handle grabbing and actually
jumping the scrollbar. I have a good idea of how to implement those
performantly as well.
2025-10-15 19:42:49 -07:00
Mitchell Hashimoto
014a2e0042 termio: color change operations must gracefully handle renderer mailbox full (#9224)
Fixes #9191

This changes our color change operations from writing to the renderer
mailbox directly to using our `rendererMailboxWriter` function which
handles the scenario where the mailbox is full by yielding the lock,
waking up the renderer, and retrying later.

This is a known deadlock scenario we've worked around since the private
beta days, but unfortunately this slipped through and I didn't catch it
in review.

What happens here is it's possible with certain escape sequences for the
IO thread to saturate other mailboxes with messages while holding the
terminal state lock. This can happen to any thread. This ultimately
leads to starvation and all threads deadlock.

Our IO thread is the only thread that produces this kind of massive
stream of events while holding the lock, so we have helpers in it to
attempt to queue (cheap, fast) and if that fails then to yield the lock,
wakeup the target thread, requeue, and grab the lock again (expensive,
slow).
2025-10-15 16:01:26 -07:00