Commit Graph

7842 Commits

Author SHA1 Message Date
Jeffrey C. Ollie
df86e30877 drop utf-8 bom log message to info 2025-11-06 11:00:38 -06:00
Jeffrey C. Ollie
c8e317b60f core: handle utf-8 bom in config files
If a UTF-8 byte order mark starts a config file, it should be ignored.
This also refactors config file loading a bit to reduce redundant code
and to make it possible to test loading config from a file.

Fixes #9490
2025-11-06 10:59:26 -06:00
Mitchell Hashimoto
3d58dc51c9 terminal: keypad variation sequences should respect VS16
This fixes the VS16 issues found in this test:
https://ucs-detect.readthedocs.io/sw_results/ghostty.html#ghostty
This is also a more robust way to handle VS15/16 in general. 

This commit also changes our propeties to be a packed struct which
reduces its size from 4 bytes to 1 and likewise drops our unicode table
size 4x.
2025-11-06 07:05:57 -08:00
Mitchell Hashimoto
631c58a302 unicode: update uucode, force emoji modifiers width 2 as standalone
This updates uucode. As part of this, the wcwidth implementation was
updated (in uucode) to make emoji modifiers width ZERO. But if they're
standalone, we want them as width 2.

So this also contains a change to force them as width 2 for our width
calculation. This only matters for standalone emoji modifiers, because
when they form a valid grapheme we don't use this width calculation.
2025-11-05 14:57:48 -08:00
Avery Mcnab
13d5f0c503 Add an example for palette configuration
I found this syntax a bit confusing when I first read it, so I thought it would be helpful for the next person to add a short example.
2025-11-04 15:02:03 +00:00
Chris Marchesi
e7c68142e3 apprt/gtk: (clipboard) add X11 atoms, extra MIME types for text content
This adds the UTF8_STRING atom and explicit UTF-8 character set MIME
type (text/plain;charset=utf-8) to text content when being sent to the
clipboard under the new multipart support.

This fixes clipboard support under X11 particularly, which generally
looks for the UTF8_STRING atom when looking for text content. This can be
verified with xclip -out -verbose, or trying to do things like paste in
Firefox.

I've noted that there's a number of other older atoms that exist, but
I've refrained from adding them for now. Kitty only seems to set
UTF8_STRING and I've had a hard time finding consensus on what exactly
is the correct set otherwise.
2025-11-02 11:19:10 -08:00
Mitchell Hashimoto
46db1cfd8f apprt/gtk: set multiple content types for clipboard ops
This supports the new `setClipboard` parameter that may provide data in
multiple formats, allowing us to copy rich text to/from the clipboard as
well as other types in the future.
2025-10-31 10:53:10 -07:00
Mitchell Hashimoto
901708e8da input: write_*_file actions take an optional format
Fixes #9398
2025-10-31 09:49:59 -07:00
Mitchell Hashimoto
24b9778432 input: add more copy formatted options to the command palette 2025-10-31 08:21:16 -07:00
Mitchell Hashimoto
05d2f881b6 terminal: emit non-ASCII characters as Unicode codepoints for HTML
Fixes #9426

