581 Commits

Author SHA1 Message Date
Mitchell Hashimoto
6d3f97ec1e Mouse drag while clicked should cancel any mouse link actions
Fixes #7077

This follows pretty standard behavior across native or popular applications
on both platforms macOS and Linux. The basic behavior is that if you
do a mouse down event and then drag the mouse beyond the current
character, then any mouse up actions are canceled (beyond emiting the
event itself).

This fixes a specific scenario where you could do the following:

  1. Click anywhere (mouse down)
  2. Drag over a valid link
  3. Press command/control (to activate the link)
  4. Release the mouse button (mouse up)
  5. The link is triggered

Now, step 3 and step 5 do not happen. Links are not even highlighted in
this scenario. This matches iTerm2 on macOS which has a similar
command-to-activate-links behavior.
2025-04-13 14:56:40 -07:00
Mitchell Hashimoto
722d41a359 config: allow commands to specify whether they shell expand or not
This introduces a syntax for `command` and `initial-command` that allows
the user to specify whether it should be run via `/bin/sh -c` or not.
The syntax is a prefix `direct:` or `shell:` prior to the command,
with no prefix implying a default behavior as documented.

Previously, we unconditionally ran commands via `/bin/sh -c`, primarily
to avoid having to do any shell expansion ourselves. We also leaned on
it as a crutch for PATH-expansion but this is an easy problem compared
to shell expansion.

For the principle of least surprise, this worked well for configurations
specified via the config file, and is still the default. However, these
configurations are also set via the `-e` special flag to the CLI, and it
is very much not the principle of least surprise to have the command run via
`/bin/sh -c` in that scenario since a shell has already expanded all the
arguments and given them to us in a nice separated format. But we had no
way to toggle this behavior.

This commit introduces the ability to do this, and changes the defaults
so that `-e` doesn't shell expand. Further, we also do PATH lookups
ourselves for the non-shell expanded case because thats easy (using
execvpe style extensions but implemented as part of the Zig stdlib). We don't
do path expansion (e.g. `~/`) because thats a shell expansion.

So to be clear, there are no two polar opposite behavioes here with
clear semantics:

  1. Direct commands are passed to `execvpe` directly, space separated.
     This will not handle quoted strings, environment variables, path
     expansion (e.g. `~/`), command expansion (e.g. `$()`), etc.

  2. Shell commands are passed to `/bin/sh -c` and will be shell expanded
     as per the shell's rules. This will handle everything that `sh`
     supports.

In doing this work, I also stumbled upon a variety of smaller
improvements that could be made:

  - A number of allocations have been removed from the startup path that
    only existed to add a null terminator to various strings. We now
    have null terminators from the beginning since we are almost always
    on a system that's going to need it anyways.

  - For bash shell integration, we no longer wrap the new bash command
    in a shell since we've formed a full parsed command line.

  - The process of creating the command to execute by termio is now unit
    tested, so we can test the various complex cases particularly on
    macOS of wrapping commands in the login command.

  - `xdg-terminal-exec` on Linux uses the `direct:` method by default
    since it is also assumed to be executed via a shell environment.
2025-04-10 13:15:14 -07:00
Mitchell Hashimoto
f31f8bb782 apprt/embedded: utf8 encoding buffer lifetime must extend beyond call
Fixes #6821

UTF8 translation using KeymapDarwin requires a buffer and the buffer was
stack allocated in the coreKeyEvent call and returned from the function.
We need the buffer to live longer than this.

