Commit Graph

13815 Commits

Author SHA1 Message Date
Mitchell Hashimoto
ec2912dbaf docs: bell border feature is available on macOS (#10242)
As of commit fe55d90 and PR #8768 this feature is also available on
macOS.
2026-01-09 11:40:12 -08:00
Martin Müller
d94ba5cf10 docs: add bell border feature version availability
Commit 22fc90f (PR #8222) on GTK and commit fe55d90 (PR #8768) on macOS.
2026-01-09 18:46:00 +01:00
Mitchell Hashimoto
51aed4d8b3 Binding internals improvements (#10243)
A handful of improvements. See individual commits.

1. **Actually compare values for the binding set.** This sounds crazy,
but up until now (for _years_) we've only compared _the hash value_ of a
trigger or action for our binding set. It's actually astounding this
hasn't bit us or at least not that we know of. This could result in
different triggers overwriting each other. Anyways, we actually compare
them now.

2. **Use an `ArrayHashMap` for sets.** This has been on the back burner
for awhile. Using an array hash map is a good idea in general (see:
https://github.com/ziglang/zig/issues/17851) but it also is a nicer API
for our use case and cleaned things up.

All unit tests pass, many new unit tests added particularly for equality
comparison. Hopeful this doesn't regress any bindings but this is the
right path forward so we should fix those if they come up.

**AI disclosure:** AI helped write the deepEqual unit tests, otherwise
everything else is certified meat.
2026-01-09 09:14:48 -08:00
Mitchell Hashimoto
0e9ce7e450 input: change our binding set to use array hash map
This is recommended for ongoing performance: 
https://github.com/ziglang/zig/issues/17851

Likely not an issue for this particular use case which is why it never
bit us; we don't actively modify this map much once it is created. But,
its still good hygiene and ArrayHashMap made some of the API usage
nicer.
2026-01-09 09:06:03 -08:00
Mitchell Hashimoto
201198c74a input: do value comparison for Set hash maps
We previously only compared the hashes for triggers and actions for hash
map equality. I'm genuinely surprised this never bit us before because
it can result in false positives when two different values have the same
hash. Fix that up!
2026-01-09 08:59:05 -08:00
Mitchell Hashimoto
c179de62a7 extract deepEqual 2026-01-09 08:59:05 -08:00
Mitchell Hashimoto
a584e6259f macOS: Only trigger main menu items if not performable or all targeted (#10240)
Fixes #10239

The main menu uses first responder which will hit a surface. If a
binding would target `all:` we need to avoid it. To achieve this, our
`is_key_binding` API now returns information about the binding (if any).
I've cleaned up the Swift to implement this.

In doing this I realized we have to do the same for `performable` since
main menus will effectively always consume.
2026-01-09 07:21:54 -08:00
Martin Müller
115351db87 docs: bell border feature is available on macOS
As of commit fe55d90 and PR #8768 this feature is also available on
macOS.
2026-01-09 16:19:50 +01:00
Mitchell Hashimoto
f34c69147a macos: use the new binding flags information value to trigger menu 2026-01-09 07:13:14 -08:00
Mitchell Hashimoto
856ef1fc1b input: change the key_is_binding to return some information 2026-01-09 06:51:48 -08:00
Mitchell Hashimoto
18535f04d1 osc: refactor parsing helper functions into separate files (#10233)
Following up on #9950, refactor the parsing helper functions into
separate files.
2026-01-09 06:13:35 -08:00
Jeffrey C. Ollie
93b4b08b52 osc: refactor parsing helper functions into separate files
Following up on #9950, refactor the parsing helper functions into
separate files.
2026-01-08 23:07:57 -06:00
Mitchell Hashimoto
27ca54cb85 terminal/search: screen search prunes history for no-scrollback screens (#10232)
Fixes #10227

The big comment in `search/screen.zig` describes the solution well. The
problem is that our search is discrete by page and a page can contain
some amount of history as well.

For zero-scrollback screens, we need to fully prune any history lines.
For everyone else, everything in the PageList is scrollable and visible
so we should search it.
2026-01-08 20:53:01 -08:00
Mitchell Hashimoto
5bfbadbc70 terminal/search: screen search prunes history for no-scrollback screens
The big comment in `search/screen.zig` describes the solution well. The
problem is that our search is discrete by page and a page can contain
some amount of history as well. 

For zero-scrollback screens, we need to fully prune any history lines.
For everyone else, everything in the PageList is scrollable and visible
so we should search it.
2026-01-08 20:48:19 -08:00
Mitchell Hashimoto
a692cb9e5f terminal: PageList shouldn't allow any scrolling with max_size=0 (#10229)
Partial #10227

This fixes the scrollbar part of #10227, but not the search part.

The way PageList works is that max_size is advisory: we always allocate
on page boundaries so we always have _some_ extra space (usually, unless
you ask for a byte-perfect max size). Normally this is fine, it doesn't
cause any real issues. And this has been true since Ghostty 1.0.

But with the introduction of scrollbars (and search), we were exposing
this hidden space to the user. To fix this, the easiest approach is to
special-case the zero-scrollback scenario, since it is already
documented that scrollback limit is not _exact_ and is subject to some
minimum allocations. But with zero-scrollback we really expect NOTHING.
2026-01-08 15:57:07 -08:00
Mitchell Hashimoto
794c47425e terminal: PageList shouldn't allow any scrolling with max_size=0
Partial #10227

This fixes the scrollbar part of #10227, but not the search part.

The way PageList works is that max_size is advisory: we always allocate
on page boundaries so we always have _some_ extra space (usually, unless
you ask for a byte-perfect max size). Normally this is fine, it doesn't
cause any real issues.

But with the introduction of scrollbars (and search), we were exposing
this hidden space to the user. To fix this, the easiest approach is to
special-case the zero-scrollback scenario, since it is already
documented that scrollback limit is not _exact_ and is subject to some
minimum allocations. But with zero-scrollback we really expect NOTHING.
2026-01-08 15:52:49 -08:00
Mitchell Hashimoto
30a2fb685a apprt/embedded: escape the initial input string (#10226)
Fixes #10214
2026-01-08 14:16:17 -08:00
Mitchell Hashimoto
caa6b958d7 apprt/embedded: escape the initial input string
Fixes #10214
2026-01-08 14:07:46 -08:00
Jeffrey C. Ollie
2766ba68ad New OSC parser (#9950)
This replaces the OSC parser with one that only uses a state machine to
determine which OSC is being handled, rather than parsing the whole OSC.
Once the OSC command is determined the remainder of the data is stored
in a buffer until the terminator is found. The data is then parsed to
determine the final OSC command.

```
→ poop './zig-out/bin/ghostty-bench-old +osc-parser --data=osc.txt' './zig-out/bin/ghostty-bench +osc-parser --data=osc.txt'
Benchmark 1 (3 runs): ./zig-out/bin/ghostty-bench-old +osc-parser --data=osc.txt
  measurement          mean ± σ            min … max           outliers         delta
  wall_time          4.19s  ± 69.1ms    4.12s  … 4.25s           0 ( 0%)        0%
  peak_rss           5.86MB ± 37.8KB    5.84MB … 5.91MB          0 ( 0%)        0%
  cpu_cycles         15.3G  ±  330M     14.9G  … 15.5G           0 ( 0%)        0%
  instructions       41.1G  ± 7.81      41.1G  … 41.1G           0 ( 0%)        0%
  cache_references    130M  ± 2.40M      128M  …  132M           0 ( 0%)        0%
  cache_misses        658K  ± 88.5K      603K  …  760K           0 ( 0%)        0%
  branch_misses      31.5M  ±  112K     31.4M  … 31.6M           0 ( 0%)        0%
Benchmark 2 (4 runs): ./zig-out/bin/ghostty-bench +osc-parser --data=osc.txt
  measurement          mean ± σ            min … max           outliers         delta
  wall_time          1.54s  ± 7.08ms    1.53s  … 1.55s           0 ( 0%)        - 63.3% ±  2.1%
  peak_rss           5.84MB ±  270KB    5.45MB … 6.02MB          1 (25%)          -  0.4% ±  7.1%
  cpu_cycles         6.07G  ± 7.82M     6.06G  … 6.08G           0 ( 0%)        - 60.3% ±  2.7%
  instructions       17.3G  ± 39.5      17.3G  … 17.3G           1 (25%)        - 57.8% ±  0.0%
  cache_references   64.7M  ±  655K     63.8M  … 65.3M           0 ( 0%)        - 50.4% ±  2.4%
  cache_misses        733K  ±  116K      611K  …  890K           0 ( 0%)          + 11.4% ± 31.7%
  branch_misses      21.7M  ±  167K     21.5M  … 21.9M           0 ( 0%)        - 31.3% ±  0.9%
```
2026-01-08 14:35:00 -06:00
Jeffrey C. Ollie
f180f1c9b8 osc: remove inline from Parser.next 2026-01-08 14:12:16 -06:00
Jeffrey C. Ollie
6ee1b3998e osc: no defaults on Parser fields 2026-01-08 13:50:44 -06:00
Jeffrey C. Ollie
0b9b17cbe0 osc: remove pub from internal parser functions 2026-01-08 13:50:44 -06:00
Jeffrey C. Ollie
2805c1e405 osc: collapse switch cases 2026-01-08 13:50:44 -06:00
Jeffrey C. Ollie
d32a94a06a core: add new OSC parser
This replaces the OSC parser with one that only uses a state machine to
determine which OSC is being handled, rather than parsing the whole OSC.
Once the OSC command is determined the remainder of the data is stored
in a buffer until the terminator is found. The data is then parsed to
determine the final OSC command.
2026-01-08 13:50:43 -06:00
Jeffrey C. Ollie
fb1268a908 benchmark: add doNotOptimizeAway to OSC benchmark 2026-01-08 13:50:43 -06:00
Mitchell Hashimoto
435cb951f0 config: add more details to the key-remap feature (#10223)
cc @jcollie
2026-01-08 10:47:28 -08:00
Mitchell Hashimoto
a6d36b5e6d config: add more details to the key-remap feature 2026-01-08 10:45:45 -08:00
Mitchell Hashimoto
89e9562615 feat: key-remap configuration to remap modifiers at the app-level (#10064)
This PR introduces a new `key-remap` configuration option that allows
users to remap modifier keys at the application level without affecting
system-wide settings.

## Issue
Closes #5160

## Usage

```ini
# Make Ctrl act as Cmd within Ghostty
key-remap = ctrl=super

# Swap Ctrl and Cmd
key-remap = ctrl=super
key-remap = super=ctrl

# Remap only left Alt to Ctrl
key-remap = left_alt=ctrl
```

### Supported Modifiers

| Generic | Left-sided | Right-sided |
|---------|------------|-------------|
| `ctrl` / `control` | `left_ctrl` | `right_ctrl` |
| `alt` / `opt` / `option` | `left_alt` | `right_alt` |
| `shift` | `left_shift` | `right_shift` |
| `super` / `cmd` / `command` | `left_super` | `right_super` |

## Behavior

Per the issue specification:

- **One-way remapping**: `ctrl=super` means Ctrl becomes Super, but
Super remains Super
- **Non-transitive**: `ctrl=super` + `alt=ctrl` → Alt becomes Ctrl (NOT
Super)
- **Sided support**: Generic modifiers match both sides; use `left_*` or
`right_*` for specific sides
- **Immediate effect**: Changes apply on config reload

## Limitations

- Implemented in Zig core, works on both macOS and Linux
- Only modifier keys can be remapped (not regular keys)
2026-01-08 10:32:15 -08:00
Mitchell Hashimoto
21d9d89d32 input: RemapSet should support aliased mods 2026-01-08 10:26:46 -08:00
Mitchell Hashimoto
5b24aebcab update to use new RemapSet 2026-01-08 10:22:56 -08:00
Mitchell Hashimoto
f804a4344e input: RemapSet 2026-01-08 10:22:56 -08:00
Mitchell Hashimoto
619427c84c input: move mods out to key_mods.zig 2026-01-08 10:22:56 -08:00
Mitchell Hashimoto
8415d8215b comments 2026-01-08 10:22:56 -08:00
Jagjeevan Kashid
111b0996d2 feat: key-remap configuration to remap modifiers at the app-level
Signed-off-by: Jagjeevan Kashid <jagjeevandev97@gmail.com>
2026-01-08 10:22:56 -08:00
Mitchell Hashimoto
891f442041 macos: custom tab title shows bell if active (#10211)
Fixes #10210
2026-01-07 13:37:32 -08:00
Mitchell Hashimoto
5a7fdf735e macos: custom tab title shows bell if active
Fixes #10210
2026-01-07 13:32:58 -08:00
Mitchell Hashimoto
e9ea94d364 fix(formatter): preserve background colors on cells without text (#10134)
The VT formatter was treating cells without text as blank and emitting
them as plain spaces, losing any background color styling. This caused
TUIs like htop to lose their background colors when rehydrating terminal
state (e.g., after detach/reattach in zmx).

For styled formats (VT/HTML), cells with background colors or `style_id`
are now emitted with proper SGR sequences and a space character instead
of being accumulated as unstyled blanks.

Adds handling for `bg_color_palette` and `bg_color_rgb` content tags
which
were previously unreachable.

I used amp to construct the test case and the code to make the test
pass. Please see the amp thread.

I tested my branch against the test cases where it was previously broken
(nvtop, htop, senpai).

Reference:
https://ampcode.com/threads/T-019b7a35-c3f3-73fc-adfa-00bbe9dbda3c

## VT

### BEFORE

<img width="2256" height="552" alt="screenshot_1767373196"
src="https://github.com/user-attachments/assets/32654801-35cb-4d94-8ebd-501cfe74b6b6"
/>

### AFTER

<img width="2256" height="632" alt="screenshot_1767373113"
src="https://github.com/user-attachments/assets/f011260b-20ca-40a7-95b4-965c29b2eba3"
/>

## HTML

### BEFORE

<img width="1118" height="749" alt="screenshot_1767373647"
src="https://github.com/user-attachments/assets/e4152640-8f1e-48f7-893c-d437d48629ef"
/>

### AFTER

<img width="1130" height="775" alt="screenshot_1767373657"
src="https://github.com/user-attachments/assets/288423c8-d034-4dea-b976-506a7b95cc3c"
/>
2026-01-07 13:17:26 -08:00
Mitchell Hashimoto
7bfcaef1e8 terminal: formatting feedback 2026-01-07 13:12:37 -08:00
Mitchell Hashimoto
9bddca81dc shell-integration: better shell detection and setup (#10044)
Command-based shell detection has been extracted to its own function
(detectShell), which is nicer for testing. It now uses argIterator to
determine the command's executable, rather than the previous string
operations, which allows us to handle command strings containing quotes
and spaces.

Also, our shell-specific setup functions now use a consistent signature,
which simplifies the calling code quite a bit.
2026-01-07 10:30:45 -08:00
Jon Parise
795de7938d shell-integration: better shell detection and setup
Command-based shell detection has been extracted to its own function
(detectShell), which is nicer for testing. It now uses argIterator to
determine the command's executable, rather than the previous string
operations, which allows us to handle command strings containing quotes
and spaces.

Also, our shell-specific setup functions now use a consistent signature,
which simplifies the calling code quite a bit.
2026-01-07 10:25:17 -08:00
Mitchell Hashimoto
7c4ae08924 feat: select entire URL on double-click (#10132)
## Why

When double-clicking on a URL like `https://example.com`, only `https`
or `//example.com` gets selected because `:` and `/` are word
boundaries. Users expect the entire URL to be selected.

## How

Added URL detection to the double-click handler in `Surface.zig`:

1. Before falling back to `selectWord`, try to detect if the clicked
position is part of a URL
2. Uses the pre-compiled link regexes from user configuration (same
patterns used for cmd+click)
3. If a URL is found at the position, select the entire URL
4. Otherwise, fall back to normal word selection

The implementation:
- Respects user's link configuration (disabled URLs won't trigger
selection)
- Reuses pre-compiled regexes from `DerivedConfig.links` (no per-click
compilation)
- Follows the same patterns as `linkAtPos`

## What

- `src/Surface.zig`: Added `urlAtPin()` helper function and modified
double-click handler
- `src/terminal/StringMap.zig`: Added 2 tests for URL detection
following existing test patterns
2026-01-07 10:18:12 -08:00
Mitchell Hashimoto
6659315760 tweaks to link detection 2026-01-07 10:03:15 -08:00
teamchong
5a042570c8 feat: select entire URL on double-click
When double-clicking text, first check if the position is part of a URL
using the default URL regex pattern. If a URL is detected, select the
entire URL instead of just the word.

This follows the feedback from PR #2324 to modify the selection behavior
rather than introducing a separate selectLink function. The implementation
uses the existing URL regex from config/url.zig which already handles
various URL schemes (http, https, ftp, ssh, etc.) and file paths.

The URL detection runs before the normal word selection, falling back to
selectWord if no URL is found at the clicked position.
2026-01-07 10:03:15 -08:00
Mitchell Hashimoto
323d362bc1 macos: dragging last window out of quick terminal works 2026-01-07 09:33:37 -08:00
Lukas
a265462aa6 macOS: moving a focused split to another tab should also update the previous tab 2026-01-07 09:18:41 -08:00
Lukas
02fc0f502f macOS: rename function to avoid mutating misunderstanding 2026-01-07 09:18:17 -08:00
Mitchell Hashimoto
ba1952c8c2 build: add -fPIC for musl targets (#10198)
Adds `-fPIC` flag for musl targets when building highway and simdutf C++
dependencies, matching the existing freebsd behavior.

## What is PIC?

Position Independent Code (PIC) generates machine code using relative
addresses instead of absolute ones, allowing the code to be loaded at
any memory address. This is required when linking static libraries into
shared libraries (.so files).

## Why both freebsd and musl need it

Both freebsd and musl use strict relocation policies that reject non-PIC
code in shared libraries. Without `-fPIC`, linking fails with errors
like:

```
relocation R_X86_64_PC32 cannot be used against symbol '__cxa_begin_catch'
```

glibc is more permissive and handles these relocations at runtime, which
is why linux-gnu targets work without this flag.

## Context

This enables cross-compiling ghostty-vt to musl/Alpine Linux targets.
Discovered while integrating ghostty-vt into opentui:
https://github.com/sst/opentui/pull/440

---

This PR was created with help from Claude Opus 4.5.
2026-01-07 07:03:00 -08:00
Tommy D. Rossi
61394d5213 build: add -fPIC for musl targets in C++ dependencies 2026-01-07 06:55:40 -08:00
Leah Amelia Chen
c559a1dbba Allow for default or inherited CWD in new window, tab and split surfaces (redone for GTK-NG) (#9158) 2026-01-07 20:45:06 +08:00
Mitchell Hashimoto
a4368064a3 macOS: add Cmd+J "Jump to Selection" menu item and default binding (#10197)
This matches other built-in macOS apps like Terminal, Notes, Safari. We
already had the binding, just needed to create the menu.
2026-01-06 14:40:01 -08:00