Since we can't set the meta charset tag since we emit partial HTML, we
use codepoint entities like `{` for non-ASCII characters to
ensure proper rendering.
2025-10-31 08:15:25 -07:00
Mitchell Hashimoto
54fe54fe37 apprt/gtk: fix build errors 2025-10-30 14:43:31 -07:00
Mitchell Hashimoto
f3352dd90b core: copy the proper format to the clipboard as configured 2025-10-30 14:36:32 -07:00
Mitchell Hashimoto
9a198b47a0 apprt/gtk: support new set clipboard API 2025-10-30 14:11:00 -07:00
Mitchell Hashimoto
26bdb12f64 core: update Surface to use setClipboard 2025-10-30 14:08:29 -07:00
Mitchell Hashimoto
0f1c46e4a4 macos: support setting multiple clipboard content types 2025-10-30 14:01:58 -07:00
Mitchell Hashimoto
df037d75a6 copy_to_clipboard format types 2025-10-30 13:40:32 -07:00
Mitchell Hashimoto
83a4f32a14 terminal: formatter improvements for color handling 2025-10-30 10:39:46 -07:00
Mitchell Hashimoto
450155f150 zig fmt 2025-10-30 10:06:13 -07:00
Mitchell Hashimoto
27a98123a0 terminal: readonly stream can update more colors now 2025-10-30 09:58:56 -07:00
Mitchell Hashimoto
2daecd94a5 renderer: use terminal color state, remove color messages 2025-10-30 09:52:39 -07:00
Mitchell Hashimoto
77343bb06e terminal: move color state fully into the terminal for fg/bg/cursor 2025-10-30 09:33:21 -07:00
Mitchell Hashimoto
cabca0aca8 terminal: unify palette functionality into shared type DynamicPalette 2025-10-30 09:15:43 -07:00
Jon Parise
4818c2b896 cli: make the entire +ssh-cache cache path (#9403)
std.fs.makeDirAbsolute() only creates the last directory. We instead
need Dir.makePath() to make the entire path, including intermediate
directories.

This fixes the problem where a missing $XDG_STATE_HOME directory (e.g.
~/.local/state/) would prevent our ssh cache file from being created.

Fixes #9393
2025-10-29 21:29:40 -07:00
Mitchell Hashimoto
c0e483c49e terminal: HTML formatting (#9402)
This adds HTML formatting capabilities to the formatter package. HTML is
emitted as inline styles. For palette indexes, direct RGB is emitted if
we have access to a palette; otherwise, we fall back to CSS variables.

This isn't exposed to end users yet, but will enable copy as html
features. This is available in libghostty.

Fixes #9395

**AI disclosure:** I used AI (Amp) to help me write tests, but the
implementation was done manually. I reviewed everything.
2025-10-29 20:55:52 -07:00
Daniel Wennberg
e70ca0b9b5 Don't encode option as alt in modify other keys 2 (#9406)
There have been frequent reports of key encoding issues in vim and tmux
with version 1.2.3 on macOS: #9340, #9361, #9401,
https://discord.com/channels/1005603569187160125/1432413679806320772.

I think I found the culprit: the option modifier is always passed as alt
to the core, regardless of `macos-option-as-alt`. Since #9289, this
means that a key event where option was used (as option) for translation
is encoded as if it also has the alt modifier.

For example, consider the many European keyboard layouts where option+8
sends `[`. If `macos-option-as-alt = true`, Ghostty correctly intercepts
the option and encodes option+8 as alt+8 instead (that is,
`^[[27;3;56~`). But if `macos-option-as-alt = false`, Ghostty first
allows option to be used for translation, obtaining `[`, and then
encodes the key event as alt+[ (that is, `^[[27;3;91~`), rather than
just `[`.

Tweaking the test case from #9289, here's a quick way to see this: set
`macos-option-as-alt = left`, run
```
printf '\033[>4;2m'
cat
```
choose a European keyboard layout (e.g., Norwegian), and hit both
left-option+8 and right-option+8. The former inserts `^[[27;3;56~` in
all well-behaved terminals. The latter inserts `[` in other terminals,
but `^[[27;3;91~` in Ghostty.

Basically, while modify other keys 2 does require encoding consumed
modifiers, the option key is not one of the supported modifiers, and
should not be included (as alt or anything else) when
`macos-option-as-alt = false`.

This PR removes alts that were actually options when using modify other
keys 2.
2025-10-29 20:29:53 -07:00
Mitchell Hashimoto
a4d54dca1c terminal: remove all legacy encodeUtf8 functions, replace with formatter (#9392)
This removes all existing functionality that I know of that encodes a
terminal, screen, pagelist, or page as plaintext and unifies all logic
onto the formatter system.
2025-10-29 10:50:47 -07:00
Mitchell Hashimoto
028ce83d46 terminal: selectionString now uses ScreenFormatter (#9391)
This replaces the logic of Screen.selectionString with calls to
ScreenFormatter.

This means that all our various selection-based features like copying to
clipboards now uses the new formatter. The formatter code is now
user-facing.

This forced us to pass all selectionString tests which revealed some
edge cases that were not handled correctly before in the formatter! The
formatter now handles:

- Plain text now emits `\n` instead of `\r\n`. VT emits `\r\n`
 - Rectangular selections
 - Various wide character edge cases
 - Selection is now inclusive on the end, not exclusive
2025-10-29 10:16:38 -07:00
Mitchell Hashimoto
d62235cb62 terminal: Add pin_map/point_map to formatter (#9379)
This adds the option `pin_map` or `point_map` (for pages) to formatter,
allowing callers to get a byte-by-byte mapping for where on the screen
each encoding maps to. This is used by search internals and hyperlinks.
I haven't hooked that all up yet. This diff was big enough I wanted this
as one.

Tests significantly cover the new feature.

Next up, we'll rip out `selectionString` and replace it with formatters!
2025-10-28 11:23:16 -07:00
Mitchell Hashimoto
17f2dc59fa terminal: formatter that can emit VT sequences (#9374)
This adds a new formatter that can be used with standard Zig `{f}`
formatting that emits any portion of the terminal screen as VT
sequences. In addition to simply styling, this can emit the entire
terminal/screen state such as cursor positions, active style, terminal
modes, etc.

To do this, I've extracted all formatting to a dedicated `formatter`
package within `terminal`. This handles all formatting types (currently
plaintext and VT formatting, but can imagine things like HTML in the
future). Presently, we have "formatting" split out across a variety of
places in Terminal, Screen, PageList, and Page. I didn't remove this
code yet but I intend to unify it all on formatter in the future.

This also doesn't expose this functionality in any user-facing way yet.
This PR just adds it to the ghostty-vt Zig module and unit tests it.
Ghostty app changes will come later.

**This also improves the readonly stream** to handle OSC color
operations for _setting_ but it doesn't emit any responses of course,
since its readonly.
2025-10-28 07:23:00 -07:00
Jon Parise
86ec29237c cli: make +ssh-cache contains() a read-only op (#9369)
contains() checks the cache for an existing entry. It's a read-only
operation, so we can drop the write bit and fixupPermissions() call.
This is also consistent with the list() operation.

fixupPermissions() is unnecessary in this code path. It provided minimal
additional security because all of our creation and update operations
enforce 0o600 (owner-only) permissions, so anyone tampering with this
file has already gotten around that. The contents of this (ssh host
cache) file are also not sensitive enough to warrant any additional
hardening on reads.
2025-10-27 09:06:55 -07:00
Mitchell Hashimoto
7d7c0bf5cd lib-vt: Wasm SGR helpers and example (#9362)
This adds some convenience functions for parsing SGR sequences
WebAssembly and adds an example demonstrating SGR parsing in the
browser.
2025-10-26 13:19:55 -07:00
Mitchell Hashimoto
a82ad89ef3 lib-vt: C API for SGR parser (#9352)
This exposes the SGR parser to the C and Wasm APIs. An example is shown
in c-vt-sgr.

Compressed example:

```c
#include <assert.h>
#include <stdio.h>
#include <ghostty/vt.h>

int main() {
  // Create parser
  GhosttySgrParser parser;
  assert(ghostty_sgr_new(NULL, &parser) == GHOSTTY_SUCCESS);

  // Parse: ESC[1;31m (bold + red foreground)
  uint16_t params[] = {1, 31};
  assert(ghostty_sgr_set_params(parser, params, NULL, 2) == GHOSTTY_SUCCESS);

  printf("Parsing: ESC[1;31m\n\n");

  // Iterate through attributes
  GhosttySgrAttribute attr;
  while (ghostty_sgr_next(parser, &attr)) {
    switch (attr.tag) {
      case GHOSTTY_SGR_ATTR_BOLD:
        printf("✓ Bold enabled\n");
        break;
      case GHOSTTY_SGR_ATTR_FG_8:
        printf("✓ Foreground color: %d (red)\n", attr.value.fg_8);
        break;
      default:
        break;
    }
  }

  ghostty_sgr_free(parser);
  return 0;
}
```

**AI disclosure:** Amp wrote most of the C headers, but I verified it
all. https://ampcode.com/threads/T-d9f145cb-e6ef-48a8-ad63-e5fc85c0d43e
2025-10-25 21:26:06 -07:00
Dusk
27b0978cd5 macos: use system beep for bell (#9339)
This seems pretty straightforward. I've tested it and it does what I'd
expect it to do.

Fixes #9338
2025-10-26 03:24:52 +00:00
Daniel Wennberg
973cfd98a5 Update Inspector to the new Stream/VTHandler APIs (#9350)
Fixes a double-free bug when closing the inspector.

Not sure if there's a good way to add a test to check that allocation
and deallocation are sound here? To instantiate an Inspector you need a
Surface, which in turn requires an entire App/apprt. Doesn't look like
the repo has any tests with that kind of scope at the moment?
2025-10-25 18:10:59 -07:00
Mitchell Hashimoto
580262c96f terminal: add ReadonlyStream that updates terminal state (#9346)
This adds a new stream handler implementation that updates terminal
state in reaction to VT sequences, but doesn't perform any of the
actions that would require responses (e.g. queries).

This is exposed in two ways: first, as a standalone `ReadonlyStream` and
`ReadonlyHandler` type that contains all the implementation. Second, as
a convenience func on `Terminal` as `vtStream` and `vtHandler` which
return their respective types preconfigured to update the calling
terminal state.

This dramatically simplifies libghostty-vt usage from Zig (and will
eventually be exposed to C, too) since a Terminal on its own is ready to
go as a full VT parser and state machine without needing to build any
custom types!

There's a second big bonus here which is that our `stream_readonly.zig`
tests are true end-to-end tests for raw bytes to terminal state. This
will let us test a wider variety of situations more broadly. To start,
there are only a handful of tests implemented here.

**AI disclosure:** Amp wrote basically this whole thing, but I reviewed
it. https://ampcode.com/threads/T-3490efd2-1137-4112-96f6-4bf8a0141ff5
2025-10-25 14:52:33 -07:00
Mitchell Hashimoto
9703d6cb6c macOS: update window appearance based on preferredBackgroundColor (#9344)
### Background

> Reported from
https://discord.com/channels/1005603569187160125/1320882404717625374/1431258448439279709


Per current implementation, when `macos-titlebar-style` is `tabs` or
`transparent`, the titlebar's background is hidden to enable a blur
effect, but this could result in an incorrect appearance when the
window's appearance is different from the one based on the terminal's
background color. For instance, with the following configs:

```
window-theme = "light"
// theme will be default to Ghostty, which is dark
```

or

```
window-theme = "system"
// theme will be default to Ghostty, which is dark
// and system theme is set to light
```

### Changes

Update window theme based on the terminal's background color when using
`tabs` or `transparent`
2025-10-25 13:34:13 -07:00
Mitchell Hashimoto
83104ff27a Convert terminal.Stream to use a tagged union, remove hasDecl (#9342)
This removes our `@hasDecl` usage from `terminal.Stream` and instead
uses a tagged union approach similar to what we already do for apprt
actions. The reasons to do this:

1. It is less magic. You don't get new functionality by magically
implementing a function.
2. It is safer. You can't typo a function name and Zig's exhaustive enum
handling will force you to handle all cases (even if most cases are
no-ops). This also helps you as at the implementor know when new
functionality pops up.
3. It is easier to integrate into C (for libghostty-vt). We can expose a
single tagged union type with a single callback rather than whatever the
previous mess was. This PR doesn't do this yet.

In addition, this PR adds in some helpers necessary to make it easier to
make C ABI compatible tagged unions. This lays the groundwork for our
libghostty-vt work but isn't exposed directly there yet. This PR has no
functional changes. Everything should behave identically as before.

I'm PRing this now because its already a huge diff, and I want to get
this in before I make more meaningful changes such as exposing some of
this to libghostty or adding a simpler Stream handler that maps to
terminal state for the Zig module and so on.

## Benchmarks

There's no meaningful impact on VT processing, I'd say all changes seen
below are noise:

<img width="2038" height="1392" alt="CleanShot 2025-10-25 at 07 10
04@2x"
src="https://github.com/user-attachments/assets/af6fa611-5b35-44d0-91ae-26955b1f980a"
/>

## One more `@hasDecl`

There is one more `hasDecl` remaining for `handleManually`. This is a
special case that's only used by our inspector. I think there is a
better way to do this but I didn't want to bloat this PR with anything
more! This doesn't impact our primary consumers of stream.

## AI Disclosure

I used AI considerably in handling the rote tasks in refactoring this. I
did the design myself manually but then prompted AI to help complete it
step by step. I did review each manually and understand it but I want to
take a careful review again...
2025-10-25 13:33:18 -07:00
Lars
d39cc6d478 macOS: update window appearance based on preferredBackgroundColor 2025-10-25 19:35:34 +02:00
Mitchell Hashimoto
1d03451d4f terminal: OSC color operations 2025-10-25 07:03:21 -07:00
Mitchell Hashimoto
e13f9b9e8c terminal: kitty color 2025-10-25 06:42:20 -07:00
Mitchell Hashimoto
a85ad0e4f8 terminal: unused decls 2025-10-24 15:20:16 -07:00
Mitchell Hashimoto
e49694439c terminal: setAttribute 2025-10-24 11:53:25 -07:00
Mitchell Hashimoto
56376a8a38 sgr: make C compat 2025-10-24 11:48:01 -07:00
Mitchell Hashimoto
5ba451d073 terminal: configureCharset 2025-10-24 11:27:48 -07:00
Mitchell Hashimoto
4d028dac1f terminal: some osc types 2025-10-24 11:17:31 -07:00
Jon Parise
3f75c66e83 cli: simplify +ssh-cache cache key validation (#9331)
Remove the semi-magic upper bound on the total cache key length. The
hostname and username validation routines will perform their own length
checks.

Also consolidate this function's tests. We previously had a few
redundant test cases.
2025-10-24 07:28:50 -07:00
Mitchell Hashimoto
bce1164ae6 terminal: cursor style 2025-10-24 07:26:04 -07:00
Mitchell Hashimoto
fd0f9bb843 terminal: device attributes 2025-10-24 07:17:44 -07:00
Mitchell Hashimoto
a4a37534d7 terminal: missed some invoke charsets 2025-10-24 07:11:09 -07:00
Mitchell Hashimoto
e347ab6915 terminal: device attributes 2025-10-24 07:08:34 -07:00