Long term, we're removing KeymapDarwin (there is a whole TODO comment in
there about how to do it), but this fixes a real problem today.
2025-03-19 21:36:39 -07:00
Mitchell Hashimoto
4d0bf303c6 ci: zig fmt check
This adds a CI test to ensure that all Zig files are properly formatted.
This avoids unrelated diff noise in future PRs.
2025-03-18 13:58:49 -07:00
Tim Culverhouse
2018a8fd3c scroll: translate non-precision to precision
Some wheel mice are capable of reporting fractional wheel ticks. These
mice don't necessarily report a corresponding precision scroll start
event, at least in Wayland + GTK. We can treat all discrete (ie
non-precision) events as the number of wheel ticks - for wheel mice,
yoff will be "1.0" per tick, while precision wheel mice may report
fractional values. This unifies handling of scroll events by normalizing
all events to "pixels to scroll".

We now report `mouse-scroll-multiplier` wheel or arrow events per wheel
tick (or per accumulated cell height). This means that applications
which subscribe to mouse button events will receive (by default) three
wheel events per wheel tick. For precision scrolls, they will receive
one wheel tick per line of scroll. In my opinion, this provides the best
user experience while also allowing customization of how much a
wheel tick should scroll

Reference: https://github.com/ghostty-org/ghostty/discussions/6677
2025-03-15 21:35:39 -05:00
Mitchell Hashimoto
7e2286eb8c Zig 0.14 2025-03-11 14:39:04 -07:00
Leah Amelia Chen
9ed76729ab gtk: add separate close_window apprt action
For *some* reason we have a binding for close_window but it merely closes
the surface and not the entire window. That is not only misleading but
also just wrong. Now we make a separate apprt action for close_window
that would make it show a close confirmation prompt identical to as if
the user had clicked the (X) button on the window titlebar.
2025-03-06 20:32:38 +01:00
Tim Culverhouse
c1e87e7122 scroll: only use multiplier for non-precision scrolls
Precision scrolls don't require a multiplier to behave nicely. However,
wheel scrolls feel extremely slow without one. We apply the multiplier
to wheel scrolls only
2025-03-02 08:35:25 -06:00
Tim Culverhouse
dbba3f1a60 scroll: don't use multiplier for wheel events
When we report mouse scroll wheel events, they should not be multiplied.
Refactor the scrollCallback to only use a multiplier for viewport or
alternate scroll reports.
2025-03-02 08:02:47 -06:00
Tim Culverhouse
34388ab5df surface: calculate scroll amount directly from yoff/xoff for non-precision scrolls
Calculate the scroll amount for non-precision scrolls as a direct
multiple of yoff. This fixes an issue where Ghostty sends scroll wheel
events (or arrow keys if in alternate scroll mode) that are variable,
dependent on the screen size. I checked multiple terminals, and each
responds to a single wheel click by sending only a single wheel / arrow
key - independent of screen size.

```sh
printf "\x1b[?1049h"
printf "\x1b[?1007h"

cat -v

```

Using the above procedure, with varying screen sizes:

```
 # 50% Screen height
| terminal   | arrows keys sent| wheels events sent|
|------------|-----------------|-------------------|
| alacritty  |        3        |          1        |
| foot       |        3        |          1        |
| xterm      |        5        |          1        |
| kitty      |        3        |          1        |
| ghostty    |        2        |          2        |

 # 100% Screen height
| terminal   | arrows keys sent| wheels events sent|
|------------|-----------------|-------------------|
| alacritty  |        3        |          1        |
| foot       |        3        |          1        |
| xterm      |        5        |          1        |
| kitty      |        5        |          1        |
| ghostty    |        3        |          3        |
```

Both ghostty and kitty scale the number of arrow keys sent in proportion
to the screen size. However, when mouse reporting is on, only ghostty
does this.

This commit makes Ghostty behave like foot, and more generally removes
the dependence on screen size.
2025-03-02 08:02:47 -06:00
Mitchell Hashimoto
17cae57f51 Introduce reset_window_size keybinding and apprt action
Related to #6035

This implements the keybind/action portion of #5974 so that this can
have a binding and so that other apprts can respond to this and
implement it this way.
2025-02-28 15:31:17 -08:00
Mitchell Hashimoto
b0f1f19da0 apprt initial_size is sent whenever the grid size changes
As noted in the comments, this is so that apprt's can always know what
the default size of a window would be so they can utilize this for
"return to default size" actions.

