Commit Graph

12975 Commits

Author SHA1 Message Date
Qwerasd
d2316ee718 perf: inline size.getOffset and intFromBase 2025-11-19 15:17:05 -07:00
Qwerasd
e799023b89 perf: inline trivial charset lookup 2025-11-19 15:17:05 -07:00
Qwerasd
7d89aa764d perf: remove some overzealous inline annotations
These were actually hurting performance lol, except in the places where
I added the `.always_inline` calls- for some reason if these functions
aren't inlined there it really messes up the top region scrolling
benchmark in vtebench and I'm not entirely certain why...
2025-11-19 15:17:05 -07:00
Qwerasd
0ce3d0bd07 remove useless code
the style ID is reset up above
2025-11-18 21:03:42 -07:00
Qwerasd
f9e245ab7f perf: separate clearing graphemes/hyperlinks from updating row flag
This improves the `clearCells` function since it only has to update once
after clearing all of the individual cells, or not at all if the whole
row was cleared since then it knows for sure that it cleared them all.

This also makes it so that the row style flag is properly tracked when
cells are cleared but not the whole row.
2025-11-18 21:03:42 -07:00
Qwerasd
5ffa7f8f45 perf: inline calls to StaticBitSet.isSet in sgr parser 2025-11-18 20:46:00 -07:00
Qwerasd
d14b4cf068 perf: streamline RefCountedSet lookup
+ add branch hint to insert
2025-11-18 20:46:00 -07:00
Qwerasd
81eda848cb perf: add full-page dirty flag
Avoids overhead of marking many rows dirty in functions that manipulate
row positions which dirties all or most of the page.
2025-11-18 20:46:00 -07:00
Qwerasd
30472c0077 perf: replace dirty bitset with a flag on each row
This is much faster for most operations since the row is often already
loaded when we have to mark it as dirty.
2025-11-18 20:46:00 -07:00
Qwerasd
212598ed66 perf: add branch hints based on real world data
+ move stream ESC state entry outside of `nextNonUtf8`
2025-11-18 20:43:31 -07:00
Qwerasd
5744fb042c perf: replace charset EnumArray with bespoke struct 2025-11-18 20:40:26 -07:00
Qwerasd
14771e5009 perf: avoid branch in parser csi param action 2025-11-18 20:40:26 -07:00
Qwerasd
3e8d94bb1c perf: misc inlines and branch hints
Inlined trivial functions, added cold branch hints to error paths, added
likely branch hints to common paths
2025-11-18 20:40:26 -07:00
Qwerasd
58c26957b4 perf: improve style hash and eql fns 2025-11-17 21:32:48 -07:00
Qwerasd
9e754f9939 perf: fix accidental overhead in refcountedset 2025-11-17 21:31:40 -07:00
Qwerasd
9ab9bc8e19 perf: small sgr parser improvements 2025-11-17 13:17:31 -07:00
Qwerasd
6d5b4a3426 perf: replace std.debug.assert with inlined version
See doc comment in `quirks.zig` for reasoning
2025-11-17 12:13:56 -07:00
Qwerasd
995a7377c1 fix(terminal): avoid lockup caused by 0-length hyperlink
This could cause a 0-length hyperlink to be present in the screen,
which, in ReleaseFast, causes a lockup as the string alloc tries to
iterate `1..0` to allocate 0 chunks.
2025-11-16 19:38:46 -07:00
Mitchell Hashimoto
bee5875351 Miscellaneous Bugfixes (#9609)
I encountered these bugs while trying to benchmark Ghostty for
performance work.

- Tmux control mode parsing would start accessing deallocated memory
after entering the "broken" state, and worse yet, would cause a
double-free once it was supposed to be deinited.
- Despite our best efforts, CoreText can still produce non-monotonic
(non-ltr) runs. Our renderer code relies on monotonic ltr ordering so in
the rare case where this happens we just sort the buffer before
returning it.
- C1 (8-bit) controls can be executed in certain parser states, so we
need to handle them in the stream's `execute` function. Luckily this was
pretty straightforward since all C1 controls are equivalent to `ESC`
followed by `C1 - 0x40`.
- `Terminal.Screen`'s `cursorScrollDown` function could cause memory
corruption because of `eraseRow` moving the cursor's tracked pin to a
different page. In fixing this, I actually reduced the complexity of
that codepath.
- **Bonus!** Added a nice helper function to `Offset.Slice` so that you
can just do `offset_slice.slice()` instead of
`offset_slice.offset.ptr(base)[0..offset_slice.len]`. Much more
readable.

### `vtebench` before/after
<img width="984" height="691" alt="image"
src="https://github.com/user-attachments/assets/ef20dcc5-d611-4763-9107-355d715a6c0b"
/>
Doesn't seem like any of these changes caused a performance regression.
2025-11-16 12:03:30 -08:00
Qwerasd
9e44c9c956 fix(terminal): avoid memory corruption in cursorScrollDown
It was previously possible for `eraseRow` to move the cursor pin to a
different page, and then the call to `cursorChangePin` would try to free
the cursor style from that page even though that's not the page it
belongs to, which creates memory corruption in release modes and
integrity violations or assertions in debug mode.

As a bonus, this should actually be faster this way than the old code,
since it avoids needless work that `cursorChangePin` otherwise does.
2025-11-16 12:39:10 -07:00
Qwerasd
bb2455b3fc fix(terminal/stream): handle executing C1 controls
These can be unambiguously invoked in certain parser states, and as such
we need to handle them. In real world use they are extremely rare, hence
the branch hint. Without this, we get illegal behavior by trying to cast
the value to the 7-bit C0 enum.
2025-11-16 12:39:10 -07:00
Qwerasd
00c2216fe1 style: add Offset.Slice.slice helper fn
Makes code that interacts with these so much cleaner
2025-11-16 12:39:10 -07:00
Qwerasd
985e1a3cea test(shaper/coretext): test non-monotonic CoreText output 2025-11-16 12:39:10 -07:00
Qwerasd
712cc9e55c fix(shaper/coretext): handle non-monotonic runs by sorting 2025-11-16 12:39:10 -07:00
Qwerasd
0a7da32c71 fix: drop tmux control parsing immediately if broken 2025-11-16 11:28:04 -07:00
Mitchell Hashimoto
711e10d930 macOS: Fix dictation icon's position while speaking (#9605)
Fixes #8493.

There is still an "overflow" issue since preedit doesn't wrap right now,
but that's kind of off-topic.


https://github.com/user-attachments/assets/a7ae6018-76c7-4d16-9a9b-e0167072d910
2025-11-16 06:58:03 -08:00
Lukas
011fc77caa macOS: Fix dictation icon's position while speaking 2025-11-16 12:17:31 +01:00
Mitchell Hashimoto
b76203bbb9 Update iTerm2 colorschemes (#9603)
Upstream release:
https://github.com/mbadolato/iTerm2-Color-Schemes/releases/tag/release-20251110-150531-d5f3d53
2025-11-15 19:50:41 -08:00
Mitchell Hashimoto
4c0d7379db Search Thread (#9602)
Progress towards #189 

## Search Thread

This completes an initial implementation of the search thread. This is a
separate thread that manages a terminal search operation, triggering
event callbacks for various scenarios. The performance goal of the
search thread is to minimize time spent within the critical area of the
terminal lock while making forward progress on search outside of that.

The search thread sends two messages back to the caller right now:

- Total matches: sent continuously as new matches are found, just a
number
- Viewport matches: a list of `Selection` structures spanning the
current viewport of matches within the visible viewport. Sent whenever
the viewport changes (location or content).

I think that's enough to build a rudimentary search UI.

For this initial implementation, the search also relies on a "refresh
timer" which trigger every 24ms (40 FPS) to grab the lock and look for
any reconciliation that needs to happen: viewport moved, active screen
changed, active area changed, etc. This is a total guess and is
arbitrary currently. The value should be tuned to balance responsiveness
and IO throughput (lock-holding). I actually suspect this may be too
frequent right now.

A TODO is noted for the future to pause the refresh timer when the
terminal being search isn't focused. We'll have to do that before
shipping search because the way its built right now we will definitely
consume unnecessary CPU while unfocused. But only while search is
active.

## `ViewportSearch`

I also determined the need for what is called the `ViewportSearch`
layer. This is similar to `ActiveSearch` in that it throws away and
re-searches an area, but is tuned towards efficiently detecting viewport
changes. I found its more efficient to continuously research the visible
viewport than to hunt for those matches within the cached ScreenSearch
results, which can be very large.

## Future

Next up we need to hook up the search thread to some keybindings to
start and stop the search so we can then trigger those from our apprts
(GUIs).

I highly suspect this is going to expose some major performance issues
(overly active message sending being the likely culprit) that we can fix
up in the search thread thereafter. Up until this point we can only run
this stuff in isolation in unit tests which is good for testing
correctness but difficult for testing resource usage.

There are some written TODOs in the Thread.zig file in this PR. I may
address some of them before merging, since I think a couple are pretty
obvious performance gotchas.
2025-11-15 19:50:28 -08:00
Mitchell Hashimoto
79af2378d2 terminal: unify all notification sending into the notify command 2025-11-15 19:48:09 -08:00
mitchellh
ead01e8ffd deps: Update iTerm2 color schemes 2025-11-16 00:15:33 +00:00
Mitchell Hashimoto
caf5040a6d macOS: find correct tab bar when in fullscreen (#9596)
Fixes #9597
2025-11-15 14:13:30 -08:00
Mitchell Hashimoto
90a6ea7aa5 terminal: note some search thread TODOs we can address later 2025-11-15 14:03:27 -08:00
Mitchell Hashimoto
f0af63db15 terminal: search thread refresh timer to reconcile state 2025-11-15 13:43:26 -08:00
Mitchell Hashimoto
acab8c90a2 terminal: search.Thread searches viewport and notifies viewport results 2025-11-15 13:30:32 -08:00
Mitchell Hashimoto
99d47a4627 terminal: viewport search 2025-11-15 13:00:58 -08:00
Mitchell Hashimoto
05366485da macOS: fix misplaced frame modifier (#9598)
As per #9504, this was supposed to be on `ZStack`, not on the overlay.
See also #9503. I cherry-picked it in the wrong place before.
2025-11-15 06:37:55 -08:00
Lukas
8d1dd332c6 macOS: fix misplaced frame modifier
As per #9504, this was supposed to be on `ZStack`, not on the overlay. See also #9503. I cherry-picked it in the wrong place before.
2025-11-15 10:14:43 +01:00
Lukas
b124b78313 macOS: find correct tab bar when in fullscreen
Fixes #9593
2025-11-15 08:10:05 +01:00
Mitchell Hashimoto
bfa397b196 terminal: search thread active screen reconciliation loop 2025-11-14 21:24:18 -08:00
Mitchell Hashimoto
1867928b84 terminal: search thread search ticking 2025-11-14 21:05:05 -08:00
Mitchell Hashimoto
d1ad32eadd terminal: search.Thread starting search loop 2025-11-14 17:04:34 -08:00
Mitchell Hashimoto
19dfc0aa98 terminal: search.Thread more boilerplate, test starting 2025-11-14 16:29:45 -08:00
Mitchell Hashimoto
466a004c39 lib-vt: export stream.Action for custom streams (#9595) 2025-11-14 16:06:59 -08:00
Mitchell Hashimoto
de545eeae1 lib-vt: export stream.Action for custom streams 2025-11-14 16:01:57 -08:00
Mitchell Hashimoto
7cc8ea7efb terminal: change primary/alt screens to use a ScreenSet, stable pointers (#9594)
This PR changes our primary/alt screen tracking from being by-value
fields that are copied during switch to heap-allocated pointers that are
stable. This is motivated now by #189 since our search thread needs a
stable screen pointer, but this will also help us in the future with our
future N-screens proposal I have.

Also, as a nice bonus, alt screen memory is now initialized on demand
when you first enter alt-screen, so this saves a few MB of memory for a
new terminal if you never use alt screen!

This is something I've wanted to do for a veryyyyyy long time, but the
annoyance of the task really held me back. I finally pushed through and
did this with the help of some AI agents for the rote tasks (renaming
stuff).
2025-11-14 16:00:47 -08:00
Mitchell Hashimoto
2452026ff3 terminal: kitty limits only if kitty graphics being built 2025-11-14 15:53:00 -08:00
Mitchell Hashimoto
4ba00dbe89 fix harfbuzz 2025-11-14 15:48:06 -08:00
Mitchell Hashimoto
580f9f057b convert t.screen to t.screens.active 2025-11-14 15:40:31 -08:00
Mitchell Hashimoto
3aff5f0aff ScreenSet 2025-11-14 15:08:10 -08:00