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.
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.
## 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
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.
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.
Adds the `selection_for_search` action, with Cmd+E keybind by default.
This action inputs the currently selected text into the search field
without changing focus, matching standard macOS behavior.
Implements discussion #9776 and #10036
<details><summary>AI Disclosure</summary>
<p>
Tab completions with Codestral.
Reviewed by Gemini 3 Flash via chatting.
No Agentic coding tools were involved.
</p>
</details>
Adds test coverage for bitmap font rendering in the FreeType backend
using the Spleen 8x16 font in three formats:
- BDF (Bitmap Distribution Format)
- PCF (Portable Compiled Format)
- OTB (OpenType Bitmap)
Tests validate glyph dimensions and pixel-perfect rendering against
expected patterns, following the model established by the existing
TerminusTTF test.
Spleen was chosen because it ships in all three required formats from a
single source, providing consistent test data across formats. Its BSD
2-Clause license is compatible with the existing font licenses in the
repo (OFL, MIT). No existing embedded fonts could be used since they are
all TTF/OTF files that use the TrueType loader rather than the
BDF/PCF/OTB loaders being tested.
Addresses #8524.
---
This PR was written with assistance from Claude Code.
Add test coverage for bitmap font rendering using the Spleen 8x16 font
in three formats: BDF (Bitmap Distribution Format), PCF (Portable
Compiled Format), and OTB (OpenType Bitmap). Tests validate glyph
rendering against expected pixel patterns.
Addresses #8524.
The "unimplemented OSC command" warning is a frequent source of red
herrings as there are many OSCs that we parse but deliberately do not
implement. It's also a small drag on performance due to the function
call overhead and the overhead of formatting and outputting the message.
This PR lowers the message from warning to debug. Debug logs are
compiled out of release builds so there should be less confusion from
general users who will no longer see the message.
Adds the `selection_for_search` action, with Cmd+E keybind by default.
This action inputs the currently selected text into the search
field without changing focus, matching standard macOS behavior.
This fixes the Windows build failure discussed in
https://github.com/ghostty-org/ghostty/discussions/10148
When building on Windows, `symbols-unigen` and `props-unigen` crash with
`error.FileTooBig` because `stdout.end()` calls `setEndPos()` to
truncate the output. Windows does not support `SetEndOfFile` on pipes or
console handles - it returns `ERROR_INVALID_PARAMETER`, which Zig maps
to `error.FileTooBig`.
Using `flush()` instead of `end()` is correct here because:
1. `end()` flushes AND truncates - useful when overwriting files that
might have leftover content
2. For stdout captured as a pipe, there's nothing to truncate - we're
writing sequentially to a fresh pipe
3. `flush()` ensures all buffered data is sent, which is all that's
needed
CI before fix was failing with FileTooBig, after fix builds
successfully:
https://github.com/remorses/opentui/actions/runs/20671299561/job/59352503875