The initial size shouldn't be treated as a "resize" event and was
already documented as such. Prior to this commit the docs already noted
that the initial size may be sent multiple times but only the first time
during initialization should be used as a resize.

Therefore, this shouldn't impact prior behavior. I've verified this with
the apprts.
2025-02-28 10:07:36 -08:00
Jeffrey C. Ollie
c7971b562e core: add env config option
Fixes #5257

Specify environment variables to pass to commands launched in a terminal
surface. The format is `env=KEY=VALUE`.

`env = foo=bar`
`env = bar=baz`

Setting `env` to an empty string will reset the entire map to default
(empty).

`env =`

Setting a key to an empty string will remove that particular key and
corresponding value from the map.

`env = foo=bar`
`env = foo=`

will result in `foo` not being passed to the launched commands.
Setting a key multiple times will overwrite previous entries.

`env = foo=bar`
`env = foo=baz`

will result in `foo=baz` being passed to the launched commands.

These environment variables _will not_ be passed to commands run by Ghostty
for other purposes, like `open` or `xdg-open` used to open URLs in your
browser.
2025-02-14 20:50:01 -08:00
Aswin M Prabhu
a581955b9b Add tab title rename feature to macos 2025-02-14 13:29:36 -08:00
Mitchell Hashimoto
ac7aa757bd macos: add padded-notch option for macos-non-native-fullscreen
Finishes #378
Supercedes #4159

This adds a new enum value for `macos-non-native-fullscreen`:
`padded-notch`. This value will add padding to the top of the window to
account for the notch on applicable devices while still hiding the
menu.

This value is preferred over "visible-menu" by some people because for
screens without a notch, the window will take up the full height.

