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
7.1 KiB
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 thekacherustc wrapper from~/.cargo/config.tomlis picked up bycc-rsas 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_sysnatively,freetype-sys/harfbuzz-sysvia theirbundledfeature (enabled only in thecfg(windows)dependency table of ghostty-font; Zig also builds them from source). yeslogic-fontconfig-sysstill wantspkg-configfor fontconfig (Zig's default backend there isfontconfig_freetype, built from source). Forcargo checka stubfontconfig.pc+PKG_CONFIG_ALLOW_CROSS=1is 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 warningsis 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 OwnedHandles) |
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) arecfg(unix);flatpak/passwdhave tiny Windows stand-ins. - ghostty-termio:
libc,nix,rustix(+ devzbus,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_gainedis a no-op (Zig would@panicthere). - Input writes go through a writer thread doing blocking overlapped
WriteFiles (no libxev). Output uses plain blockingReadFile. - Windows
exec::Configomitsrt_pre_exec_info,rt_post_fork_info,create_scope,restore_rlimit(cgroup/rlimit are Linux-only); ghostty-core's surface setup will needcfgaround them when it gets a Windows apprt. Command::wait(block)ignoresblock(blocks, like Zig). The thread handle fromCreateProcessWis closed (Zig leaks it).- Fontconfig discovery is kept on Windows (needs a real fontconfig to link).
- Not touched:
cli/ssh-cache/DiskCachefile locking,cli/boo|list_colors| list_keybinds|edit_configWindows branches (ghostty-cli),benchmark/ CodepointWidth,config/Config.zigprobableCliEnvironmentenv-based extras. ghostty-core/apprt-gtk are not Windows-checkable (GTK). - Unrelated breakage seen while verifying (other agents):
ghostty-configconfig.rsusesghostty_os::launched_from_desktopundercfg!(macos)which fails on wasm32;ghostty-os/tests/common/flatpak_mock.rsfailsclippy::needless_pass_by_value;ghostty-fontcoretext_math clippy.