feat(windows): port Ghostty's Windows code paths
Ports the Windows branches of the Zig code behind cfg(windows): ConPTY pty (CreatePseudoConsole, pipes, resize), CreateProcessW with the pseudo-console attribute list, env blocks and command-line quoting, a pipe read thread with CancelIoEx and a WaitForMultipleObjects IO loop, plus os helpers (home dir, env, paths, temp dirs, hostname, XDG via LOCALAPPDATA) and config/input/terminal/crash Windows branches. Compile-checked with `cargo check --target x86_64-pc-windows-gnu` for vt, unicode, datastruct, input, os, config, terminal and termio (setup in docs/rewrite/notes/windows-WIN.md); cannot run here. Platform-independent pieces (quoting with a CommandLineToArgvW round-trip, env block encoding) have unit tests. Test Plan: - cargo test -p ghostty-termio windows_args - cargo check --target x86_64-pc-windows-gnu -p ghostty-termio
This commit is contained in:
1 parent
42cb8796da
commit
3c8fae1089
8 files changed
+2402
No files matched your search
@@ -0,0 +1,105 @@
|
||||
# Windows port (agent WIN)
|
||||
|
||||
Windows-specific Zig code ported behind `cfg(windows)`; Linux code paths are
|
||||
unchanged. Windows is compile-checked only (`cargo check --target
|
||||
x86_64-pc-windows-gnu`), nothing can be run here.
|
||||
|
||||
## Verifying
|
||||
|
||||
```
|
||||
RUSTC_WRAPPER= PKG_CONFIG_ALLOW_CROSS=1 PKG_CONFIG_PATH=<dir with stub fontconfig.pc> \
|
||||
CC_x86_64_pc_windows_gnu=x86_64-w64-mingw32-gcc AR_x86_64_pc_windows_gnu=x86_64-w64-mingw32-ar \
|
||||
cargo check --target x86_64-pc-windows-gnu --tests \
|
||||
-p ghostty-vt -p ghostty-unicode -p ghostty-datastruct -p ghostty-input \
|
||||
-p ghostty-os -p ghostty-config -p ghostty-terminal -p ghostty-termio
|
||||
```
|
||||
* `RUSTC_WRAPPER=` is needed because the `kache` rustc wrapper from
|
||||
`~/.cargo/config.toml` is picked up by `cc-rs` as a compiler launcher and
|
||||
breaks the mingw C builds (onig_sys, freetype-sys, harfbuzz-sys).
|
||||
* mingw (`x86_64-w64-mingw32-gcc/g++`, cmake) exists, so the C crates build:
|
||||
`onig_sys` natively, `freetype-sys` / `harfbuzz-sys` via their `bundled`
|
||||
feature (enabled only in the `cfg(windows)` dependency table of
|
||||
ghostty-font; Zig also builds them from source).
|
||||
* `yeslogic-fontconfig-sys` still wants `pkg-config` for fontconfig (Zig's
|
||||
default backend there is `fontconfig_freetype`, built from source). For
|
||||
`cargo check` a stub `fontconfig.pc` + `PKG_CONFIG_ALLOW_CROSS=1` is enough
|
||||
(no linking happens). A real Windows link needs fontconfig from vcpkg/MSYS2.
|
||||
* Windows clippy: `cargo clippy --target x86_64-pc-windows-gnu --no-deps
|
||||
-p ghostty-os -p ghostty-termio -p ghostty-crash -p ghostty-config
|
||||
-p ghostty-terminal -p ghostty-input --all-targets -- -D warnings` is clean.
|
||||
|
||||
## What was ported
|
||||
|
||||
| Zig | Rust |
|
||||
|-----|------|
|
||||
| `os/windows.zig` | `ghostty-os/src/windows.rs` (`windows-sys` re-export, `PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE`, `to_wide_nul`, `computer_name`) |
|
||||
| `os/pipe.zig` (CreatePipe) | `ghostty-os/src/pipe.rs` (returns `OwnedHandle`s) |
|
||||
| `os/homedir.zig` | `homedir.rs`: `HOMEDRIVE`+`HOMEPATH` (`home_windows`, tested), `expand_home` is identity |
|
||||
| `os/env.zig` | `;` delimiter; `EnvMap` is ASCII case-insensitive on Windows (Zig's EnvMap hash context); `filter_snap_paths` no-op |
|
||||
| `os/file.zig` | `alloc_tmp_dir` = `%TMP%` only (None if unset); rlimit helpers are unix only |
|
||||
| `os/path.zig` | `;` delimiter, `\` separator, every file is executable |
|
||||
| `os/hostname.zig` | `GetComputerNameA` |
|
||||
| `os/open.zig` | `rundll32 url.dll,FileProtocolHandler` (merged with M1's `open_command`) |
|
||||
| `os/xdg.zig` | `LOCALAPPDATA` fallback for the XDG env var |
|
||||
| `os/resourcesdir.zig` | sentinel `terminfo/ghostty.terminfo` |
|
||||
| `os/desktop.zig` | `DesktopEnvironment::Windows`, `launched_from_desktop` uses `std::process::id` |
|
||||
| `os/i18n.zig` | `init` is a no-op, `tr` returns the msgid (gettext is not built on Windows) |
|
||||
| `os/temp_dir` | `BCryptGenRandom` for the name, no unix mode |
|
||||
| `os/passwd.zig` (`@compileError` on Windows) | `ghostty_os::passwd` stub returning an empty `Entry`; `flatpak::is_flatpak()` is `false` |
|
||||
| `pty.zig` `WindowsPty` | `ghostty-termio/src/pty_windows.rs` (named pipe for input, anonymous pipe for output, `CreatePseudoConsole`/`ResizePseudoConsole`/`ClosePseudoConsole`, non-inheritable handles, drop order as `deinit`) |
|
||||
| `Command.zig` Windows branch | `command_windows.rs` (`CreateProcessW` + `STARTUPINFOEXW` + proc-thread attribute list for the pseudo console, NUL stdio, cwd, env block, `wait` = `WaitForSingleObject`+`GetExitCodeProcess`, `terminate`) and the pure `windows_args.rs` (`windows_create_command_line`, `create_windows_env_block`, `windows_shell_args`) |
|
||||
| `termio/Exec.zig` Windows branches | `exec_windows.rs` (read thread = blocking `ReadFile` on the output pipe, quit pipe polled with `PeekNamedPipe`, interrupted with `CancelIoEx`; process exit via the process handle; `cmd.exe` default shell and `%WINDIR%\System32\cmd.exe /C` for shell commands; `TerminateProcess` on stop) |
|
||||
| `Thread.zig` loop (libxev IOCP) | `thread_windows.rs`: `WaitForMultipleObjects` over mailbox event, stop event, process handle + deadline timeout |
|
||||
| `xev.Async` | `wakeup_windows.rs`: auto-reset event |
|
||||
| `config/Config.zig` Windows branches | `load_cli_args` has no argc fast path, `probable_cli_environment` is false, default shell `cmd.exe` + `%HOMEDRIVE%%HOMEPATH%` working dir, `~/` not expanded in `path.rs` |
|
||||
| `input/keycodes.zig` | native column 3 (win) on Windows |
|
||||
| `terminal/kitty/graphics_image.zig` | shared-memory medium returns `UnsupportedMedium`, tmp dir = `%TMP%` |
|
||||
| `crash/sentry.zig` | `init` is a no-op on Windows (as Zig), `signal_windows.rs` provides only `random_bytes` |
|
||||
|
||||
Module selection in termio is `#[cfg_attr(windows, path = "..._windows.rs")]`
|
||||
in `lib.rs` (pty, command, exec, wakeup) so the Linux files are untouched;
|
||||
`thread.rs` only gets `#[cfg(unix)]` on its poll loop and a `#[cfg(windows)]
|
||||
mod windows_loop` child module.
|
||||
|
||||
## Dependency gating
|
||||
|
||||
* ghostty-os: `gettext-rs`, `nix`, `rustix`, `zbus` -> `cfg(not(any(wasm32, windows)))`;
|
||||
`windows-sys` -> `cfg(windows)`. Unix-only modules (`flatpak`, `passwd`,
|
||||
`systemd`) are `cfg(unix)`; `flatpak` / `passwd` have tiny Windows stand-ins.
|
||||
* ghostty-termio: `libc`, `nix`, `rustix` (+ dev `zbus`, `rustix`) -> `cfg(unix)`;
|
||||
`windows-sys` -> `cfg(windows)`. Linux integration tests got `#![cfg(unix)]`.
|
||||
* ghostty-terminal: `rustix` (shm) -> not wasm/windows.
|
||||
* ghostty-crash: `libc` -> `cfg(unix)`.
|
||||
* ghostty-font: bundled freetype/harfbuzz on Windows (see above).
|
||||
|
||||
## Tests
|
||||
|
||||
Platform independent (run natively): `windows_args` (10 tests: command-line
|
||||
quoting rules incl. a CommandLineToArgvW round-trip reference splitter, env
|
||||
block layout/UTF-16/invalid unicode, `%WINDIR%` shell args), `path_join_with`
|
||||
Windows flavour, `home_windows`. Windows-only (compiled, not runnable here):
|
||||
ConPTY size, pipe round-trip, `cmd.exe /c exit 7`, wakeup event, wait timeout
|
||||
rounding, `exec_command` Windows variants, `hostname.exe` PATH lookup.
|
||||
Unix-specific existing tests are `cfg(unix)`-gated.
|
||||
|
||||
## Deviations / gaps
|
||||
|
||||
* No termios timer on Windows (Zig doesn't run it either); `focus_gained` is a
|
||||
no-op (Zig would `@panic` there).
|
||||
* Input writes go through a writer thread doing blocking overlapped
|
||||
`WriteFile`s (no libxev). Output uses plain blocking `ReadFile`.
|
||||
* Windows `exec::Config` omits `rt_pre_exec_info`, `rt_post_fork_info`,
|
||||
`create_scope`, `restore_rlimit` (cgroup/rlimit are Linux-only);
|
||||
ghostty-core's surface setup will need `cfg` around them when it gets a
|
||||
Windows apprt.
|
||||
* `Command::wait(block)` ignores `block` (blocks, like Zig). The thread
|
||||
handle from `CreateProcessW` is closed (Zig leaks it).
|
||||
* Fontconfig discovery is kept on Windows (needs a real fontconfig to link).
|
||||
* Not touched: `cli/ssh-cache/DiskCache` file locking, `cli/boo|list_colors|
|
||||
list_keybinds|edit_config` Windows branches (ghostty-cli), `benchmark/
|
||||
CodepointWidth`, `config/Config.zig` `probableCliEnvironment` env-based
|
||||
extras. ghostty-core/apprt-gtk are not Windows-checkable (GTK).
|
||||
* Unrelated breakage seen while verifying (other agents): `ghostty-config`
|
||||
`config.rs` uses `ghostty_os::launched_from_desktop` under `cfg!(macos)`
|
||||
which fails on wasm32; `ghostty-os/tests/common/flatpak_mock.rs` fails
|
||||
`clippy::needless_pass_by_value`; `ghostty-font` coretext_math clippy.
|
||||
Reference in new issue
Block a user