Ports main_wasm.zig as crates/ghostty-wasm (cdylib exporting the Zig names: atlas_*, face_*, deferred_face_*, shaper_*, config_*), the web_canvas font face and shaper (backend selected on wasm32), os/wasm (logging, target, JS interop) and config/Wasm.zig. C-library dependencies (freetype, harfbuzz, fontconfig, onig, gettext, D-Bus, rustix) are target-gated. Like Zig's wasm build, link regex search (StringMap::search_iterator) is unavailable without Oniguruma; Collection/SharedGrid/harfbuzz are compiled out on wasm32. ghostty-os switches from forbid to deny unsafe_code for the JS import blocks. The JS import ABI is currently a documented handle-based interface with a reference host (js/ghostty_host.js); aligning it with zig-js's exact import names follows separately. Test Plan: - cargo build --target wasm32-unknown-unknown -p ghostty-font \ -p ghostty-config -p ghostty-terminal -p ghostty-vt -p ghostty-wasm - cargo test -p ghostty-wasm (node runs the module against a fake canvas)
69 lines
2.4 KiB
Rust
69 lines
2.4 KiB
Rust
//! `config/Wasm.zig`: the wasm-compatible config API.
|
|
|
|
use std::io::Cursor;
|
|
|
|
use ghostty_config::{
|
|
cli_args::{self, LineIterator},
|
|
config::Config,
|
|
file_formatter::FileFormatter,
|
|
};
|
|
|
|
use crate::{ensure_init, host_bytes};
|
|
|
|
/// Create a new configuration filled with the initial default values.
|
|
#[unsafe(no_mangle)]
|
|
pub extern "C" fn config_new() -> *mut Config {
|
|
ensure_init();
|
|
Box::into_raw(Box::new(Config::new_default()))
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub extern "C" fn config_free(ptr: *mut Config) {
|
|
if !ptr.is_null() {
|
|
// SAFETY: pointer came from `config_new` and is freed once.
|
|
drop(unsafe { Box::from_raw(ptr) });
|
|
}
|
|
}
|
|
|
|
/// Load the configuration from a string in the same format as the file-based
|
|
/// syntax for the desktop version of the terminal.
|
|
#[unsafe(no_mangle)]
|
|
pub extern "C" fn config_load_string(config: *mut Config, s: *const u8, len: usize) {
|
|
// SAFETY: live pointer from `config_new`; `s` is valid for `len` bytes.
|
|
let (config, s) = unsafe { (&mut *config, host_bytes(s, len)) };
|
|
let mut iter = LineIterator::new(Cursor::new(s));
|
|
if let Err(err) = cli_args::parse(config, &mut iter) {
|
|
log::error!("error loading config err={err}");
|
|
}
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub extern "C" fn config_finalize(config: *mut Config) {
|
|
// SAFETY: live pointer from `config_new`.
|
|
if let Err(err) = unsafe { &mut *config }.finalize() {
|
|
log::error!("error finalizing config err={err}");
|
|
}
|
|
}
|
|
|
|
/// Extra (not in Zig): writes the config in file format (like
|
|
/// `+show-config`, only changed values) to `out` (capacity `cap`) and returns
|
|
/// the full length; the output is truncated if it does not fit.
|
|
#[unsafe(no_mangle)]
|
|
pub extern "C" fn config_format(config: *const Config, out: *mut u8, cap: usize) -> usize {
|
|
// SAFETY: live pointer from `config_new`; `out` is valid for `cap` bytes.
|
|
let (config, out) = unsafe { (&*config, std::slice::from_raw_parts_mut(out, cap)) };
|
|
let mut fmt = FileFormatter::new(config);
|
|
fmt.changed = true;
|
|
let s = fmt.to_string();
|
|
let n = s.len().min(cap);
|
|
out[..n].copy_from_slice(&s.as_bytes()[..n]);
|
|
s.len()
|
|
}
|
|
|
|
/// Extra (not in Zig): the number of diagnostics (parse errors) recorded.
|
|
#[unsafe(no_mangle)]
|
|
pub extern "C" fn config_diagnostics_count(config: *const Config) -> usize {
|
|
// SAFETY: live pointer from `config_new`.
|
|
unsafe { &*config }.diagnostics.items().len()
|
|
}
|