SwiftLint <https://realm.github.io/SwiftLint/> is both a linter and
formatting. It's a popular way to spot issues and enforce a consistent
style.
Our SwiftLint configuration lives in macos/.swiftlint.yml, where is is
automatically discovered. It's very configurable, and I made an initial
pass as some basic, weakly-opinionated rules. The "TODO" section lists
rules that currently have violations but can be easily (auto)fixed in
follow-up commits.
Our integration is CLI-based. Similar to our other support tools, we
expect developers to install `swiftlint` via nix or e.g. Homebrew.
This is documented in HACKING.md.
We also have an optional Xcode integration, for in-editor feedback. When
`swiftlint` is available, it's run as a script-based Build Phase.
SwiftLint supports an auto-fix mode (--fix). Agents are aware of this
via AGENTS.md.
The rules are enforced using a (nix-based) CI job.
Switch to using the existing UTType.unixExecutable constant for this
operator, which also lets us remove a failure path. Also, use the
completion-based setDefaultApplication() variant to handle errors.
This simplifies the code enough that we don't need the additional
NSWorkspace+Ghostty extension functions.
This PR enables iTerm2-like one button "Set Ghostty as Default Terminal
App" functionality on macOS, making it easier to open a directory in
Ghostty, run shell scripts when mouse clicking, etc.
We already had an established Ghostty.Shell namespace (previously a
struct; now a more idiomatic enum), and locating these functions next to
each other makes it clearer how they relate to one another.
We already had an established Ghostty.Shell namespace (previously a
struct; now a more idiomatic enum), and locating these functions next to
each other makes it clearer how they relate to one another.
Xcode wants these to be sorted and will update this list when the
project file is saved so proactively make this change before it gets
mixed up in other work.
## Summary
- Fixes#10345 — `copy_title_to_clipboard` now copies the user-set
custom title instead of the raw terminal title
- Adds a new `copy_title` apprt action as [suggested by
@mitchellh](https://github.com/ghostty-org/ghostty/issues/10345#issuecomment-2601002974)
- Each platform (GTK + macOS) resolves the effective title (user
override → terminal title fallback) before copying to clipboard
## Changes
- **`src/apprt/action.zig`** — New `copy_title` void action
- **`include/ghostty.h`** — C ABI enum entry
- **`src/Surface.zig`** — Binding handler now dispatches apprt action
instead of inline logic
- **`src/apprt/gtk/class/surface.zig`** — `getEffectiveTitle()` helper
(returns `title_override orelse title`)
- **`src/apprt/gtk/class/application.zig`** — GTK action handler
- **`macos/.../Ghostty.App.swift`** — macOS handler using
`surfaceView.title` + `NSPasteboard`
*Note*: This PR was *AI* assisted.
When a user renames a surface via "Change Terminal Title" and then
uses copy_title_to_clipboard, the raw terminal title was copied
instead of the custom name.
This adds a new `copy_title` apprt action so each platform resolves
the effective title (user override or terminal-set) before copying
to clipboard.
Fixes#10345
When we're building an input string that's explicitly meant to be used
as a shell command, quote it using the same logic as Python's
`shlex.quote` function.
This specifically addresses issues we've seen when open(1)'ing Ghostty
with filename arguments that contain spaces.
See #2633, #3030
When we're building an input string that's explicitly meant to be used
as a shell command, quote (escape) it using the same logic as Python's
shlex.quote function.
This specifically addresses issues we've seen when open(1)'ing Ghostty
with filename arguments that contain spaces.
[Reference](https://github.com/insidegui/AudioCap). This is Apple's latest system for allowing apps to access loopback audio streams eg: Desktop-Audio, Window-Audio, etc...
Refer to discussion #10000
When a tab contains only a single split, resize_split and
toggle_split_zoom actions now return false (not performed). This allows
keybindings marked with `performable: true` to pass the event through to
the terminal program.
The performable flag causes unperformed actions to be treated as if the
binding didn't exist, so the key event is sent to the terminal instead
of being consumed.
- Add isSplit() helper to SplitTree to detect single-pane vs split state
- Update GTK resizeSplit/toggleSplitZoom to return false when single
pane
- Update macOS resizeSplit/toggleSplitZoom to return Bool and check
isSplit
- Add unit test for isSplit method
### Background
~~I was trying to add a few UI test cases for
`macOS-titlebar-style`[Already in this PR]~~. In order to do this, I
need a way from `GhosttyKit` to load a temporary configuration without
messing around with users'.
### Changes
- Add `ghostty_config_load_file` using the existing
[`loadFile`](dafb9e89a3/src/config/Config.zig (L3399))
- Use `xcbeautify` to format test&build errors
**Couldn't find a way to do this in `GhosttyXcodebuild`, if you have a
better approach please let me know!**
- Add GhosttyUITests target and test cases for
`GhosttyTitlebarTabsUITests`(#2349) and `GhosttyThemeTests`(#9360)
### NOTE
Running UI tests on the runner could be **very** slow and I couldn't
find a way to guarantee success, so I made these only runnable by
manually testing in Xcode.
Better to squash this🤪
> > Some of the test cases could fail when testing all the cases
together; a rerun would succeed.