Zig parses config values (cli/args.zig, Config.zig field parsers, config/string.zig) from raw byte slices, and each field type decides whether it requires UTF-8 (InvalidValue otherwise) or stores bytes. The port escape-encoded raw bytes into Strings at the line reader and let fields parse the escaped text, so fields could observe encoding artifacts; successive audits kept finding such leaks (RV5-RV8). Field parsers now receive the original bytes: text fields validate UTF-8 where Zig does, byte/path fields store bytes (EncodedOs/OsString). This resolves all 9 RV8 findings (docs/rewrite/notes/review-rv8-codex.md), each with a regression test: Windows path conversion fails with BadPathName instead of substituting U+FFFD; Windows process launch uses strict UTF-8 like Zig's Command; the WTF-8 decoder accepts paired- surrogate encodings like Zig; literal U+FDD0 Unicode key triggers; selection-word-chars and clipboard-codepoint-map reject invalid UTF-8; font style / codepoint-map family names use original bytes; C title actions forward bytes; D-Bus new-window/Flatpak conversions match Zig. Design, sweep and validation: docs/rewrite/notes/final-bytes-refactor.md. Also moves the bundled iTerm2-Color-Schemes license out of resources/themes/ so +list-themes no longer lists it as a theme (output is now byte-identical to Ghostty 1.3.1). Done by Codex (gpt-6-astra), reviewed and verified by the orchestrator. Test Plan: - cargo test --workspace --no-fail-fast (3428 passed, exit 0) - just check-macos (both), just check-windows, just check-wasm - +show-config --default --docs, +list-keybinds, +list-actions --docs, +list-themes --plain compared with /usr/bin/ghostty
125 lines
4.2 KiB
Rust
125 lines
4.2 KiB
Rust
//! `+version` (ZIG/src/cli/version.zig).
|
|
|
|
use std::io::{IsTerminal, Write};
|
|
|
|
use crate::{
|
|
build_info::{self, BuildInfo},
|
|
error::Error,
|
|
};
|
|
|
|
/// The `version` command is used to display information about Ghostty. Recognized as
|
|
/// either `+version` or `--version`.
|
|
pub fn run(_args: &[impl AsRef<[u8]>]) -> Result<u8, Error> {
|
|
let stdout = std::io::stdout();
|
|
let tty = stdout.is_terminal();
|
|
let mut out = std::io::BufWriter::new(stdout.lock());
|
|
write_version(&mut out, &build_info::get(), tty)?;
|
|
out.flush()?;
|
|
Ok(0)
|
|
}
|
|
|
|
fn version_na(v: Option<crate::build_info::Version>) -> String {
|
|
v.map_or_else(|| "unknown".to_string(), |v| v.to_string())
|
|
}
|
|
|
|
/// Write the version text.
|
|
pub fn write_version(out: &mut dyn Write, info: &BuildInfo, tty: bool) -> std::io::Result<()> {
|
|
if tty {
|
|
if let Some(commit) = &info.commit {
|
|
write!(
|
|
out,
|
|
"\x1b]8;;https://github.com/ghostty-org/ghostty/commit/{commit}\x1b\\"
|
|
)?;
|
|
}
|
|
}
|
|
write!(out, "Ghostty {}\n\n", info.version_string)?;
|
|
if tty {
|
|
write!(out, "\x1b]8;;\x1b\\")?;
|
|
}
|
|
|
|
writeln!(out, "Version")?;
|
|
writeln!(out, " - version: {}", info.version_string)?;
|
|
writeln!(out, " - channel: {}", info.release_channel)?;
|
|
|
|
writeln!(out, "Build Config")?;
|
|
// The Zig build prints its compiler version here.
|
|
writeln!(out, " - Rust version : {}", env!("GHOSTTY_RUSTC_VERSION"))?;
|
|
writeln!(out, " - build mode : {}", info.build_mode)?;
|
|
writeln!(out, " - app runtime : {}", info.app_runtime)?;
|
|
writeln!(out, " - font engine : {}", info.font_backend)?;
|
|
writeln!(out, " - renderer : {}", info.renderer)?;
|
|
// There is no libxev in the Rust port.
|
|
writeln!(out, " - libxev : n/a")?;
|
|
if info.app_runtime == ".gtk" {
|
|
let kernel_info = ghostty_os::get_kernel_info();
|
|
writeln!(
|
|
out,
|
|
" - kernel version: {}",
|
|
kernel_info
|
|
.as_deref()
|
|
.unwrap_or("Kernel information unavailable")
|
|
)?;
|
|
let de = match ghostty_os::desktop_environment() {
|
|
ghostty_os::DesktopEnvironment::Gnome => "gnome",
|
|
ghostty_os::DesktopEnvironment::Macos => "macos",
|
|
ghostty_os::DesktopEnvironment::Other => "other",
|
|
ghostty_os::DesktopEnvironment::Windows => "windows",
|
|
};
|
|
writeln!(out, " - desktop env : {de}")?;
|
|
writeln!(out, " - GTK version :")?;
|
|
writeln!(out, " build : {}", version_na(info.gtk_build))?;
|
|
writeln!(out, " runtime : {}", version_na(info.gtk_runtime))?;
|
|
writeln!(out, " - libadwaita : enabled")?;
|
|
writeln!(out, " build : {}", version_na(info.adw_build))?;
|
|
writeln!(out, " runtime : {}", version_na(info.adw_runtime))?;
|
|
writeln!(
|
|
out,
|
|
" - libX11 : {}",
|
|
if info.x11 { "enabled" } else { "disabled" }
|
|
)?;
|
|
writeln!(
|
|
out,
|
|
" - libwayland : {}",
|
|
if info.wayland { "enabled" } else { "disabled" }
|
|
)?;
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
#![allow(clippy::unwrap_used)]
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn version_output_layout() {
|
|
let mut buf = Vec::new();
|
|
let info = BuildInfo {
|
|
version_string: "1.3.1".into(),
|
|
commit: None,
|
|
release_channel: "stable".into(),
|
|
..BuildInfo::default()
|
|
};
|
|
write_version(&mut buf, &info, false).unwrap();
|
|
let s = String::from_utf8(buf).unwrap();
|
|
assert!(s.starts_with(
|
|
"Ghostty 1.3.1\n\nVersion\n - version: 1.3.1\n - channel: stable\nBuild Config\n"
|
|
));
|
|
assert!(s.contains(" - libwayland : enabled\n"));
|
|
}
|
|
|
|
#[test]
|
|
fn version_tty_link() {
|
|
let info = BuildInfo {
|
|
commit: Some("abc".into()),
|
|
..BuildInfo::default()
|
|
};
|
|
let mut buf = Vec::new();
|
|
write_version(&mut buf, &info, true).unwrap();
|
|
let s = String::from_utf8(buf).unwrap();
|
|
assert!(
|
|
s.starts_with("\x1b]8;;https://github.com/ghostty-org/ghostty/commit/abc\x1b\\Ghostty")
|
|
);
|
|
}
|
|
}
|