mirror of
https://github.com/ghostty-org/ghostty.git
synced 2026-09-21 13:08:09 +00:00
libghostty: simplify Wasm allocation API
Replace a bunch of type-specific Wasm allocation functions with a generic byte allocator and reusable opaque out-parameters for pointers. This makes it a lot more ergonomic (relatively) to use the Wasm interface and removes a dozen or so exports. This also updates the `ghostty_type_json` `abi` field with a maximum alignment value that host sides can use to keep every allocation aligned properly, easily, without hardcoding numbers. This adds a test to verify this all works as intended and runs in CI.
This commit is contained in:
@@ -183,6 +183,15 @@
|
||||
return wasmMemory.buffer;
|
||||
}
|
||||
|
||||
function readUsize(ptr) {
|
||||
const view = new DataView(getBuffer());
|
||||
switch (typeLayout.abi.usize_size) {
|
||||
case 4: return view.getUint32(ptr, true);
|
||||
case 8: return Number(view.getBigUint64(ptr, true));
|
||||
default: throw new Error('unsupported size_t width');
|
||||
}
|
||||
}
|
||||
|
||||
// Parse escape sequences in the input string (e.g. \x1b, \r, \n)
|
||||
function parseEscapes(str) {
|
||||
return str
|
||||
@@ -204,6 +213,7 @@
|
||||
const cols = parseInt(document.getElementById('cols').value, 10);
|
||||
const rows = parseInt(document.getElementById('rows').value, 10);
|
||||
const vtText = parseEscapes(document.getElementById('vtInput').value);
|
||||
const usizeSize = typeLayout.abi.usize_size;
|
||||
|
||||
// Allocate pointer to receive the terminal handle
|
||||
const termPtrPtr = wasmInstance.exports.ghostty_wasm_alloc_opaque();
|
||||
@@ -219,19 +229,19 @@
|
||||
throw new Error(`ghostty_terminal_new failed with result ${newResult}`);
|
||||
}
|
||||
|
||||
const termPtr = new DataView(getBuffer()).getUint32(termPtrPtr, true);
|
||||
const termPtr = wasmInstance.exports.ghostty_wasm_take_opaque(termPtrPtr);
|
||||
wasmInstance.exports.ghostty_wasm_free_opaque(termPtrPtr);
|
||||
|
||||
// Write VT data to the terminal
|
||||
const vtBytes = new TextEncoder().encode(vtText);
|
||||
const dataPtr = wasmInstance.exports.ghostty_wasm_alloc_u8_array(vtBytes.length);
|
||||
const dataPtr = wasmInstance.exports.ghostty_wasm_alloc(vtBytes.length);
|
||||
new Uint8Array(getBuffer()).set(vtBytes, dataPtr);
|
||||
wasmInstance.exports.ghostty_terminal_vt_write(termPtr, dataPtr, vtBytes.length);
|
||||
wasmInstance.exports.ghostty_wasm_free_u8_array(dataPtr, vtBytes.length);
|
||||
wasmInstance.exports.ghostty_wasm_free(dataPtr, vtBytes.length);
|
||||
|
||||
// Create a plain-text formatter
|
||||
const FMT_OPTS_SIZE = typeLayout.types.GhosttyFormatterTerminalOptions.size;
|
||||
const fmtOptsPtr = wasmInstance.exports.ghostty_wasm_alloc_u8_array(FMT_OPTS_SIZE);
|
||||
const fmtOptsPtr = wasmInstance.exports.ghostty_wasm_alloc(FMT_OPTS_SIZE);
|
||||
new Uint8Array(getBuffer(), fmtOptsPtr, FMT_OPTS_SIZE).fill(0);
|
||||
const fmtOptsView = new DataView(getBuffer(), fmtOptsPtr, FMT_OPTS_SIZE);
|
||||
setField(fmtOptsView, 'GhosttyFormatterTerminalOptions', 'size', FMT_OPTS_SIZE);
|
||||
@@ -254,19 +264,19 @@
|
||||
const fmtResult = wasmInstance.exports.ghostty_formatter_terminal_new(
|
||||
0, fmtPtrPtr, termPtr, fmtOptsPtr
|
||||
);
|
||||
wasmInstance.exports.ghostty_wasm_free_u8_array(fmtOptsPtr, FMT_OPTS_SIZE);
|
||||
wasmInstance.exports.ghostty_wasm_free(fmtOptsPtr, FMT_OPTS_SIZE);
|
||||
|
||||
if (fmtResult !== GHOSTTY_SUCCESS) {
|
||||
wasmInstance.exports.ghostty_terminal_free(termPtr);
|
||||
throw new Error(`ghostty_formatter_terminal_new failed with result ${fmtResult}`);
|
||||
}
|
||||
|
||||
const fmtPtr = new DataView(getBuffer()).getUint32(fmtPtrPtr, true);
|
||||
const fmtPtr = wasmInstance.exports.ghostty_wasm_take_opaque(fmtPtrPtr);
|
||||
wasmInstance.exports.ghostty_wasm_free_opaque(fmtPtrPtr);
|
||||
|
||||
// Format with alloc
|
||||
const outPtrPtr = wasmInstance.exports.ghostty_wasm_alloc_opaque();
|
||||
const outLenPtr = wasmInstance.exports.ghostty_wasm_alloc_usize();
|
||||
const outLenPtr = wasmInstance.exports.ghostty_wasm_alloc(usizeSize);
|
||||
const formatResult = wasmInstance.exports.ghostty_formatter_format_alloc(
|
||||
fmtPtr, 0, outPtrPtr, outLenPtr
|
||||
);
|
||||
@@ -277,8 +287,8 @@
|
||||
throw new Error(`ghostty_formatter_format_alloc failed with result ${formatResult}`);
|
||||
}
|
||||
|
||||
const outPtr = new DataView(getBuffer()).getUint32(outPtrPtr, true);
|
||||
const outLen = new DataView(getBuffer()).getUint32(outLenPtr, true);
|
||||
const outPtr = wasmInstance.exports.ghostty_wasm_take_opaque(outPtrPtr);
|
||||
const outLen = readUsize(outLenPtr);
|
||||
|
||||
const outBytes = new Uint8Array(getBuffer(), outPtr, outLen);
|
||||
const outText = new TextDecoder().decode(outBytes);
|
||||
@@ -294,7 +304,7 @@
|
||||
// Clean up
|
||||
wasmInstance.exports.ghostty_free(0, outPtr, outLen);
|
||||
wasmInstance.exports.ghostty_wasm_free_opaque(outPtrPtr);
|
||||
wasmInstance.exports.ghostty_wasm_free_usize(outLenPtr);
|
||||
wasmInstance.exports.ghostty_wasm_free(outLenPtr, usizeSize);
|
||||
wasmInstance.exports.ghostty_formatter_free(fmtPtr);
|
||||
wasmInstance.exports.ghostty_terminal_free(termPtr);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user