The plan in the future is that we may color the padded area when a notch
is present. In this commit it appears as transparent.
2025-02-13 20:27:42 -08:00
Mitchell Hashimoto
1fea8028a3 apprt: require envmap for exec-based termio
Supercedes #5726
2025-02-13 12:26:11 -08:00
Jeffrey C. Ollie
4ad749607a core: performAction now returns a bool
This is to facilitate the `performable:` prefix on keybinds that are
implemented using app runtime actions.
2025-02-11 16:43:50 -08:00
Leah Amelia Chen
56ea6c406c gtk(x11): set WINDOWID env var for subprocesses
`WINDOWID` is the conventional environment variable for scripts that
want to know the X11 window ID of the terminal, so that it may call
tools like `xprop` or `xdotool`. We already know the window ID for
window protocol handling, so we might as well throw this in for
convenience.
2025-02-11 13:42:12 -08:00
Bryan Lee
bf6cce23da Prevent hyperlink hover state when mouse is outside viewport 2025-01-22 02:49:37 +08:00
otomist
e5a3be3c46 use whitespace instead of new flag for selecting full line 2025-01-20 10:23:41 -08:00
otomist
95debc59d1 add and use flag for selecting empty lines in the selectLine function 2025-01-14 12:04:43 -05:00
Mitchell Hashimoto
844f20d01f Handle setting _NET_WM_STATE (#4936)
As recommended in
https://github.com/ghostty-org/ghostty/pull/4927#issuecomment-2585003934,
adds a config option `maximize` for starting a window in a maximized
state in terms of window properties. Also adds a `toggle_maximize`
keybind to allow users to manually toggle this feature on and off.

It might make more sense to make this an optional config value so that
we don't toggle the state off if the WM already handles that for us, but
I'll let a reviewer decide.

Closes https://github.com/ghostty-org/ghostty/issues/4646
2025-01-13 13:14:31 -08:00
Mitchell Hashimoto
6c5c5b2ec0 core: clear selection whenever preedit is changed 2025-01-11 14:06:42 -08:00
Bryan Lee
2409d46600 Correct IME position calculation with window padding 2025-01-12 01:15:53 +08:00
Adam Wolf
c9636598fc chore: rename config value to maximize and move startup logic to proper location 2025-01-10 23:24:00 -06:00
Adam Wolf
8102fddceb apprt/gtk: add toggle_maximize keybind and window-maximize config option 2025-01-10 22:42:41 -06:00
Bryan Lee
5213edfa6c Add keybind action copy_url_to_clipboard 2025-01-08 13:22:33 -08:00
Bryan Lee
140ac93884 Add close_tab keybinding action for macOS
Implement `close_tab` keybinding action to close the current tab and all splits within that tab.
2025-01-08 12:04:40 -08:00
Sabarigirish Manikandan
306c7ea2be close_tab keybind (gtk apprt only) (#4033)
Title. Adds a close_tab keybind that essentially behaves the exact same
as clicking the tab close button on the tab bar.
2025-01-08 19:07:00 +00:00
George Joseph
c127daa552 Fix minimum initial window size
Change the calculation of minimum initial window size so it agrees with
the documented 10x4 cells instead of 640x480 px.

Resolves: #4655
2025-01-06 07:13:51 -07:00
Mitchell Hashimoto
1bcfff3b79 macos: manual send keyUp event for command key 2025-01-04 14:02:16 -08:00
Mitchell Hashimoto
4d103ca16d core: add keyEventIsBinding
This API can be used to determine if the next key event, if given as-is,
would result in a key binding being triggered.
2025-01-04 12:45:15 -08:00
Mitchell Hashimoto
e6399c947a update our default bindings that are performable 2025-01-02 15:54:09 -08:00
Mitchell Hashimoto
95b73f197f Add docs for performable 2025-01-02 15:41:01 -08:00
Ethan Conneely
f38d1585e8 Do nothing if action not performed with flag 2025-01-02 01:14:47 +00:00
Ethan Conneely
46097617b4 copy_to_clipboard return false if not performed 2025-01-02 00:18:05 +00:00
Jeffrey C. Ollie
cf34ffa28e core: fix windows compile regression from #4021 2024-12-31 12:56:18 -06:00
Mitchell Hashimoto
d59a57e133 write_*_file actions default to mode 0600
This commit changes the default filemode for the write actions so that
it is only readable and writable by the user running Ghostty.
2024-12-31 07:16:43 -08:00
Mitchell Hashimoto
d7c5017cd2 surface: don't issue mode 2031 DSR reports when colors are changed by a VT sequence (#3994)
#3965
2024-12-30 21:10:32 -08:00
Bryan Lee
c62f64866c Ensure correct coordinate ordering in selection file write
When writing selected text to file, use `topLeft` and `bottomRight` instead of
`start` and `end` to ensure correct coordinate ordering. This fixes an issue
where selection files could be empty when selecting text in reverse order.

- Use `terminal.Selection.topLeft()` for start coordinate
- Use `terminal.Selection.bottomRight()` for end coordinate
2024-12-31 01:14:56 +08:00
Mitchell Hashimoto
e17bb69645 config: edit opens AppSupport over XDG on macOS, prefers non-empty paths (#4004)
Fixes #3953
Fixes #3284

This fixes two issues. In fixing one issue, the other became apparent so
I fixed both in this one commit.

The first issue is that on macOS, the `open` command should take the
`-t` flag to open text files in a text editor. To do this, the `os.open`
function now takes a type hint that is used to better do the right
thing.

Second, the order of the paths that we attempt to open when editing a
config on macOS is wrong. Our priority when loading configs is well
documented:
https://ghostty.org/docs/config#macos-specific-path-(macos-only). But
open_config does the opposite. This makes it too easy for people to have
configs that are being overridden without them realizing it.

This commit changes the order of the paths to match the documented
order. If neither path exists, we prefer AppSupport.
2024-12-30 08:52:55 -08:00
Mitchell Hashimoto
318641f5a1 surface: handle hyperlinks more reliably (#3903)
We refresh the link hover state in two (generic) cases

1. When the modifiers change
2. When the cursor changes position

Each of these have additional state qualifiers. Modify the qualifiers
such that we refresh links under the following scenarios:

1. Modifiers change
  - Control is pressed (this is handled in the renderer)
  - Mouse reporting is off
    OR
    Mouse reporting is on AND shift is pressed AND we are NOT reporting
    shift to the terminal

2. Cursor changes position
  - Control is pressed (this is handled in the renderer)
  - We previously were over a link
  - The position changed (or we had no previous position)
  - Mouse reporting is off
    OR
    Mouse reporting is on AND shift is pressed AND we are NOT reporting
    shift to the terminal

This fixes a few issues with the previous implementation:

1. If mouse reporting was on and you were over a link, pressing ctrl
   would enable link hover state. If you moved your mouse, you would
   exit that state. The logic in the keyCallback and the
   cursorPosCallback was not the same. Now, they both check for the same
   set of conditions
2. If mouse reporting was off, you could hold control and move the mouse
   to discover links. If mouse reporting was on, holding control + shift
   would not allow you to discover links. You had to be hovering one
   when you pressed the modifiers. Previously, we only refreshed links
   if we *weren't* reporting the mouse event. Now, we refresh links even
   even if we report a mouse event (ie a mouse motion event with the
   shift modifier pressed *will* hover links and also report events)

## Old Behavior

Notice that the state of the hyperlink is erratic in `comlink`. When I
am over it and press ctrl the link is underlined and the url hint in the
lower left shown for one frame, but then the state is dropped.


https://github.com/user-attachments/assets/52d6a8c8-8459-4d67-85eb-5d91f9833771

## New Behavior

State is retained when holding ctrl+shift. And the link only underlines
if I press both ctrl+shift. If I move the mouse around while holding
these keys, I can discover new links.


https://github.com/user-attachments/assets/78fa8e97-eb0c-4618-bd96-fe40d6bc67ce
2024-12-30 08:50:35 -08:00
Mitchell Hashimoto
adcaff7137 config: edit opens AppSupport over XDG on macOS, prefers non-empty paths
Fixes #3953
Fixes #3284

This fixes two issues. In fixing one issue, the other became apparent so
I fixed both in this one commit.

The first issue is that on macOS, the `open` command should take the
`-t` flag to open text files in a text editor. To do this, the `os.open`
function now takes a type hint that is used to better do the right
thing.

Second, the order of the paths that we attempt to open when editing a
config on macOS is wrong. Our priority when loading configs is well documented:
https://ghostty.org/docs/config#macos-specific-path-(macos-only). But
open_config does the opposite. This makes it too easy for people to have
configs that are being overridden without them realizing it.

This commit changes the order of the paths to match the documented
order. If neither path exists, we prefer AppSupport.
2024-12-30 08:43:59 -08:00
moni-dz
4d983a2083 surface: don't issue mode 2031 DSR reports when colors are changed by a VT sequence 2024-12-30 12:33:05 +08:00
Mitchell Hashimoto
5be77ded3a config: add title_report (default false) to configure CSI 21 t 2024-12-29 08:56:53 -08:00
Tim Culverhouse
e24f33ae6b surface: handle hyperlinks more reliably
We refresh the link hover state in two (generic) cases

1. When the modifiers change
2. When the cursor changes position

Each of these have additional state qualifiers. Modify the qualifiers
such that we refresh links under the following scenarios:

1. Modifiers change
  - Control is pressed (this is handled in the renderer)
  - Mouse reporting is off
    OR
    Mouse reporting is on AND shift is pressed AND we are NOT reporting
    shift to the terminal

2. Cursor changes position
  - Control is pressed (this is handled in the renderer)
  - We previously were over a link
  - The position changed (or we had no previous position)
  - Mouse reporting is off
    OR
    Mouse reporting is on AND shift is pressed AND we are NOT reporting
    shift to the terminal

This fixes a few issues with the previous implementation:

1. If mouse reporting was on and you were over a link, pressing ctrl
   would enable link hover state. If you moved your mouse, you would
   exit that state. The logic in the keyCallback and the
   cursorPosCallback was not the same. Now, they both check for the same
   set of conditions
2. If mouse reporting was off, you could hold control and move the mouse
   to discover links. If mouse reporting was on, holding control + shift
   would not allow you to discover links. You had to be hovering one
   when you pressed the modifiers. Previously, we only refreshed links
   if we *weren't* reporting the mouse event. Now, we refresh links even
   even if we report a mouse event (ie a mouse motion event with the
   shift modifier pressed *will* hover links and also report events)
2024-12-29 10:04:06 -06:00
Mohammadi, Erfan
85fc49b22c confirm-close-surface option can be set to always to always require confirmation
Fixes #3648
The confirm-close-surface configuration can now be set to always
ensuring a confirmation dialog is shown before closing a surface, even
if shell integration indicates no running processes.
2024-12-28 19:16:36 -08:00
moni
819b7e066d surface: don't early return when clearing hyperlinks
When outside the viewport, other actions such as scrolling might be happening, and doing an early return when clearing hyperlinks prevents scrolling upwards.

We do not early return so we can process scrolling when it happens.
2024-12-21 04:24:00 +08:00
Mitchell Hashimoto
df97c19a37 macOS: "option-as-alt" defaults to "true" for US keyboard layouts
A common issue for US-centric users of a terminal is that the "option"
key on macOS is not treated as the "alt" key in the terminal.

## Background

macOS does not have an "alt" key, but instead has an "option" key. The "option"
key is used for a variety of purposes, but the troublesome behavior for some
(and expected/desired behavior for others) is that it is used to input special
characters.

For example, on a US standard layout, `option-b` inputs `∫`. This is not
a typically desired character when using a terminal and most users will
instead expect that `option-b` maps to `alt-b` for keybinding purposes
with whatever shell, TUI, editor, etc. they're using.

On non-US layouts, the "option" key is a critical modifier key for
inputting certain characters in the same way "shift" is a critical
modifier key for inputting certain characters on US layouts.

We previously tried to change the default for `macos-option-as-alt`
to `left` (so that the left option key behaves as alt) because I had the
wrong assumption that international users always used the right option
key with terminals or were used to this. But very quickly beta users
with different layouts (such as German, I believe) noted that this is
not the case and broke their idiomatic input behavior. This behavior was
therefore reverted.

## Solution

This confusing behavior happened frequently enough that I decided to
implement the more complex behavior in this commit. The new behavior is
that when a US layout is active, `macos-option-as-alt` defaults to true
if it is unset. When a non-US layout is active, `macos-option-as-alt`
defaults to false if it is unset. This happens live as users change
their keyboard layout.

**An important goal of Ghostty is to have zero-config defaults** that
satisfy the majority of users. Fiddling with configurations is -- for
most -- an annoying task and software that works well enough out of the
box is delightful. Based on surveying beta users, I believe this commit
will result in less configuration for the majority of users.

## Other Terminals

This behavior is unique amongst terminals as far as I know.
Terminal.app, Kitty, iTerm2, Alacritty (I stopped checking there) all
default to the default macOS behavior (option is option and special
characters are inputted).

All of the aforementioned terminals have a setting to change this
behavior, identical to Ghostty (or, Ghostty identical to them perhaps
since they all predate Ghostty).

I couldn't find any history where users requested the behavior of
defaulting this to something else for US based keyboards. That's
interesting since this has come up so frequently during the Ghostty
beta!
2024-12-11 10:27:08 -08:00
Mitchell Hashimoto
43a7dece02 config: title can reload at runtime
Related to #2898
2024-12-08 11:22:15 -08:00