diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 1638b0fd9..9893106dd 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -14,7 +14,6 @@ jobs:
- build-dist
- build-examples
- build-flatpak
- - build-freebsd
- build-libghostty-vt
- build-linux
- build-linux-libghostty
@@ -333,7 +332,7 @@ jobs:
run: nix build .#ghostty-releasefast
- name: Check version
- run: result/bin/ghostty +version | grep -q 'builtin.OptimizeMode.ReleaseFast'
+ run: result/bin/ghostty +version | grep -q '.ReleaseFast'
- name: Check to see if the binary has been stripped
run: nm result/bin/.ghostty-wrapped 2>&1 | grep -q 'no symbols'
@@ -342,7 +341,7 @@ jobs:
run: nix build .#ghostty-debug
- name: Check version
- run: result/bin/ghostty +version | grep -q 'builtin.OptimizeMode.Debug'
+ run: result/bin/ghostty +version | grep -q '.Debug'
- name: Check to see if the binary has not been stripped
run: nm result/bin/.ghostty-wrapped 2>&1 | grep -q 'main_ghostty.main'
@@ -513,7 +512,7 @@ jobs:
$fileContent = Get-Content -Path "build.zig" -Raw
$pattern = 'buildpkg\.requireZig\("(.*?)"\);'
$zigVersion = [regex]::Match($fileContent, $pattern).Groups[1].Value
- $version = "zig-windows-x86_64-$zigVersion"
+ $version = "zig-x86_64-windows-$zigVersion"
Write-Output $version
$uri = "https://ziglang.org/download/$zigVersion/$version.zip"
Invoke-WebRequest -Uri "$uri" -OutFile ".\zig-windows.zip"
@@ -1138,6 +1137,7 @@ jobs:
name: Build on FreeBSD
needs: test
runs-on: namespace-profile-mitchellh-sm-systemd
+ if: false # FIXME: FreeBSD does not yet ship with Zig 0.15
strategy:
matrix:
release:
diff --git a/build.zig b/build.zig
index 62fa77511..7b66af81a 100644
--- a/build.zig
+++ b/build.zig
@@ -4,7 +4,7 @@ const builtin = @import("builtin");
const buildpkg = @import("src/build/main.zig");
comptime {
- buildpkg.requireZig("0.14.0");
+ buildpkg.requireZig("0.15.1");
}
pub fn build(b: *std.Build) !void {
@@ -249,8 +249,6 @@ pub fn build(b: *std.Build) !void {
{
const mod_vt_test = b.addTest(.{
.root_module = mod.vt,
- .target = config.target,
- .optimize = config.optimize,
.filters = test_filters,
});
const mod_vt_test_run = b.addRunArtifact(mod_vt_test);
@@ -258,8 +256,6 @@ pub fn build(b: *std.Build) !void {
const mod_vt_c_test = b.addTest(.{
.root_module = mod.vt_c,
- .target = config.target,
- .optimize = config.optimize,
.filters = test_filters,
});
const mod_vt_c_test_run = b.addRunArtifact(mod_vt_c_test);
@@ -280,6 +276,8 @@ pub fn build(b: *std.Build) !void {
.omit_frame_pointer = false,
.unwind_tables = .sync,
}),
+ // Crash on x86_64 without this
+ .use_llvm = true,
});
if (config.emit_test_exe) b.installArtifact(test_exe);
_ = try deps.add(test_exe);
@@ -289,7 +287,7 @@ pub fn build(b: *std.Build) !void {
test_step.dependOn(&test_run.step);
// Normal tests always test our libghostty modules
- test_step.dependOn(test_lib_vt_step);
+ //test_step.dependOn(test_lib_vt_step);
// Valgrind test running
const valgrind_run = b.addSystemCommand(&.{
diff --git a/build.zig.zon b/build.zig.zon
index 992284bf7..a1885f7f7 100644
--- a/build.zig.zon
+++ b/build.zig.zon
@@ -3,54 +3,55 @@
.version = "1.2.1",
.paths = .{""},
.fingerprint = 0x64407a2a0b4147e5,
- .minimum_zig_version = "0.14.1",
+ .minimum_zig_version = "0.15.1",
.dependencies = .{
// Zig libs
.libxev = .{
// mitchellh/libxev
- .url = "https://github.com/mitchellh/libxev/archive/7f803181b158a10fec8619f793e3b4df515566cb.tar.gz",
- .hash = "libxev-0.0.0-86vtc2UaEwDfiTKX3iBI-s_hdzfzWQUarT3MUrmUQl-Q",
+ .url = "https://github.com/mitchellh/libxev/archive/34fa50878aec6e5fa8f532867001ab3c36fae23e.tar.gz",
+ .hash = "libxev-0.0.0-86vtc4IcEwCqEYxEYoN_3KXmc6A9VLcm22aVImfvecYs",
.lazy = true,
},
.vaxis = .{
// rockorager/libvaxis
- .url = "git+https://github.com/rockorager/libvaxis#1f41c121e8fc153d9ce8c6eb64b2bbab68ad7d23",
- .hash = "vaxis-0.1.0-BWNV_FUICQAFZnTCL11TUvnUr1Y0_ZdqtXHhd51d76Rn",
+ .url = "https://github.com/rockorager/libvaxis/archive/9fc9015d5f147568e18c5e7ca28f15bf8b293760.tar.gz",
+ .hash = "vaxis-0.5.1-BWNV_O8fCQAeUeVrESVc-2BdXloEXkFqReDJL7Q6XTSZ",
.lazy = true,
},
.z2d = .{
// vancluever/z2d
- .url = "https://github.com/vancluever/z2d/archive/refs/tags/v0.8.1.tar.gz",
- .hash = "z2d-0.8.1-j5P_Hq8vDwB8ZaDA54-SzESDLF2zznG_zvTHiQNJImZP",
+ .url = "https://github.com/vancluever/z2d/archive/a1237f6881d99b75abd8a20a934e62e34b44a005.tar.gz",
+ .hash = "z2d-0.8.2-pre-j5P_HlVRFgCsBTQ3EgUoKbYHx5JMnyH1mHsOSPiafnef",
.lazy = true,
},
.zig_objc = .{
// mitchellh/zig-objc
- .url = "https://github.com/mitchellh/zig-objc/archive/c9e917a4e15a983b672ca779c7985d738a2d517c.tar.gz",
- .hash = "zig_objc-0.0.0-Ir_SpwsPAQBJgi9YRm2ubJMfdoysSq5gKpsIj3izQ8Zk",
+ .url = "https://github.com/mitchellh/zig-objc/archive/f356ed02833f0f1b8e84d50bed9e807bf7cdc0ae.tar.gz",
+ .hash = "zig_objc-0.0.0-Ir_Sp5gTAQCvxxR7oVIrPXxXwsfKgVP7_wqoOQrZjFeK",
.lazy = true,
},
.zig_js = .{
// mitchellh/zig-js
- .url = "https://deps.files.ghostty.org/zig_js-12205a66d423259567764fa0fc60c82be35365c21aeb76c5a7dc99698401f4f6fefc.tar.gz",
- .hash = "N-V-__8AAB9YCQBaZtQjJZVndk-g_GDIK-NTZcIa63bFp9yZ",
+ .url = "https://github.com/mitchellh/zig-js/archive/04db83c617da1956ac5adc1cb9ba1e434c1cb6fd.tar.gz",
+ .hash = "zig_js-0.0.0-rjCAV-6GAADxFug7rDmPH-uM_XcnJ5NmuAMJCAscMjhi",
.lazy = true,
},
.uucode = .{
- .url = "https://github.com/jacobsandlund/uucode/archive/190706c6b56f0842d29778007f74f7d3d1335fc5.tar.gz",
- .hash = "uucode-0.1.0-ZZjBPpAFQABNCvd9cVPBg4I7233Ays-NWfWphPNqGbyE",
+ // TODO: currently the use-llvm branch because its broken on self-hosted
+ .url = "https://github.com/jacobsandlund/uucode/archive/f81f8ef8518b8ec5a7fca30ec5fdbc76cc6197df.tar.gz",
+ .hash = "uucode-0.1.0-ZZjBPjQHQADuCy1VMWftjrMl3iWqgMpUugWVQJG6_7xT",
},
.zig_wayland = .{
// codeberg ifreund/zig-wayland
- .url = "https://codeberg.org/ifreund/zig-wayland/archive/f3c5d503e540ada8cbcb056420de240af0c094f7.tar.gz",
- .hash = "wayland-0.4.0-dev-lQa1kjfIAQCmhhQu3xF0KH-94-TzeMXOqfnP0-Dg6Wyy",
+ .url = "https://codeberg.org/ifreund/zig-wayland/archive/1b5c038ec10da20ed3a15b0b2a6db1c21383e8ea.tar.gz",
+ .hash = "wayland-0.5.0-dev-lQa1khrMAQDJDwYFKpdH3HizherB7sHo5dKMECfvxQHe",
.lazy = true,
},
.zf = .{
// natecraddock/zf
- .url = "https://github.com/natecraddock/zf/archive/7aacbe6d155d64d15937ca95ca6c014905eb531f.tar.gz",
- .hash = "zf-0.10.3-OIRy8aiIAACLrBllz0zjxaH0aOe5oNm3KtEMyCntST-9",
+ .url = "https://github.com/jcollie/zf/archive/52ad2e5528ab754f77437edf08a07b5ec843661c.tar.gz",
+ .hash = "zf-0.10.3-OIRy8QGJAACJcu3tCGtfbJnnd3Y4QL7OW_X8PJ8u_ASR",
.lazy = true,
},
.gobject = .{
diff --git a/build.zig.zon.json b/build.zig.zon.json
index 83625f765..445f39827 100644
--- a/build.zig.zon.json
+++ b/build.zig.zon.json
@@ -64,10 +64,10 @@
"url": "https://deps.files.ghostty.org/libpng-1220aa013f0c83da3fb64ea6d327f9173fa008d10e28bc9349eac3463457723b1c66.tar.gz",
"hash": "sha256-/syVtGzwXo4/yKQUdQ4LparQDYnp/fF16U/wQcrxoDo="
},
- "libxev-0.0.0-86vtc2UaEwDfiTKX3iBI-s_hdzfzWQUarT3MUrmUQl-Q": {
+ "libxev-0.0.0-86vtc4IcEwCqEYxEYoN_3KXmc6A9VLcm22aVImfvecYs": {
"name": "libxev",
- "url": "https://github.com/mitchellh/libxev/archive/7f803181b158a10fec8619f793e3b4df515566cb.tar.gz",
- "hash": "sha256-KaozYKEhhT/6sInef7/8O/60LDBJN+8QmdLuNY1Gkmc="
+ "url": "https://github.com/mitchellh/libxev/archive/34fa50878aec6e5fa8f532867001ab3c36fae23e.tar.gz",
+ "hash": "sha256-YAPqa5bkpRihKPkyMn15oRvTCZaxO3O66ymRY3lIfdc="
},
"N-V-__8AAG3RoQEyRC2Vw7Qoro5SYBf62IHn3HjqtNVY6aWK": {
"name": "libxml2",
@@ -109,15 +109,20 @@
"url": "https://deps.files.ghostty.org/utfcpp-1220d4d18426ca72fc2b7e56ce47273149815501d0d2395c2a98c726b31ba931e641.tar.gz",
"hash": "sha256-/8ZooxDndgfTk/PBizJxXyI9oerExNbgV5oR345rWc8="
},
- "uucode-0.1.0-ZZjBPpAFQABNCvd9cVPBg4I7233Ays-NWfWphPNqGbyE": {
+ "uucode-0.1.0-ZZjBPjQHQADuCy1VMWftjrMl3iWqgMpUugWVQJG6_7xT": {
"name": "uucode",
- "url": "https://github.com/jacobsandlund/uucode/archive/190706c6b56f0842d29778007f74f7d3d1335fc5.tar.gz",
- "hash": "sha256-iq9Oyns5e5Tnz2BKPPPTuyJ03BN4bK0dsmSPE1s0wig="
+ "url": "https://github.com/jacobsandlund/uucode/archive/f81f8ef8518b8ec5a7fca30ec5fdbc76cc6197df.tar.gz",
+ "hash": "sha256-VomSYOF8fRJwb/8GtVG/QqR6c95zSkQt4649C/4KXAc="
},
- "vaxis-0.1.0-BWNV_FUICQAFZnTCL11TUvnUr1Y0_ZdqtXHhd51d76Rn": {
+ "vaxis-0.5.1-BWNV_H0PCQAeMusmtLzh9P9xO2IW242GZ2IRe9iKYhcA": {
"name": "vaxis",
- "url": "git+https://github.com/rockorager/libvaxis#1f41c121e8fc153d9ce8c6eb64b2bbab68ad7d23",
- "hash": "sha256-bNZ3oveT6vPChjimPJ/GGfcdivlAeJdl/xfWM+S/MHY="
+ "url": "https://github.com/rockorager/libvaxis/archive/1bf887aa7e3736bad69fd4e277a378946edb0f2a.tar.gz",
+ "hash": "sha256-eq5YC26OY0i2cdQJ0ZXMZ+o2vHQLEFNNGzQt5Zuz4BM="
+ },
+ "vaxis-0.5.1-BWNV_O8fCQAeUeVrESVc-2BdXloEXkFqReDJL7Q6XTSZ": {
+ "name": "vaxis",
+ "url": "https://github.com/rockorager/libvaxis/archive/9fc9015d5f147568e18c5e7ca28f15bf8b293760.tar.gz",
+ "hash": "sha256-7H5a0J7uUsrzlO7JNAf/Ussi9WxvmsbyJSmhqvl+rqI="
},
"N-V-__8AAKrHGAAs2shYq8UkE6bGcR1QJtLTyOE_lcosMn6t": {
"name": "wayland",
@@ -134,40 +139,50 @@
"url": "https://deps.files.ghostty.org/wuffs-122037b39d577ec2db3fd7b2130e7b69ef6cc1807d68607a7c232c958315d381b5cd.tar.gz",
"hash": "sha256-nkzSCr6W5sTG7enDBXEIhgEm574uLD41UVR2wlC+HBM="
},
- "z2d-0.8.1-j5P_Hq8vDwB8ZaDA54-SzESDLF2zznG_zvTHiQNJImZP": {
+ "z2d-0.8.2-pre-j5P_HlVRFgCsBTQ3EgUoKbYHx5JMnyH1mHsOSPiafnef": {
"name": "z2d",
- "url": "https://github.com/vancluever/z2d/archive/refs/tags/v0.8.1.tar.gz",
- "hash": "sha256-0DbDKSYA1ejhVx/WbOkwTgD57PNRFcnRviqBh8xpPZ0="
+ "url": "https://github.com/vancluever/z2d/archive/a1237f6881d99b75abd8a20a934e62e34b44a005.tar.gz",
+ "hash": "sha256-5/qRZAIh1U42v7jql9W0jr2zzQZtu39DxJPLVrSybJg="
},
- "zf-0.10.3-OIRy8aiIAACLrBllz0zjxaH0aOe5oNm3KtEMyCntST-9": {
+ "zf-0.10.3-OIRy8QGJAACJcu3tCGtfbJnnd3Y4QL7OW_X8PJ8u_ASR": {
"name": "zf",
- "url": "https://github.com/natecraddock/zf/archive/7aacbe6d155d64d15937ca95ca6c014905eb531f.tar.gz",
- "hash": "sha256-3nulNQd/4rZ4paeXJYXwAliNNyRNsIOX/q3z1JB8C7I="
+ "url": "https://github.com/jcollie/zf/archive/52ad2e5528ab754f77437edf08a07b5ec843661c.tar.gz",
+ "hash": "sha256-8BinbanSfZeBA8SBAopVxwJObN36/BTpxVHABKicsMQ="
},
- "zg-0.13.4-AAAAAGiZ7QLz4pvECFa_wG4O4TP4FLABHHbemH2KakWM": {
+ "zg-0.14.1-oGqU3J4_tAKBfyes3AWleKDjo-IcYvnEwaB8qxOqFMwM": {
"name": "zg",
- "url": "git+https://codeberg.org/atman/zg#4a002763419a34d61dcbb1f415821b83b9bf8ddc",
- "hash": "sha256-fo3l6cjkrr/godElTGnQzalBsasN7J73IDIRmw7v1gA="
+ "url": "git+https://codeberg.org/ivanstepanovftw/zg#4fe689e56ce2ed5a8f59308b471bccd7da89fac9",
+ "hash": "sha256-P0ieLuOQ05wKVaMmeNKJIxCWMIdyeKkmhsj8Ps80BGU="
},
- "N-V-__8AAB9YCQBaZtQjJZVndk-g_GDIK-NTZcIa63bFp9yZ": {
+ "zg-0.15.1-oGqU3M0-tALZCy7boQS86znlBloyKx6--JriGlY0Paa9": {
+ "name": "zg",
+ "url": "https://codeberg.org/chaten/zg/archive/749197a3f9d25e211615960c02380a3d659b20f9.tar.gz",
+ "hash": "sha256-BZhz1nPqxK6hdsJQ66n7Jk4zMgFSGLXm8eU0CX/7mDI="
+ },
+ "zig_js-0.0.0-rjCAV-6GAADxFug7rDmPH-uM_XcnJ5NmuAMJCAscMjhi": {
"name": "zig_js",
- "url": "https://deps.files.ghostty.org/zig_js-12205a66d423259567764fa0fc60c82be35365c21aeb76c5a7dc99698401f4f6fefc.tar.gz",
- "hash": "sha256-fyNeCVbC9UAaKJY6JhAZlT0A479M/AKYMPIWEZbDWD0="
+ "url": "https://github.com/mitchellh/zig-js/archive/04db83c617da1956ac5adc1cb9ba1e434c1cb6fd.tar.gz",
+ "hash": "sha256-TCAY5WAV05UEuAkDhq2c6Tk/ODgAhdnDI3O/flb8c6M="
},
- "zig_objc-0.0.0-Ir_SpwsPAQBJgi9YRm2ubJMfdoysSq5gKpsIj3izQ8Zk": {
+ "zig_objc-0.0.0-Ir_Sp5gTAQCvxxR7oVIrPXxXwsfKgVP7_wqoOQrZjFeK": {
"name": "zig_objc",
- "url": "https://github.com/mitchellh/zig-objc/archive/c9e917a4e15a983b672ca779c7985d738a2d517c.tar.gz",
- "hash": "sha256-o3vl7qfkSi0bKXa6JWuF92qMEGP8Af/shcip5nRo5Nw="
+ "url": "https://github.com/mitchellh/zig-objc/archive/f356ed02833f0f1b8e84d50bed9e807bf7cdc0ae.tar.gz",
+ "hash": "sha256-3YSvc3YlNW/NciyzCQnzsujXAmZ89XlxSqfqvArAjsw="
},
- "wayland-0.4.0-dev-lQa1kjfIAQCmhhQu3xF0KH-94-TzeMXOqfnP0-Dg6Wyy": {
+ "wayland-0.5.0-dev-lQa1khrMAQDJDwYFKpdH3HizherB7sHo5dKMECfvxQHe": {
"name": "zig_wayland",
- "url": "https://codeberg.org/ifreund/zig-wayland/archive/f3c5d503e540ada8cbcb056420de240af0c094f7.tar.gz",
- "hash": "sha256-E77GZ15APYbbO1WzmuJi8eG9/iQFbc2CgkNBxjCLUhk="
+ "url": "https://codeberg.org/ifreund/zig-wayland/archive/1b5c038ec10da20ed3a15b0b2a6db1c21383e8ea.tar.gz",
+ "hash": "sha256-TxRrc17Q1Sf1IOO/cdPpP3LD0PpYOujt06SFH3B5Ek4="
},
- "zigimg-0.1.0-lly-O6N2EABOxke8dqyzCwhtUCAafqP35zC7wsZ4Ddxj": {
+ "zigimg-0.1.0-8_eo2mWmEgBoqdr0sH9O5GTqDHthkoEPM5_tipcBRreL": {
"name": "zigimg",
- "url": "git+https://github.com/TUSF/zigimg#31268548fe3276c0e95f318a6c0d2ab10565b58d",
- "hash": "sha256-oblfr2FIzuqq0FLo/RrzCwUX1NJJuT53EwD3nP3KwN0="
+ "url": "git+https://github.com/ivanstepanovftw/zigimg#aa4c31db872612c39edbb79f753b3cd9a79fe726",
+ "hash": "sha256-Ko5RuxxTAvpUHCnWEdHqNl7b+PVUAxg1/OPmzGGjdt0="
+ },
+ "zigimg-0.1.0-8_eo2vHnEwCIVW34Q14Ec-xUlzIoVg86-7FU2ypPtxms": {
+ "name": "zigimg",
+ "url": "https://github.com/ivanstepanovftw/zigimg/archive/d7b7ab0ba0899643831ef042bd73289510b39906.tar.gz",
+ "hash": "sha256-LB7Xa6KzVRRUSwwnyWM+y6fDG+kIDjfnoBDJO1obxVM="
},
"N-V-__8AAB0eQwD-0MdOEBmz7intriBReIsIDNlukNVoNu6o": {
"name": "zlib",
diff --git a/build.zig.zon.nix b/build.zig.zon.nix
index abd5a37c5..0111f0769 100644
--- a/build.zig.zon.nix
+++ b/build.zig.zon.nix
@@ -187,11 +187,11 @@ in
};
}
{
- name = "libxev-0.0.0-86vtc2UaEwDfiTKX3iBI-s_hdzfzWQUarT3MUrmUQl-Q";
+ name = "libxev-0.0.0-86vtc4IcEwCqEYxEYoN_3KXmc6A9VLcm22aVImfvecYs";
path = fetchZigArtifact {
name = "libxev";
- url = "https://github.com/mitchellh/libxev/archive/7f803181b158a10fec8619f793e3b4df515566cb.tar.gz";
- hash = "sha256-KaozYKEhhT/6sInef7/8O/60LDBJN+8QmdLuNY1Gkmc=";
+ url = "https://github.com/mitchellh/libxev/archive/34fa50878aec6e5fa8f532867001ab3c36fae23e.tar.gz";
+ hash = "sha256-YAPqa5bkpRihKPkyMn15oRvTCZaxO3O66ymRY3lIfdc=";
};
}
{
@@ -259,19 +259,27 @@ in
};
}
{
- name = "uucode-0.1.0-ZZjBPpAFQABNCvd9cVPBg4I7233Ays-NWfWphPNqGbyE";
+ name = "uucode-0.1.0-ZZjBPjQHQADuCy1VMWftjrMl3iWqgMpUugWVQJG6_7xT";
path = fetchZigArtifact {
name = "uucode";
- url = "https://github.com/jacobsandlund/uucode/archive/190706c6b56f0842d29778007f74f7d3d1335fc5.tar.gz";
- hash = "sha256-iq9Oyns5e5Tnz2BKPPPTuyJ03BN4bK0dsmSPE1s0wig=";
+ url = "https://github.com/jacobsandlund/uucode/archive/f81f8ef8518b8ec5a7fca30ec5fdbc76cc6197df.tar.gz";
+ hash = "sha256-VomSYOF8fRJwb/8GtVG/QqR6c95zSkQt4649C/4KXAc=";
};
}
{
- name = "vaxis-0.1.0-BWNV_FUICQAFZnTCL11TUvnUr1Y0_ZdqtXHhd51d76Rn";
+ name = "vaxis-0.5.1-BWNV_H0PCQAeMusmtLzh9P9xO2IW242GZ2IRe9iKYhcA";
path = fetchZigArtifact {
name = "vaxis";
- url = "git+https://github.com/rockorager/libvaxis#1f41c121e8fc153d9ce8c6eb64b2bbab68ad7d23";
- hash = "sha256-bNZ3oveT6vPChjimPJ/GGfcdivlAeJdl/xfWM+S/MHY=";
+ url = "https://github.com/rockorager/libvaxis/archive/1bf887aa7e3736bad69fd4e277a378946edb0f2a.tar.gz";
+ hash = "sha256-eq5YC26OY0i2cdQJ0ZXMZ+o2vHQLEFNNGzQt5Zuz4BM=";
+ };
+ }
+ {
+ name = "vaxis-0.5.1-BWNV_O8fCQAeUeVrESVc-2BdXloEXkFqReDJL7Q6XTSZ";
+ path = fetchZigArtifact {
+ name = "vaxis";
+ url = "https://github.com/rockorager/libvaxis/archive/9fc9015d5f147568e18c5e7ca28f15bf8b293760.tar.gz";
+ hash = "sha256-7H5a0J7uUsrzlO7JNAf/Ussi9WxvmsbyJSmhqvl+rqI=";
};
}
{
@@ -299,59 +307,75 @@ in
};
}
{
- name = "z2d-0.8.1-j5P_Hq8vDwB8ZaDA54-SzESDLF2zznG_zvTHiQNJImZP";
+ name = "z2d-0.8.2-pre-j5P_HlVRFgCsBTQ3EgUoKbYHx5JMnyH1mHsOSPiafnef";
path = fetchZigArtifact {
name = "z2d";
- url = "https://github.com/vancluever/z2d/archive/refs/tags/v0.8.1.tar.gz";
- hash = "sha256-0DbDKSYA1ejhVx/WbOkwTgD57PNRFcnRviqBh8xpPZ0=";
+ url = "https://github.com/vancluever/z2d/archive/a1237f6881d99b75abd8a20a934e62e34b44a005.tar.gz";
+ hash = "sha256-5/qRZAIh1U42v7jql9W0jr2zzQZtu39DxJPLVrSybJg=";
};
}
{
- name = "zf-0.10.3-OIRy8aiIAACLrBllz0zjxaH0aOe5oNm3KtEMyCntST-9";
+ name = "zf-0.10.3-OIRy8QGJAACJcu3tCGtfbJnnd3Y4QL7OW_X8PJ8u_ASR";
path = fetchZigArtifact {
name = "zf";
- url = "https://github.com/natecraddock/zf/archive/7aacbe6d155d64d15937ca95ca6c014905eb531f.tar.gz";
- hash = "sha256-3nulNQd/4rZ4paeXJYXwAliNNyRNsIOX/q3z1JB8C7I=";
+ url = "https://github.com/jcollie/zf/archive/52ad2e5528ab754f77437edf08a07b5ec843661c.tar.gz";
+ hash = "sha256-8BinbanSfZeBA8SBAopVxwJObN36/BTpxVHABKicsMQ=";
};
}
{
- name = "zg-0.13.4-AAAAAGiZ7QLz4pvECFa_wG4O4TP4FLABHHbemH2KakWM";
+ name = "zg-0.14.1-oGqU3J4_tAKBfyes3AWleKDjo-IcYvnEwaB8qxOqFMwM";
path = fetchZigArtifact {
name = "zg";
- url = "git+https://codeberg.org/atman/zg#4a002763419a34d61dcbb1f415821b83b9bf8ddc";
- hash = "sha256-fo3l6cjkrr/godElTGnQzalBsasN7J73IDIRmw7v1gA=";
+ url = "git+https://codeberg.org/ivanstepanovftw/zg#4fe689e56ce2ed5a8f59308b471bccd7da89fac9";
+ hash = "sha256-P0ieLuOQ05wKVaMmeNKJIxCWMIdyeKkmhsj8Ps80BGU=";
};
}
{
- name = "N-V-__8AAB9YCQBaZtQjJZVndk-g_GDIK-NTZcIa63bFp9yZ";
+ name = "zg-0.15.1-oGqU3M0-tALZCy7boQS86znlBloyKx6--JriGlY0Paa9";
+ path = fetchZigArtifact {
+ name = "zg";
+ url = "https://codeberg.org/chaten/zg/archive/749197a3f9d25e211615960c02380a3d659b20f9.tar.gz";
+ hash = "sha256-BZhz1nPqxK6hdsJQ66n7Jk4zMgFSGLXm8eU0CX/7mDI=";
+ };
+ }
+ {
+ name = "zig_js-0.0.0-rjCAV-6GAADxFug7rDmPH-uM_XcnJ5NmuAMJCAscMjhi";
path = fetchZigArtifact {
name = "zig_js";
- url = "https://deps.files.ghostty.org/zig_js-12205a66d423259567764fa0fc60c82be35365c21aeb76c5a7dc99698401f4f6fefc.tar.gz";
- hash = "sha256-fyNeCVbC9UAaKJY6JhAZlT0A479M/AKYMPIWEZbDWD0=";
+ url = "https://github.com/mitchellh/zig-js/archive/04db83c617da1956ac5adc1cb9ba1e434c1cb6fd.tar.gz";
+ hash = "sha256-TCAY5WAV05UEuAkDhq2c6Tk/ODgAhdnDI3O/flb8c6M=";
};
}
{
- name = "zig_objc-0.0.0-Ir_SpwsPAQBJgi9YRm2ubJMfdoysSq5gKpsIj3izQ8Zk";
+ name = "zig_objc-0.0.0-Ir_Sp5gTAQCvxxR7oVIrPXxXwsfKgVP7_wqoOQrZjFeK";
path = fetchZigArtifact {
name = "zig_objc";
- url = "https://github.com/mitchellh/zig-objc/archive/c9e917a4e15a983b672ca779c7985d738a2d517c.tar.gz";
- hash = "sha256-o3vl7qfkSi0bKXa6JWuF92qMEGP8Af/shcip5nRo5Nw=";
+ url = "https://github.com/mitchellh/zig-objc/archive/f356ed02833f0f1b8e84d50bed9e807bf7cdc0ae.tar.gz";
+ hash = "sha256-3YSvc3YlNW/NciyzCQnzsujXAmZ89XlxSqfqvArAjsw=";
};
}
{
- name = "wayland-0.4.0-dev-lQa1kjfIAQCmhhQu3xF0KH-94-TzeMXOqfnP0-Dg6Wyy";
+ name = "wayland-0.5.0-dev-lQa1khrMAQDJDwYFKpdH3HizherB7sHo5dKMECfvxQHe";
path = fetchZigArtifact {
name = "zig_wayland";
- url = "https://codeberg.org/ifreund/zig-wayland/archive/f3c5d503e540ada8cbcb056420de240af0c094f7.tar.gz";
- hash = "sha256-E77GZ15APYbbO1WzmuJi8eG9/iQFbc2CgkNBxjCLUhk=";
+ url = "https://codeberg.org/ifreund/zig-wayland/archive/1b5c038ec10da20ed3a15b0b2a6db1c21383e8ea.tar.gz";
+ hash = "sha256-TxRrc17Q1Sf1IOO/cdPpP3LD0PpYOujt06SFH3B5Ek4=";
};
}
{
- name = "zigimg-0.1.0-lly-O6N2EABOxke8dqyzCwhtUCAafqP35zC7wsZ4Ddxj";
+ name = "zigimg-0.1.0-8_eo2mWmEgBoqdr0sH9O5GTqDHthkoEPM5_tipcBRreL";
path = fetchZigArtifact {
name = "zigimg";
- url = "git+https://github.com/TUSF/zigimg#31268548fe3276c0e95f318a6c0d2ab10565b58d";
- hash = "sha256-oblfr2FIzuqq0FLo/RrzCwUX1NJJuT53EwD3nP3KwN0=";
+ url = "git+https://github.com/ivanstepanovftw/zigimg#aa4c31db872612c39edbb79f753b3cd9a79fe726";
+ hash = "sha256-Ko5RuxxTAvpUHCnWEdHqNl7b+PVUAxg1/OPmzGGjdt0=";
+ };
+ }
+ {
+ name = "zigimg-0.1.0-8_eo2vHnEwCIVW34Q14Ec-xUlzIoVg86-7FU2ypPtxms";
+ path = fetchZigArtifact {
+ name = "zigimg";
+ url = "https://github.com/ivanstepanovftw/zigimg/archive/d7b7ab0ba0899643831ef042bd73289510b39906.tar.gz";
+ hash = "sha256-LB7Xa6KzVRRUSwwnyWM+y6fDG+kIDjfnoBDJO1obxVM=";
};
}
{
diff --git a/build.zig.zon.txt b/build.zig.zon.txt
index 453a12347..7dda3d294 100644
--- a/build.zig.zon.txt
+++ b/build.zig.zon.txt
@@ -1,7 +1,7 @@
-git+https://codeberg.org/atman/zg#4a002763419a34d61dcbb1f415821b83b9bf8ddc
-git+https://github.com/TUSF/zigimg#31268548fe3276c0e95f318a6c0d2ab10565b58d
-git+https://github.com/rockorager/libvaxis#1f41c121e8fc153d9ce8c6eb64b2bbab68ad7d23
-https://codeberg.org/ifreund/zig-wayland/archive/f3c5d503e540ada8cbcb056420de240af0c094f7.tar.gz
+git+https://codeberg.org/ivanstepanovftw/zg#4fe689e56ce2ed5a8f59308b471bccd7da89fac9
+git+https://github.com/ivanstepanovftw/zigimg#aa4c31db872612c39edbb79f753b3cd9a79fe726
+https://codeberg.org/chaten/zg/archive/749197a3f9d25e211615960c02380a3d659b20f9.tar.gz
+https://codeberg.org/ifreund/zig-wayland/archive/1b5c038ec10da20ed3a15b0b2a6db1c21383e8ea.tar.gz
https://deps.files.ghostty.org/JetBrainsMono-2.304.tar.gz
https://deps.files.ghostty.org/NerdFontsSymbolsOnly-3.4.0.tar.gz
https://deps.files.ghostty.org/breakpad-b99f444ba5f6b98cac261cbb391d8766b34a5918.tar.gz
@@ -24,12 +24,15 @@ https://deps.files.ghostty.org/utfcpp-1220d4d18426ca72fc2b7e56ce47273149815501d0
https://deps.files.ghostty.org/wayland-9cb3d7aa9dc995ffafdbdef7ab86a949d0fb0e7d.tar.gz
https://deps.files.ghostty.org/wayland-protocols-258d8f88f2c8c25a830c6316f87d23ce1a0f12d9.tar.gz
https://deps.files.ghostty.org/wuffs-122037b39d577ec2db3fd7b2130e7b69ef6cc1807d68607a7c232c958315d381b5cd.tar.gz
-https://deps.files.ghostty.org/zig_js-12205a66d423259567764fa0fc60c82be35365c21aeb76c5a7dc99698401f4f6fefc.tar.gz
https://deps.files.ghostty.org/zlib-1220fed0c74e1019b3ee29edae2051788b080cd96e90d56836eea857b0b966742efb.tar.gz
https://github.com/ghostty-org/zig-gobject/releases/download/2025-09-20-20-1/ghostty-gobject-2025-09-20-20-1.tar.zst
-https://github.com/jacobsandlund/uucode/archive/190706c6b56f0842d29778007f74f7d3d1335fc5.tar.gz
+https://github.com/ivanstepanovftw/zigimg/archive/d7b7ab0ba0899643831ef042bd73289510b39906.tar.gz
+https://github.com/jacobsandlund/uucode/archive/f81f8ef8518b8ec5a7fca30ec5fdbc76cc6197df.tar.gz
+https://github.com/jcollie/zf/archive/52ad2e5528ab754f77437edf08a07b5ec843661c.tar.gz
https://github.com/mbadolato/iTerm2-Color-Schemes/releases/download/release-20250922-150534-d28055b/ghostty-themes.tgz
-https://github.com/mitchellh/libxev/archive/7f803181b158a10fec8619f793e3b4df515566cb.tar.gz
-https://github.com/mitchellh/zig-objc/archive/c9e917a4e15a983b672ca779c7985d738a2d517c.tar.gz
-https://github.com/natecraddock/zf/archive/7aacbe6d155d64d15937ca95ca6c014905eb531f.tar.gz
-https://github.com/vancluever/z2d/archive/refs/tags/v0.8.1.tar.gz
+https://github.com/mitchellh/libxev/archive/34fa50878aec6e5fa8f532867001ab3c36fae23e.tar.gz
+https://github.com/mitchellh/zig-js/archive/04db83c617da1956ac5adc1cb9ba1e434c1cb6fd.tar.gz
+https://github.com/mitchellh/zig-objc/archive/f356ed02833f0f1b8e84d50bed9e807bf7cdc0ae.tar.gz
+https://github.com/rockorager/libvaxis/archive/1bf887aa7e3736bad69fd4e277a378946edb0f2a.tar.gz
+https://github.com/rockorager/libvaxis/archive/9fc9015d5f147568e18c5e7ca28f15bf8b293760.tar.gz
+https://github.com/vancluever/z2d/archive/a1237f6881d99b75abd8a20a934e62e34b44a005.tar.gz
diff --git a/example/c-vt/build.zig.zon b/example/c-vt/build.zig.zon
index 3230f440e..5da1a9168 100644
--- a/example/c-vt/build.zig.zon
+++ b/example/c-vt/build.zig.zon
@@ -2,7 +2,7 @@
.name = .c_vt,
.version = "0.0.0",
.fingerprint = 0x413a8529b1255f9a,
- .minimum_zig_version = "0.14.1",
+ .minimum_zig_version = "0.15.1",
.dependencies = .{
// Ghostty dependency. In reality, you'd probably use a URL-based
// dependency like the one showed (and commented out) below this one.
diff --git a/example/zig-vt/build.zig.zon b/example/zig-vt/build.zig.zon
index 852e736ca..bc7246de5 100644
--- a/example/zig-vt/build.zig.zon
+++ b/example/zig-vt/build.zig.zon
@@ -2,7 +2,7 @@
.name = .zig_vt,
.version = "0.0.0",
.fingerprint = 0x6045575a7a8387e6,
- .minimum_zig_version = "0.14.1",
+ .minimum_zig_version = "0.15.1",
.dependencies = .{
// Ghostty dependency. In reality, you'd probably use a URL-based
// dependency like the one showed (and commented out) below this one.
diff --git a/flake.lock b/flake.lock
index bbd4567e3..349248668 100644
--- a/flake.lock
+++ b/flake.lock
@@ -36,15 +36,15 @@
},
"nixpkgs": {
"locked": {
- "lastModified": 1748189127,
- "narHash": "sha256-zRDR+EbbeObu4V2X5QCd2Bk5eltfDlCr5yvhBwUT6pY=",
- "rev": "7c43f080a7f28b2774f3b3f43234ca11661bf334",
+ "lastModified": 315532800,
+ "narHash": "sha256-YwoXN6fthkakCFD7nXPcUK+rkNr6ZTNTuF8zdGaxZo0=",
+ "rev": "dc704e6102e76aad573f63b74c742cd96f8f1e6c",
"type": "tarball",
- "url": "https://releases.nixos.org/nixos/25.05/nixos-25.05.802491.7c43f080a7f2/nixexprs.tar.xz"
+ "url": "https://releases.nixos.org/nixpkgs/nixpkgs-25.11pre870318.dc704e6102e7/nixexprs.tar.xz"
},
"original": {
"type": "tarball",
- "url": "https://channels.nixos.org/nixos-25.05/nixexprs.tar.xz"
+ "url": "https://channels.nixos.org/nixpkgs-unstable/nixexprs.tar.xz"
}
},
"nixpkgs_2": {
@@ -97,11 +97,11 @@
]
},
"locked": {
- "lastModified": 1748261582,
- "narHash": "sha256-3i0IL3s18hdDlbsf0/E+5kyPRkZwGPbSFngq5eToiAA=",
+ "lastModified": 1759192380,
+ "narHash": "sha256-0BWJgt4OSzxCESij5oo8WLWrPZ+1qLp8KUQe32QeV4Q=",
"owner": "mitchellh",
"repo": "zig-overlay",
- "rev": "aafb1b093fb838f7a02613b719e85ec912914221",
+ "rev": "0bcd1401ed43d10f10cbded49624206553e92f57",
"type": "github"
},
"original": {
diff --git a/flake.nix b/flake.nix
index 7d72a9af3..18241a447 100644
--- a/flake.nix
+++ b/flake.nix
@@ -5,7 +5,9 @@
# We want to stay as up to date as possible but need to be careful that the
# glibc versions used by our dependencies from Nix are compatible with the
# system glibc that the user is building for.
- nixpkgs.url = "https://channels.nixos.org/nixos-25.05/nixexprs.tar.xz";
+ #
+ # We are currently on unstable to get Zig 0.15 for our package.nix
+ nixpkgs.url = "https://channels.nixos.org/nixpkgs-unstable/nixexprs.tar.xz";
flake-utils.url = "github:numtide/flake-utils";
# Used for shell.nix
@@ -47,7 +49,7 @@
pkgs = nixpkgs.legacyPackages.${system};
in {
devShell.${system} = pkgs.callPackage ./nix/devShell.nix {
- zig = zig.packages.${system}."0.14.1";
+ zig = zig.packages.${system}."0.15.1";
wraptest = pkgs.callPackage ./nix/wraptest.nix {};
zon2nix = zon2nix;
};
diff --git a/flatpak/dependencies.yml b/flatpak/dependencies.yml
index 082107923..667e4662c 100644
--- a/flatpak/dependencies.yml
+++ b/flatpak/dependencies.yml
@@ -13,12 +13,12 @@ modules:
- chmod a+x /app/zig/zig
sources:
- type: archive
- sha256: 24aeeec8af16c381934a6cd7d95c807a8cb2cf7df9fa40d359aa884195c4716c
- url: https://ziglang.org/download/0.14.1/zig-x86_64-linux-0.14.1.tar.xz
+ sha256: c61c5da6edeea14ca51ecd5e4520c6f4189ef5250383db33d01848293bfafe05
+ url: https://ziglang.org/download/0.15.1/zig-x86_64-linux-0.15.1.tar.xz
only-arches: [x86_64]
- type: archive
- sha256: f7a654acc967864f7a050ddacfaa778c7504a0eca8d2b678839c21eea47c992b
- url: https://ziglang.org/download/0.14.1/zig-aarch64-linux-0.14.1.tar.xz
+ sha256: bb4a8d2ad735e7fba764c497ddf4243cb129fece4148da3222a7046d3f1f19fe
+ url: https://ziglang.org/download/0.15.1/zig-aarch64-linux-0.15.1.tar.xz
only-arches: [aarch64]
- name: bzip2-redirect
diff --git a/flatpak/zig-packages.json b/flatpak/zig-packages.json
index beea0dc04..5d0ed3108 100644
--- a/flatpak/zig-packages.json
+++ b/flatpak/zig-packages.json
@@ -79,9 +79,9 @@
},
{
"type": "archive",
- "url": "https://github.com/mitchellh/libxev/archive/7f803181b158a10fec8619f793e3b4df515566cb.tar.gz",
- "dest": "vendor/p/libxev-0.0.0-86vtc2UaEwDfiTKX3iBI-s_hdzfzWQUarT3MUrmUQl-Q",
- "sha256": "29aa3360a121853ffab089de7fbffc3bfeb42c304937ef1099d2ee358d469267"
+ "url": "https://github.com/mitchellh/libxev/archive/34fa50878aec6e5fa8f532867001ab3c36fae23e.tar.gz",
+ "dest": "vendor/p/libxev-0.0.0-86vtc4IcEwCqEYxEYoN_3KXmc6A9VLcm22aVImfvecYs",
+ "sha256": "6003ea6b96e4a518a128f932327d79a11bd30996b13b73baeb29916379487dd7"
},
{
"type": "archive",
@@ -133,15 +133,21 @@
},
{
"type": "archive",
- "url": "https://github.com/jacobsandlund/uucode/archive/190706c6b56f0842d29778007f74f7d3d1335fc5.tar.gz",
- "dest": "vendor/p/uucode-0.1.0-ZZjBPpAFQABNCvd9cVPBg4I7233Ays-NWfWphPNqGbyE",
- "sha256": "8aaf4eca7b397b94e7cf604a3cf3d3bb2274dc13786cad1db2648f135b34c228"
+ "url": "https://github.com/jacobsandlund/uucode/archive/f81f8ef8518b8ec5a7fca30ec5fdbc76cc6197df.tar.gz",
+ "dest": "vendor/p/uucode-0.1.0-ZZjBPjQHQADuCy1VMWftjrMl3iWqgMpUugWVQJG6_7xT",
+ "sha256": "56899260e17c7d12706fff06b551bf42a47a73de734a442de3ae3d0bfe0a5c07"
},
{
- "type": "git",
- "url": "https://github.com/rockorager/libvaxis",
- "commit": "1f41c121e8fc153d9ce8c6eb64b2bbab68ad7d23",
- "dest": "vendor/p/vaxis-0.1.0-BWNV_FUICQAFZnTCL11TUvnUr1Y0_ZdqtXHhd51d76Rn"
+ "type": "archive",
+ "url": "https://github.com/rockorager/libvaxis/archive/1bf887aa7e3736bad69fd4e277a378946edb0f2a.tar.gz",
+ "dest": "vendor/p/vaxis-0.5.1-BWNV_H0PCQAeMusmtLzh9P9xO2IW242GZ2IRe9iKYhcA",
+ "sha256": "7aae580b6e8e6348b671d409d195cc67ea36bc740b10534d1b342de59bb3e013"
+ },
+ {
+ "type": "archive",
+ "url": "https://github.com/rockorager/libvaxis/archive/9fc9015d5f147568e18c5e7ca28f15bf8b293760.tar.gz",
+ "dest": "vendor/p/vaxis-0.5.1-BWNV_O8fCQAeUeVrESVc-2BdXloEXkFqReDJL7Q6XTSZ",
+ "sha256": "ec7e5ad09eee52caf394eec93407ff52cb22f56c6f9ac6f22529a1aaf97eaea2"
},
{
"type": "archive",
@@ -163,45 +169,57 @@
},
{
"type": "archive",
- "url": "https://github.com/vancluever/z2d/archive/refs/tags/v0.8.1.tar.gz",
- "dest": "vendor/p/z2d-0.8.1-j5P_Hq8vDwB8ZaDA54-SzESDLF2zznG_zvTHiQNJImZP",
- "sha256": "d036c3292600d5e8e1571fd66ce9304e00f9ecf35115c9d1be2a8187cc693d9d"
+ "url": "https://github.com/vancluever/z2d/archive/a1237f6881d99b75abd8a20a934e62e34b44a005.tar.gz",
+ "dest": "vendor/p/z2d-0.8.2-pre-j5P_HlVRFgCsBTQ3EgUoKbYHx5JMnyH1mHsOSPiafnef",
+ "sha256": "e7fa91640221d54e36bfb8ea97d5b48ebdb3cd066dbb7f43c493cb56b4b26c98"
},
{
"type": "archive",
- "url": "https://github.com/natecraddock/zf/archive/7aacbe6d155d64d15937ca95ca6c014905eb531f.tar.gz",
- "dest": "vendor/p/zf-0.10.3-OIRy8aiIAACLrBllz0zjxaH0aOe5oNm3KtEMyCntST-9",
- "sha256": "de7ba535077fe2b678a5a7972585f002588d37244db08397feadf3d4907c0bb2"
+ "url": "https://github.com/jcollie/zf/archive/52ad2e5528ab754f77437edf08a07b5ec843661c.tar.gz",
+ "dest": "vendor/p/zf-0.10.3-OIRy8QGJAACJcu3tCGtfbJnnd3Y4QL7OW_X8PJ8u_ASR",
+ "sha256": "f018a76da9d27d978103c481028a55c7024e6cddfafc14e9c551c004a89cb0c4"
},
{
"type": "git",
- "url": "https://codeberg.org/atman/zg",
- "commit": "4a002763419a34d61dcbb1f415821b83b9bf8ddc",
- "dest": "vendor/p/zg-0.13.4-AAAAAGiZ7QLz4pvECFa_wG4O4TP4FLABHHbemH2KakWM"
+ "url": "https://codeberg.org/ivanstepanovftw/zg",
+ "commit": "4fe689e56ce2ed5a8f59308b471bccd7da89fac9",
+ "dest": "vendor/p/zg-0.14.1-oGqU3J4_tAKBfyes3AWleKDjo-IcYvnEwaB8qxOqFMwM"
},
{
"type": "archive",
- "url": "https://deps.files.ghostty.org/zig_js-12205a66d423259567764fa0fc60c82be35365c21aeb76c5a7dc99698401f4f6fefc.tar.gz",
- "dest": "vendor/p/N-V-__8AAB9YCQBaZtQjJZVndk-g_GDIK-NTZcIa63bFp9yZ",
- "sha256": "7f235e0956c2f5401a28963a261019953d00e3bf4cfc029830f2161196c3583d"
+ "url": "https://codeberg.org/chaten/zg/archive/749197a3f9d25e211615960c02380a3d659b20f9.tar.gz",
+ "dest": "vendor/p/zg-0.15.1-oGqU3M0-tALZCy7boQS86znlBloyKx6--JriGlY0Paa9",
+ "sha256": "059873d673eac4aea176c250eba9fb264e3332015218b5e6f1e534097ffb9832"
},
{
"type": "archive",
- "url": "https://github.com/mitchellh/zig-objc/archive/c9e917a4e15a983b672ca779c7985d738a2d517c.tar.gz",
- "dest": "vendor/p/zig_objc-0.0.0-Ir_SpwsPAQBJgi9YRm2ubJMfdoysSq5gKpsIj3izQ8Zk",
- "sha256": "a37be5eea7e44a2d1b2976ba256b85f76a8c1063fc01ffec85c8a9e67468e4dc"
+ "url": "https://github.com/mitchellh/zig-js/archive/04db83c617da1956ac5adc1cb9ba1e434c1cb6fd.tar.gz",
+ "dest": "vendor/p/zig_js-0.0.0-rjCAV-6GAADxFug7rDmPH-uM_XcnJ5NmuAMJCAscMjhi",
+ "sha256": "4c2018e56015d39504b8090386ad9ce9393f38380085d9c32373bf7e56fc73a3"
},
{
"type": "archive",
- "url": "https://codeberg.org/ifreund/zig-wayland/archive/f3c5d503e540ada8cbcb056420de240af0c094f7.tar.gz",
- "dest": "vendor/p/wayland-0.4.0-dev-lQa1kjfIAQCmhhQu3xF0KH-94-TzeMXOqfnP0-Dg6Wyy",
- "sha256": "13bec6675e403d86db3b55b39ae262f1e1bdfe24056dcd82824341c6308b5219"
+ "url": "https://github.com/mitchellh/zig-objc/archive/f356ed02833f0f1b8e84d50bed9e807bf7cdc0ae.tar.gz",
+ "dest": "vendor/p/zig_objc-0.0.0-Ir_Sp5gTAQCvxxR7oVIrPXxXwsfKgVP7_wqoOQrZjFeK",
+ "sha256": "dd84af737625356fcd722cb30909f3b2e8d702667cf579714aa7eabc0ac08ecc"
+ },
+ {
+ "type": "archive",
+ "url": "https://codeberg.org/ifreund/zig-wayland/archive/1b5c038ec10da20ed3a15b0b2a6db1c21383e8ea.tar.gz",
+ "dest": "vendor/p/wayland-0.5.0-dev-lQa1khrMAQDJDwYFKpdH3HizherB7sHo5dKMECfvxQHe",
+ "sha256": "4f146b735ed0d527f520e3bf71d3e93f72c3d0fa583ae8edd3a4851f7079124e"
},
{
"type": "git",
- "url": "https://github.com/TUSF/zigimg",
- "commit": "31268548fe3276c0e95f318a6c0d2ab10565b58d",
- "dest": "vendor/p/zigimg-0.1.0-lly-O6N2EABOxke8dqyzCwhtUCAafqP35zC7wsZ4Ddxj"
+ "url": "https://github.com/ivanstepanovftw/zigimg",
+ "commit": "aa4c31db872612c39edbb79f753b3cd9a79fe726",
+ "dest": "vendor/p/zigimg-0.1.0-8_eo2mWmEgBoqdr0sH9O5GTqDHthkoEPM5_tipcBRreL"
+ },
+ {
+ "type": "archive",
+ "url": "https://github.com/ivanstepanovftw/zigimg/archive/d7b7ab0ba0899643831ef042bd73289510b39906.tar.gz",
+ "dest": "vendor/p/zigimg-0.1.0-8_eo2vHnEwCIVW34Q14Ec-xUlzIoVg86-7FU2ypPtxms",
+ "sha256": "2c1ed76ba2b35514544b0c27c9633ecba7c31be9080e37e7a010c93b5a1bc553"
},
{
"type": "archive",
diff --git a/nix/package.nix b/nix/package.nix
index fcc80b9dc..73d31c3b9 100644
--- a/nix/package.nix
+++ b/nix/package.nix
@@ -10,7 +10,7 @@
git,
ncurses,
pkg-config,
- zig_0_14,
+ zig_0_15,
pandoc,
revision ? "dirty",
optimize ? "Debug",
@@ -27,7 +27,7 @@
# https://github.com/ziglang/zig/issues/14281#issuecomment-1624220653 is
# ultimately acted on and has made its way to a nixpkgs implementation, this
# can probably be removed in favor of that.
- zig_hook = zig_0_14.hook.overrideAttrs {
+ zig_hook = zig_0_15.hook.overrideAttrs {
zig_default_flags = "-Dcpu=baseline -Doptimize=${optimize} --color off";
};
gi_typelib_path = import ./build-support/gi-typelib-path.nix {
diff --git a/pkg/apple-sdk/build.zig b/pkg/apple-sdk/build.zig
index 18a6c0968..c573c3910 100644
--- a/pkg/apple-sdk/build.zig
+++ b/pkg/apple-sdk/build.zig
@@ -46,19 +46,19 @@ pub fn addPaths(
// find the SDK path.
const libc = try std.zig.LibCInstallation.findNative(.{
.allocator = b.allocator,
- .target = step.rootModuleTarget(),
+ .target = &step.rootModuleTarget(),
.verbose = false,
});
// Render the file compatible with the `--libc` Zig flag.
- var list: std.ArrayList(u8) = .init(b.allocator);
- defer list.deinit();
- try libc.render(list.writer());
+ var stream: std.io.Writer.Allocating = .init(b.allocator);
+ defer stream.deinit();
+ try libc.render(&stream.writer);
// Create a temporary file to store the libc path because
// `--libc` expects a file path.
const wf = b.addWriteFiles();
- const path = wf.add("libc.txt", list.items);
+ const path = wf.add("libc.txt", stream.written());
// Determine our framework path. Zig has a bug where it doesn't
// parse this from the libc txt file for `-framework` flags:
diff --git a/pkg/breakpad/build.zig b/pkg/breakpad/build.zig
index 9ab6b89cd..56d51b159 100644
--- a/pkg/breakpad/build.zig
+++ b/pkg/breakpad/build.zig
@@ -19,9 +19,8 @@ pub fn build(b: *std.Build) !void {
try apple_sdk.addPaths(b, lib);
}
- var flags = std.ArrayList([]const u8).init(b.allocator);
- defer flags.deinit();
- try flags.appendSlice(&.{});
+ var flags: std.ArrayList([]const u8) = .empty;
+ defer flags.deinit(b.allocator);
if (b.lazyDependency("breakpad", .{})) |upstream| {
lib.addIncludePath(upstream.path("src"));
diff --git a/pkg/cimgui/build.zig b/pkg/cimgui/build.zig
index f14bc1242..b94f11943 100644
--- a/pkg/cimgui/build.zig
+++ b/pkg/cimgui/build.zig
@@ -55,19 +55,19 @@ pub fn build(b: *std.Build) !void {
if (imgui_) |imgui| lib.addIncludePath(imgui.path(""));
module.addIncludePath(b.path("vendor"));
- var flags = std.ArrayList([]const u8).init(b.allocator);
- defer flags.deinit();
- try flags.appendSlice(&.{
+ var flags: std.ArrayList([]const u8) = .empty;
+ defer flags.deinit(b.allocator);
+ try flags.appendSlice(b.allocator, &.{
"-DCIMGUI_FREETYPE=1",
"-DIMGUI_USE_WCHAR32=1",
"-DIMGUI_DISABLE_OBSOLETE_FUNCTIONS=1",
});
if (target.result.os.tag == .windows) {
- try flags.appendSlice(&.{
+ try flags.appendSlice(b.allocator, &.{
"-DIMGUI_IMPL_API=extern\t\"C\"\t__declspec(dllexport)",
});
} else {
- try flags.appendSlice(&.{
+ try flags.appendSlice(b.allocator, &.{
"-DIMGUI_IMPL_API=extern\t\"C\"",
});
}
diff --git a/pkg/fontconfig/build.zig b/pkg/fontconfig/build.zig
index c9ea517ed..7c87d1f2e 100644
--- a/pkg/fontconfig/build.zig
+++ b/pkg/fontconfig/build.zig
@@ -82,9 +82,9 @@ fn buildLib(b: *std.Build, module: *std.Build.Module, options: anytype) !*std.Bu
lib.addIncludePath(b.path("override/include"));
module.addIncludePath(b.path("override/include"));
- var flags = std.ArrayList([]const u8).init(b.allocator);
- defer flags.deinit();
- try flags.appendSlice(&.{
+ var flags: std.ArrayList([]const u8) = .empty;
+ defer flags.deinit(b.allocator);
+ try flags.appendSlice(b.allocator, &.{
"-DHAVE_DIRENT_H",
"-DHAVE_FCNTL_H",
"-DHAVE_STDLIB_H",
@@ -129,12 +129,12 @@ fn buildLib(b: *std.Build, module: *std.Build.Module, options: anytype) !*std.Bu
});
switch (target.result.ptrBitWidth()) {
- 32 => try flags.appendSlice(&.{
+ 32 => try flags.appendSlice(b.allocator, &.{
"-DSIZEOF_VOID_P=4",
"-DALIGNOF_VOID_P=4",
}),
- 64 => try flags.appendSlice(&.{
+ 64 => try flags.appendSlice(b.allocator, &.{
"-DSIZEOF_VOID_P=8",
"-DALIGNOF_VOID_P=8",
}),
@@ -142,14 +142,14 @@ fn buildLib(b: *std.Build, module: *std.Build.Module, options: anytype) !*std.Bu
else => @panic("unsupported arch"),
}
if (target.result.os.tag == .windows) {
- try flags.appendSlice(&.{
+ try flags.appendSlice(b.allocator, &.{
"-DFC_CACHEDIR=\"LOCAL_APPDATA_FONTCONFIG_CACHE\"",
"-DFC_TEMPLATEDIR=\"c:/share/fontconfig/conf.avail\"",
"-DCONFIGDIR=\"c:/etc/fonts/conf.d\"",
"-DFC_DEFAULT_FONTS=\"\\t
WINDOWSFONTDIR\\n\\tWINDOWSUSERFONTDIR\\n\"",
});
} else {
- try flags.appendSlice(&.{
+ try flags.appendSlice(b.allocator, &.{
"-DHAVE_FSTATFS",
"-DHAVE_FSTATVFS",
"-DHAVE_GETOPT",
@@ -173,13 +173,13 @@ fn buildLib(b: *std.Build, module: *std.Build.Module, options: anytype) !*std.Bu
});
if (target.result.os.tag == .freebsd) {
- try flags.appendSlice(&.{
+ try flags.appendSlice(b.allocator, &.{
"-DFC_TEMPLATEDIR=\"/usr/local/etc/fonts/conf.avail\"",
"-DFONTCONFIG_PATH=\"/usr/local/etc/fonts\"",
"-DCONFIGDIR=\"/usr/local/etc/fonts/conf.d\"",
});
} else {
- try flags.appendSlice(&.{
+ try flags.appendSlice(b.allocator, &.{
"-DFC_TEMPLATEDIR=\"/usr/share/fontconfig/conf.avail\"",
"-DFONTCONFIG_PATH=\"/etc/fonts\"",
"-DCONFIGDIR=\"/usr/local/fontconfig/conf.d\"",
@@ -187,7 +187,7 @@ fn buildLib(b: *std.Build, module: *std.Build.Module, options: anytype) !*std.Bu
}
if (target.result.os.tag == .linux) {
- try flags.appendSlice(&.{
+ try flags.appendSlice(b.allocator, &.{
"-DHAVE_SYS_STATFS_H",
"-DHAVE_SYS_VFS_H",
});
@@ -214,14 +214,14 @@ fn buildLib(b: *std.Build, module: *std.Build.Module, options: anytype) !*std.Bu
// Libxml2
_ = b.systemIntegrationOption("libxml2", .{}); // So it shows up in help
if (libxml2_enabled) {
- try flags.appendSlice(&.{
+ try flags.appendSlice(b.allocator, &.{
"-DENABLE_LIBXML2",
"-DLIBXML_STATIC",
"-DLIBXML_PUSH_ENABLED",
});
if (target.result.os.tag == .windows) {
// NOTE: this should be defined on all targets
- try flags.appendSlice(&.{
+ try flags.appendSlice(b.allocator, &.{
"-Werror=implicit-function-declaration",
});
}
diff --git a/pkg/freetype/build.zig b/pkg/freetype/build.zig
index d000442be..a25dc18da 100644
--- a/pkg/freetype/build.zig
+++ b/pkg/freetype/build.zig
@@ -77,9 +77,9 @@ fn buildLib(b: *std.Build, module: *std.Build.Module, options: anytype) !*std.Bu
try apple_sdk.addPaths(b, lib);
}
- var flags = std.ArrayList([]const u8).init(b.allocator);
- defer flags.deinit();
- try flags.appendSlice(&.{
+ var flags: std.ArrayList([]const u8) = .empty;
+ defer flags.deinit(b.allocator);
+ try flags.appendSlice(b.allocator, &.{
"-DFT2_BUILD_LIBRARY",
"-DFT_CONFIG_OPTION_SYSTEM_ZLIB=1",
@@ -103,7 +103,7 @@ fn buildLib(b: *std.Build, module: *std.Build.Module, options: anytype) !*std.Bu
// Libpng
_ = b.systemIntegrationOption("libpng", .{}); // So it shows up in help
if (libpng_enabled) {
- try flags.append("-DFT_CONFIG_OPTION_USE_PNG=1");
+ try flags.append(b.allocator, "-DFT_CONFIG_OPTION_USE_PNG=1");
if (b.systemIntegrationOption("libpng", .{})) {
lib.linkSystemLibrary2("libpng", dynamic_link_opts);
diff --git a/pkg/freetype/face.zig b/pkg/freetype/face.zig
index 84178b860..f8714d4fe 100644
--- a/pkg/freetype/face.zig
+++ b/pkg/freetype/face.zig
@@ -193,8 +193,8 @@ pub const Face = struct {
) void {
c.FT_Set_Transform(
self.handle,
- @constCast(@ptrCast(matrix)),
- @constCast(@ptrCast(delta)),
+ @ptrCast(@constCast(matrix)),
+ @ptrCast(@constCast(delta)),
);
}
};
diff --git a/pkg/glslang/build.zig b/pkg/glslang/build.zig
index 52993a662..746a41497 100644
--- a/pkg/glslang/build.zig
+++ b/pkg/glslang/build.zig
@@ -59,9 +59,9 @@ fn buildGlslang(
try apple_sdk.addPaths(b, lib);
}
- var flags = std.ArrayList([]const u8).init(b.allocator);
- defer flags.deinit();
- try flags.appendSlice(&.{
+ var flags: std.ArrayList([]const u8) = .empty;
+ defer flags.deinit(b.allocator);
+ try flags.appendSlice(b.allocator, &.{
"-fno-sanitize=undefined",
"-fno-sanitize-trap=undefined",
});
diff --git a/pkg/gtk4-layer-shell/build.zig b/pkg/gtk4-layer-shell/build.zig
index 543faf129..b9cf78a23 100644
--- a/pkg/gtk4-layer-shell/build.zig
+++ b/pkg/gtk4-layer-shell/build.zig
@@ -36,10 +36,13 @@ fn buildLib(b: *std.Build, module: *std.Build.Module, options: anytype) !*std.Bu
const optimize = options.optimize;
// Shared library
- const lib = b.addSharedLibrary(.{
+ const lib = b.addLibrary(.{
.name = "gtk4-layer-shell",
- .target = target,
- .optimize = optimize,
+ .linkage = .dynamic,
+ .root_module = b.createModule(.{
+ .target = target,
+ .optimize = optimize,
+ }),
});
b.installArtifact(lib);
diff --git a/pkg/harfbuzz/build.zig b/pkg/harfbuzz/build.zig
index bf247461a..8696c0203 100644
--- a/pkg/harfbuzz/build.zig
+++ b/pkg/harfbuzz/build.zig
@@ -111,13 +111,13 @@ fn buildLib(b: *std.Build, module: *std.Build.Module, options: anytype) !*std.Bu
const dynamic_link_opts = options.dynamic_link_opts;
- var flags = std.ArrayList([]const u8).init(b.allocator);
- defer flags.deinit();
- try flags.appendSlice(&.{
+ var flags: std.ArrayList([]const u8) = .empty;
+ defer flags.deinit(b.allocator);
+ try flags.appendSlice(b.allocator, &.{
"-DHAVE_STDBOOL_H",
});
if (target.result.os.tag != .windows) {
- try flags.appendSlice(&.{
+ try flags.appendSlice(b.allocator, &.{
"-DHAVE_UNISTD_H",
"-DHAVE_SYS_MMAN_H",
"-DHAVE_PTHREAD=1",
@@ -127,7 +127,7 @@ fn buildLib(b: *std.Build, module: *std.Build.Module, options: anytype) !*std.Bu
// Freetype
_ = b.systemIntegrationOption("freetype", .{}); // So it shows up in help
if (freetype_enabled) {
- try flags.appendSlice(&.{
+ try flags.appendSlice(b.allocator, &.{
"-DHAVE_FREETYPE=1",
// Let's just assume a new freetype
@@ -153,7 +153,7 @@ fn buildLib(b: *std.Build, module: *std.Build.Module, options: anytype) !*std.Bu
}
if (coretext_enabled) {
- try flags.appendSlice(&.{"-DHAVE_CORETEXT=1"});
+ try flags.appendSlice(b.allocator, &.{"-DHAVE_CORETEXT=1"});
lib.linkFramework("CoreText");
module.linkFramework("CoreText", .{});
}
diff --git a/pkg/highway/build.zig b/pkg/highway/build.zig
index 1013f1643..4c75de49e 100644
--- a/pkg/highway/build.zig
+++ b/pkg/highway/build.zig
@@ -31,9 +31,9 @@ pub fn build(b: *std.Build) !void {
try apple_sdk.addPaths(b, lib);
}
- var flags = std.ArrayList([]const u8).init(b.allocator);
- defer flags.deinit();
- try flags.appendSlice(&.{
+ var flags: std.ArrayList([]const u8) = .empty;
+ defer flags.deinit(b.allocator);
+ try flags.appendSlice(b.allocator, &.{
// Avoid changing binaries based on the current time and date.
"-Wno-builtin-macro-redefined",
"-D__DATE__=\"redacted\"",
@@ -69,7 +69,7 @@ pub fn build(b: *std.Build) !void {
"-fno-vectorize",
});
if (target.result.os.tag != .windows) {
- try flags.appendSlice(&.{
+ try flags.appendSlice(b.allocator, &.{
"-fmath-errno",
"-fno-exceptions",
});
diff --git a/pkg/libintl/build.zig b/pkg/libintl/build.zig
index 0e32648e7..32221e5ad 100644
--- a/pkg/libintl/build.zig
+++ b/pkg/libintl/build.zig
@@ -22,9 +22,9 @@ pub fn build(b: *std.Build) !void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
- var flags = std.ArrayList([]const u8).init(b.allocator);
- defer flags.deinit();
- try flags.appendSlice(&.{
+ var flags: std.ArrayList([]const u8) = .empty;
+ defer flags.deinit(b.allocator);
+ try flags.appendSlice(b.allocator, &.{
"-DHAVE_CONFIG_H",
"-DLOCALEDIR=\"\"",
});
diff --git a/pkg/libpng/build.zig b/pkg/libpng/build.zig
index 11ed29b18..dbedac632 100644
--- a/pkg/libpng/build.zig
+++ b/pkg/libpng/build.zig
@@ -46,9 +46,9 @@ pub fn build(b: *std.Build) !void {
}
if (b.lazyDependency("libpng", .{})) |upstream| {
- var flags = std.ArrayList([]const u8).init(b.allocator);
- defer flags.deinit();
- try flags.appendSlice(&.{
+ var flags: std.ArrayList([]const u8) = .empty;
+ defer flags.deinit(b.allocator);
+ try flags.appendSlice(b.allocator, &.{
"-DPNG_ARM_NEON_OPT=0",
"-DPNG_POWERPC_VSX_OPT=0",
"-DPNG_INTEL_SSE_OPT=0",
diff --git a/pkg/libxml2/build.zig b/pkg/libxml2/build.zig
index acebfaf63..a9b3e4b1a 100644
--- a/pkg/libxml2/build.zig
+++ b/pkg/libxml2/build.zig
@@ -25,9 +25,9 @@ pub fn build(b: *std.Build) !void {
lib.addIncludePath(b.path("override/config/posix"));
}
- var flags = std.ArrayList([]const u8).init(b.allocator);
- defer flags.deinit();
- try flags.appendSlice(&.{
+ var flags: std.ArrayList([]const u8) = .empty;
+ defer flags.deinit(b.allocator);
+ try flags.appendSlice(b.allocator, &.{
// Version info, hardcoded
comptime "-DLIBXML_VERSION=" ++ Version.number(),
comptime "-DLIBXML_VERSION_STRING=" ++ Version.string(),
@@ -46,7 +46,7 @@ pub fn build(b: *std.Build) !void {
"-DWITHOUT_TRIO=1",
});
if (target.result.os.tag != .windows) {
- try flags.appendSlice(&.{
+ try flags.appendSlice(b.allocator, &.{
"-DHAVE_ARPA_INET_H=1",
"-DHAVE_ARPA_NAMESER_H=1",
"-DHAVE_DL_H=1",
@@ -74,25 +74,25 @@ pub fn build(b: *std.Build) !void {
var nameBuf: [32]u8 = undefined;
const name = std.ascii.upperString(&nameBuf, field.name);
const define = try std.fmt.allocPrint(b.allocator, "-DLIBXML_{s}_ENABLED=1", .{name});
- try flags.append(define);
+ try flags.append(b.allocator, define);
if (std.mem.eql(u8, field.name, "history")) {
- try flags.appendSlice(&.{
+ try flags.appendSlice(b.allocator, &.{
"-DHAVE_LIBHISTORY=1",
"-DHAVE_LIBREADLINE=1",
});
}
if (std.mem.eql(u8, field.name, "mem_debug")) {
- try flags.append("-DDEBUG_MEMORY_LOCATION=1");
+ try flags.append(b.allocator, "-DDEBUG_MEMORY_LOCATION=1");
}
if (std.mem.eql(u8, field.name, "regexp")) {
- try flags.append("-DLIBXML_UNICODE_ENABLED=1");
+ try flags.append(b.allocator, "-DLIBXML_UNICODE_ENABLED=1");
}
if (std.mem.eql(u8, field.name, "run_debug")) {
- try flags.append("-DLIBXML_DEBUG_RUNTIME=1");
+ try flags.append(b.allocator, "-DLIBXML_DEBUG_RUNTIME=1");
}
if (std.mem.eql(u8, field.name, "thread")) {
- try flags.append("-DHAVE_LIBPTHREAD=1");
+ try flags.append(b.allocator, "-DHAVE_LIBPTHREAD=1");
}
}
}
diff --git a/pkg/macos/foundation/array.zig b/pkg/macos/foundation/array.zig
index d3a977539..7b580eb03 100644
--- a/pkg/macos/foundation/array.zig
+++ b/pkg/macos/foundation/array.zig
@@ -68,7 +68,7 @@ pub const MutableArray = opaque {
comptime Elem: type,
value: *const Elem,
) void {
- CFArrayAppendValue(self, @constCast(@ptrCast(value)));
+ CFArrayAppendValue(self, @ptrCast(@constCast(value)));
}
pub fn removeValue(self: *MutableArray, idx: usize) void {
diff --git a/pkg/macos/foundation/attributed_string.zig b/pkg/macos/foundation/attributed_string.zig
index de509b2c0..c7f27d7d7 100644
--- a/pkg/macos/foundation/attributed_string.zig
+++ b/pkg/macos/foundation/attributed_string.zig
@@ -10,7 +10,7 @@ pub const AttributedString = opaque {
str: *foundation.String,
attributes: *foundation.Dictionary,
) Allocator.Error!*AttributedString {
- return @constCast(@ptrCast(c.CFAttributedStringCreate(
+ return @ptrCast(@constCast(c.CFAttributedStringCreate(
null,
@ptrCast(str),
@ptrCast(attributes),
diff --git a/pkg/macos/foundation/dictionary.zig b/pkg/macos/foundation/dictionary.zig
index 90642e59a..a529442ac 100644
--- a/pkg/macos/foundation/dictionary.zig
+++ b/pkg/macos/foundation/dictionary.zig
@@ -17,8 +17,8 @@ pub const Dictionary = opaque {
return @as(?*Dictionary, @ptrFromInt(@intFromPtr(c.CFDictionaryCreate(
null,
- @constCast(@ptrCast(if (keys) |slice| slice.ptr else null)),
- @constCast(@ptrCast(if (values) |slice| slice.ptr else null)),
+ @ptrCast(@constCast(if (keys) |slice| slice.ptr else null)),
+ @ptrCast(@constCast(if (values) |slice| slice.ptr else null)),
@intCast(if (keys) |slice| slice.len else 0),
&c.kCFTypeDictionaryKeyCallBacks,
&c.kCFTypeDictionaryValueCallBacks,
diff --git a/pkg/macos/os/log.zig b/pkg/macos/os/log.zig
index 32ecb3296..219c914da 100644
--- a/pkg/macos/os/log.zig
+++ b/pkg/macos/os/log.zig
@@ -32,10 +32,11 @@ pub const Log = opaque {
comptime format: []const u8,
args: anytype,
) void {
- const str = nosuspend std.fmt.allocPrintZ(
+ const str = nosuspend std.fmt.allocPrintSentinel(
alloc,
format,
args,
+ 0,
) catch return;
defer alloc.free(str);
zig_os_log_with_type(self, typ, str.ptr);
diff --git a/pkg/macos/text/font.zig b/pkg/macos/text/font.zig
index 383861d62..ea37891f5 100644
--- a/pkg/macos/text/font.zig
+++ b/pkg/macos/text/font.zig
@@ -68,7 +68,7 @@ pub const Font = opaque {
}
pub fn copyTable(self: *Font, tag: FontTableTag) ?*foundation.Data {
- return @constCast(@ptrCast(c.CTFontCopyTable(
+ return @ptrCast(@constCast(c.CTFontCopyTable(
@ptrCast(self),
@intFromEnum(tag),
c.kCTFontTableOptionNoOptions,
@@ -90,7 +90,7 @@ pub const Font = opaque {
}
pub fn createPathForGlyph(self: *Font, glyph: graphics.Glyph) ?*graphics.Path {
- return @constCast(@ptrCast(c.CTFontCreatePathForGlyph(
+ return @ptrCast(@constCast(c.CTFontCreatePathForGlyph(
@ptrCast(self),
glyph,
null,
diff --git a/pkg/macos/text/line.zig b/pkg/macos/text/line.zig
index 135fd8558..248f8e645 100644
--- a/pkg/macos/text/line.zig
+++ b/pkg/macos/text/line.zig
@@ -51,7 +51,7 @@ pub const Line = opaque {
}
pub fn getGlyphRuns(self: *Line) *foundation.Array {
- return @constCast(@ptrCast(c.CTLineGetGlyphRuns(@ptrCast(self))));
+ return @ptrCast(@constCast(c.CTLineGetGlyphRuns(@ptrCast(self))));
}
};
diff --git a/pkg/macos/video/display_link.zig b/pkg/macos/video/display_link.zig
index 4bbf58a0c..7d6b437f9 100644
--- a/pkg/macos/video/display_link.zig
+++ b/pkg/macos/video/display_link.zig
@@ -74,7 +74,7 @@ pub const DisplayLink = opaque {
callbackFn(
displayLink,
- @alignCast(@ptrCast(inner_userinfo)),
+ @ptrCast(@alignCast(inner_userinfo)),
);
return c.kCVReturnSuccess;
}
diff --git a/pkg/oniguruma/build.zig b/pkg/oniguruma/build.zig
index 77e3b6f65..ea39b4814 100644
--- a/pkg/oniguruma/build.zig
+++ b/pkg/oniguruma/build.zig
@@ -100,9 +100,8 @@ fn buildLib(b: *std.Build, module: *std.Build.Module, options: anytype) !*std.Bu
.SIZEOF_VOIDP = t.ptrBitWidth() / t.cTypeBitSize(.char),
}));
- var flags = std.ArrayList([]const u8).init(b.allocator);
- defer flags.deinit();
- try flags.appendSlice(&.{});
+ var flags: std.ArrayList([]const u8) = .empty;
+ defer flags.deinit(b.allocator);
lib.addCSourceFiles(.{
.root = upstream.path(""),
.flags = flags.items,
diff --git a/pkg/oniguruma/init.zig b/pkg/oniguruma/init.zig
index 933e50b5a..ea64724c2 100644
--- a/pkg/oniguruma/init.zig
+++ b/pkg/oniguruma/init.zig
@@ -6,7 +6,7 @@ const errors = @import("errors.zig");
/// the encodings that the program will use.
pub fn init(encs: []const *Encoding) !void {
_ = try errors.convertError(c.onig_initialize(
- @constCast(@ptrCast(@alignCast(encs.ptr))),
+ @ptrCast(@alignCast(@constCast(encs.ptr))),
@intCast(encs.len),
));
}
diff --git a/pkg/sentry/build.zig b/pkg/sentry/build.zig
index 95900ae8f..3c88df56d 100644
--- a/pkg/sentry/build.zig
+++ b/pkg/sentry/build.zig
@@ -26,22 +26,21 @@ pub fn build(b: *std.Build) !void {
try apple_sdk.addPaths(b, lib);
}
- var flags = std.ArrayList([]const u8).init(b.allocator);
- defer flags.deinit();
- try flags.appendSlice(&.{});
+ var flags: std.ArrayList([]const u8) = .empty;
+ defer flags.deinit(b.allocator);
if (target.result.os.tag == .windows) {
- try flags.appendSlice(&.{
+ try flags.appendSlice(b.allocator, &.{
"-DSENTRY_WITH_UNWINDER_DBGHELP",
});
} else {
- try flags.appendSlice(&.{
+ try flags.appendSlice(b.allocator, &.{
"-DSENTRY_WITH_UNWINDER_LIBBACKTRACE",
});
}
switch (backend) {
- .crashpad => try flags.append("-DSENTRY_BACKEND_CRASHPAD"),
- .breakpad => try flags.append("-DSENTRY_BACKEND_BREAKPAD"),
- .inproc => try flags.append("-DSENTRY_BACKEND_INPROC"),
+ .crashpad => try flags.append(b.allocator, "-DSENTRY_BACKEND_CRASHPAD"),
+ .breakpad => try flags.append(b.allocator, "-DSENTRY_BACKEND_BREAKPAD"),
+ .inproc => try flags.append(b.allocator, "-DSENTRY_BACKEND_INPROC"),
.none => {},
}
diff --git a/pkg/simdutf/build.zig b/pkg/simdutf/build.zig
index f96eeae45..f2ddfeba4 100644
--- a/pkg/simdutf/build.zig
+++ b/pkg/simdutf/build.zig
@@ -20,11 +20,11 @@ pub fn build(b: *std.Build) !void {
try apple_sdk.addPaths(b, lib);
}
- var flags = std.ArrayList([]const u8).init(b.allocator);
- defer flags.deinit();
+ var flags: std.ArrayList([]const u8) = .empty;
+ defer flags.deinit(b.allocator);
// Zig 0.13 bug: https://github.com/ziglang/zig/issues/20414
// (See root Ghostty build.zig on why we do this)
- try flags.appendSlice(&.{"-DSIMDUTF_IMPLEMENTATION_ICELAKE=0"});
+ try flags.appendSlice(b.allocator, &.{"-DSIMDUTF_IMPLEMENTATION_ICELAKE=0"});
lib.addCSourceFiles(.{
.flags = flags.items,
diff --git a/pkg/spirv-cross/build.zig b/pkg/spirv-cross/build.zig
index ff7f15c94..003ec43cf 100644
--- a/pkg/spirv-cross/build.zig
+++ b/pkg/spirv-cross/build.zig
@@ -64,9 +64,9 @@ fn buildSpirvCross(
try apple_sdk.addPaths(b, lib);
}
- var flags = std.ArrayList([]const u8).init(b.allocator);
- defer flags.deinit();
- try flags.appendSlice(&.{
+ var flags: std.ArrayList([]const u8) = .empty;
+ defer flags.deinit(b.allocator);
+ try flags.appendSlice(b.allocator, &.{
"-DSPIRV_CROSS_C_API_GLSL=1",
"-DSPIRV_CROSS_C_API_MSL=1",
diff --git a/pkg/utfcpp/build.zig b/pkg/utfcpp/build.zig
index 341b35578..e06813b83 100644
--- a/pkg/utfcpp/build.zig
+++ b/pkg/utfcpp/build.zig
@@ -19,9 +19,8 @@ pub fn build(b: *std.Build) !void {
try apple_sdk.addPaths(b, lib);
}
- var flags = std.ArrayList([]const u8).init(b.allocator);
- defer flags.deinit();
- try flags.appendSlice(&.{});
+ var flags: std.ArrayList([]const u8) = .empty;
+ defer flags.deinit(b.allocator);
lib.addCSourceFiles(.{
.flags = flags.items,
diff --git a/pkg/wuffs/build.zig b/pkg/wuffs/build.zig
index 57d89e6b6..3d9f83daa 100644
--- a/pkg/wuffs/build.zig
+++ b/pkg/wuffs/build.zig
@@ -17,11 +17,11 @@ pub fn build(b: *std.Build) !void {
});
unit_tests.linkLibC();
- var flags = std.ArrayList([]const u8).init(b.allocator);
- defer flags.deinit();
- try flags.append("-DWUFFS_IMPLEMENTATION");
+ var flags: std.ArrayList([]const u8) = .empty;
+ defer flags.deinit(b.allocator);
+ try flags.append(b.allocator, "-DWUFFS_IMPLEMENTATION");
inline for (@import("src/c.zig").defines) |key| {
- try flags.append("-D" ++ key);
+ try flags.append(b.allocator, "-D" ++ key);
}
if (b.lazyDependency("wuffs", .{})) |wuffs_dep| {
diff --git a/pkg/wuffs/src/jpeg.zig b/pkg/wuffs/src/jpeg.zig
index c07278eed..700ba01b9 100644
--- a/pkg/wuffs/src/jpeg.zig
+++ b/pkg/wuffs/src/jpeg.zig
@@ -31,7 +31,7 @@ pub fn decode(alloc: Allocator, data: []const u8) Error!ImageData {
}
var source_buffer: c.wuffs_base__io_buffer = .{
- .data = .{ .ptr = @constCast(@ptrCast(data.ptr)), .len = data.len },
+ .data = .{ .ptr = @ptrCast(@constCast(data.ptr)), .len = data.len },
.meta = .{
.wi = data.len,
.ri = 0,
diff --git a/pkg/wuffs/src/png.zig b/pkg/wuffs/src/png.zig
index 1f37bb375..d79ae5b56 100644
--- a/pkg/wuffs/src/png.zig
+++ b/pkg/wuffs/src/png.zig
@@ -31,7 +31,7 @@ pub fn decode(alloc: Allocator, data: []const u8) Error!ImageData {
}
var source_buffer: c.wuffs_base__io_buffer = .{
- .data = .{ .ptr = @constCast(@ptrCast(data.ptr)), .len = data.len },
+ .data = .{ .ptr = @ptrCast(@constCast(data.ptr)), .len = data.len },
.meta = .{
.wi = data.len,
.ri = 0,
diff --git a/pkg/zlib/build.zig b/pkg/zlib/build.zig
index caa557454..246ab1bcb 100644
--- a/pkg/zlib/build.zig
+++ b/pkg/zlib/build.zig
@@ -26,9 +26,9 @@ pub fn build(b: *std.Build) !void {
.{ .include_extensions = &.{".h"} },
);
- var flags = std.ArrayList([]const u8).init(b.allocator);
- defer flags.deinit();
- try flags.appendSlice(&.{
+ var flags: std.ArrayList([]const u8) = .empty;
+ defer flags.deinit(b.allocator);
+ try flags.appendSlice(b.allocator, &.{
"-DHAVE_SYS_TYPES_H",
"-DHAVE_STDINT_H",
"-DHAVE_STDDEF_H",
diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml
index e48fa93c8..2e434843c 100644
--- a/snap/snapcraft.yaml
+++ b/snap/snapcraft.yaml
@@ -52,7 +52,7 @@ parts:
rm -rf $CRAFT_PART_SRC/*
if [[ -n $arch ]]; then
- curl -LO --retry-connrefused --retry 10 https://ziglang.org/download/0.14.0/zig-linux-$arch-0.14.0.tar.xz
+ curl -LO --retry-connrefused --retry 10 https://ziglang.org/download/0.15.1/zig-$arch-linux-0.15.1.tar.xz
else
echo "Unsupported arch"
exit 1
diff --git a/src/Command.zig b/src/Command.zig
index b0d804327..f28d8bb9d 100644
--- a/src/Command.zig
+++ b/src/Command.zig
@@ -194,7 +194,9 @@ fn startPosix(self: *Command, arena: Allocator) !void {
// child process so there isn't much we can do. We try to output
// something reasonable. Its important to note we MUST NOT return
// any other error condition from here on out.
- const stderr = std.io.getStdErr().writer();
+ var stderr_buf: [1024]u8 = undefined;
+ var stderr_writer = std.fs.File.stderr().writer(&stderr_buf);
+ const stderr = &stderr_writer.interface;
switch (err) {
error.FileNotFound => stderr.print(
\\Requested executable not found. Please verify the command is on
@@ -211,6 +213,7 @@ fn startPosix(self: *Command, arena: Allocator) !void {
.{err},
) catch {},
}
+ stderr.flush() catch {};
// We return a very specific error that can be detected to determine
// we're in the child.
@@ -464,34 +467,35 @@ fn createWindowsEnvBlock(allocator: mem.Allocator, env_map: *const EnvMap) ![]u1
/// Copied from Zig. This function could be made public in child_process.zig instead.
fn windowsCreateCommandLine(allocator: mem.Allocator, argv: []const []const u8) ![:0]u8 {
- var buf = std.ArrayList(u8).init(allocator);
+ var buf: std.Io.Writer.Allocating = .init(allocator);
defer buf.deinit();
+ const writer = &buf.writer;
for (argv, 0..) |arg, arg_i| {
- if (arg_i != 0) try buf.append(' ');
+ if (arg_i != 0) try writer.writeByte(' ');
if (mem.indexOfAny(u8, arg, " \t\n\"") == null) {
- try buf.appendSlice(arg);
+ try writer.writeAll(arg);
continue;
}
- try buf.append('"');
+ try writer.writeByte('"');
var backslash_count: usize = 0;
for (arg) |byte| {
switch (byte) {
'\\' => backslash_count += 1,
'"' => {
- try buf.appendNTimes('\\', backslash_count * 2 + 1);
- try buf.append('"');
+ try writer.splatByteAll('\\', backslash_count * 2 + 1);
+ try writer.writeByte('"');
backslash_count = 0;
},
else => {
- try buf.appendNTimes('\\', backslash_count);
- try buf.append(byte);
+ try writer.splatByteAll('\\', backslash_count);
+ try writer.writeByte(byte);
backslash_count = 0;
},
}
}
- try buf.appendNTimes('\\', backslash_count * 2);
- try buf.append('"');
+ try writer.splatByteAll('\\', backslash_count * 2);
+ try writer.writeByte('"');
}
return buf.toOwnedSliceSentinel(0);
diff --git a/src/Surface.zig b/src/Surface.zig
index 3b4bf872f..403a628d2 100644
--- a/src/Surface.zig
+++ b/src/Surface.zig
@@ -305,19 +305,19 @@ const DerivedConfig = struct {
// Build all of our links
const links = links: {
- var links = std.ArrayList(Link).init(alloc);
- defer links.deinit();
+ var links: std.ArrayList(Link) = .empty;
+ defer links.deinit(alloc);
for (config.link.links.items) |link| {
var regex = try link.oniRegex();
errdefer regex.deinit();
- try links.append(.{
+ try links.append(alloc, .{
.regex = regex,
.action = link.action,
.highlight = link.highlight,
});
}
- break :links try links.toOwnedSlice();
+ break :links try links.toOwnedSlice(alloc);
};
errdefer {
for (links) |*link| link.regex.deinit();
@@ -1009,7 +1009,7 @@ pub fn handleMessage(self: *Surface, msg: Message) !void {
self.command_timer = null;
const duration: Duration = .{ .duration = end.since(start) };
- log.debug("command took {}", .{duration});
+ log.debug("command took {f}", .{duration});
_ = self.rt_app.performAction(
.{ .surface = self },
@@ -2493,7 +2493,7 @@ fn maybeHandleBinding(
self.keyboard.bindings = null;
// Attempt to perform the action
- log.debug("key event binding flags={} action={}", .{
+ log.debug("key event binding flags={} action={f}", .{
leaf.flags,
action,
});
@@ -5119,7 +5119,9 @@ fn writeScreenFile(
defer file.close();
// Screen.dumpString writes byte-by-byte, so buffer it
- var buf_writer = std.io.bufferedWriter(file.writer());
+ var buf: [4096]u8 = undefined;
+ var file_writer = file.writer(&buf);
+ var buf_writer = &file_writer.interface;
// Write the scrollback contents. This requires a lock.
{
@@ -5169,7 +5171,7 @@ fn writeScreenFile(
const br = sel.bottomRight(&self.io.terminal.screen);
try self.io.terminal.screen.dumpString(
- buf_writer.writer(),
+ buf_writer,
.{
.tl = tl,
.br = br,
diff --git a/src/apprt/action.zig b/src/apprt/action.zig
index b356ff32f..14a8165f2 100644
--- a/src/apprt/action.zig
+++ b/src/apprt/action.zig
@@ -578,7 +578,7 @@ pub const SetTitle = struct {
value: @This(),
comptime _: []const u8,
_: std.fmt.FormatOptions,
- writer: anytype,
+ writer: *std.Io.Writer,
) !void {
try writer.print("{s}{{ {s} }}", .{ @typeName(@This()), value.title });
}
@@ -602,7 +602,7 @@ pub const Pwd = struct {
value: @This(),
comptime _: []const u8,
_: std.fmt.FormatOptions,
- writer: anytype,
+ writer: *std.Io.Writer,
) !void {
try writer.print("{s}{{ {s} }}", .{ @typeName(@This()), value.pwd });
}
@@ -630,7 +630,7 @@ pub const DesktopNotification = struct {
value: @This(),
comptime _: []const u8,
_: std.fmt.FormatOptions,
- writer: anytype,
+ writer: *std.Io.Writer,
) !void {
try writer.print("{s}{{ title: {s}, body: {s} }}", .{
@typeName(@This()),
diff --git a/src/apprt/embedded.zig b/src/apprt/embedded.zig
index 08d8291ef..617557995 100644
--- a/src/apprt/embedded.zig
+++ b/src/apprt/embedded.zig
@@ -266,8 +266,8 @@ pub const App = struct {
// embedded apprt.
self.performPreAction(target, action, value);
- log.debug("dispatching action target={s} action={} value={}", .{
- @tagName(target),
+ log.debug("dispatching action target={t} action={} value={any}", .{
+ target,
action,
value,
});
@@ -1910,7 +1910,7 @@ pub const CAPI = struct {
};
return ptr.core_surface.performBindingAction(action) catch |err| {
- log.err("error performing binding action action={} err={}", .{ action, err });
+ log.err("error performing binding action action={f} err={}", .{ action, err });
return false;
};
}
diff --git a/src/apprt/gtk/adw_version.zig b/src/apprt/gtk/adw_version.zig
index 7ce88f585..6f7be52da 100644
--- a/src/apprt/gtk/adw_version.zig
+++ b/src/apprt/gtk/adw_version.zig
@@ -27,7 +27,7 @@ pub fn getRuntimeVersion() std.SemanticVersion {
}
pub fn logVersion() void {
- log.info("libadwaita version build={} runtime={}", .{
+ log.info("libadwaita version build={f} runtime={f}", .{
comptime_version,
getRuntimeVersion(),
});
diff --git a/src/apprt/gtk/build/blueprint.zig b/src/apprt/gtk/build/blueprint.zig
index 1e614f972..f25e7e1f9 100644
--- a/src/apprt/gtk/build/blueprint.zig
+++ b/src/apprt/gtk/build/blueprint.zig
@@ -45,7 +45,7 @@ pub fn main() !void {
std.debug.print(
\\`libadwaita` is too old.
\\
- \\Ghostty requires a version {} or newer of `libadwaita` to
+ \\Ghostty requires a version {f} or newer of `libadwaita` to
\\compile this blueprint. Please install it, ensure that it is
\\available on your PATH, and then retry building Ghostty.
, .{required_adwaita_version});
@@ -80,7 +80,7 @@ pub fn main() !void {
std.debug.print(
\\`blueprint-compiler` not found.
\\
- \\Ghostty requires version {} or newer of
+ \\Ghostty requires version {f} or newer of
\\`blueprint-compiler` as a build-time dependency starting
\\from version 1.2. Please install it, ensure that it is
\\available on your PATH, and then retry building Ghostty.
@@ -104,7 +104,7 @@ pub fn main() !void {
std.debug.print(
\\`blueprint-compiler` is the wrong version.
\\
- \\Ghostty requires version {} or newer of
+ \\Ghostty requires version {f} or newer of
\\`blueprint-compiler` as a build-time dependency starting
\\from version 1.2. Please install it, ensure that it is
\\available on your PATH, and then retry building Ghostty.
@@ -145,7 +145,7 @@ pub fn main() !void {
std.debug.print(
\\`blueprint-compiler` not found.
\\
- \\Ghostty requires version {} or newer of
+ \\Ghostty requires version {f} or newer of
\\`blueprint-compiler` as a build-time dependency starting
\\from version 1.2. Please install it, ensure that it is
\\available on your PATH, and then retry building Ghostty.
diff --git a/src/apprt/gtk/build/gresource.zig b/src/apprt/gtk/build/gresource.zig
index 1f253fd5e..fabd5763e 100644
--- a/src/apprt/gtk/build/gresource.zig
+++ b/src/apprt/gtk/build/gresource.zig
@@ -142,7 +142,9 @@ pub fn main() !void {
);
}
- const writer = std.io.getStdOut().writer();
+ var buf: [4096]u8 = undefined;
+ var stdout = std.fs.File.stdout().writer(&buf);
+ const writer = &stdout.interface;
try writer.writeAll(
\\
\\
@@ -157,12 +159,14 @@ pub fn main() !void {
\\
\\
);
+
+ try stdout.end();
}
/// Generate the icon resources. This works by looking up all the icons
/// specified by `icon_sizes` in `images/icons/`. They are asserted to exist
/// by trying to access the file.
-fn genIcons(writer: anytype) !void {
+fn genIcons(writer: *std.Io.Writer) !void {
try writer.print(
\\
\\
@@ -204,7 +208,7 @@ fn genIcons(writer: anytype) !void {
}
/// Generate the resources at the root prefix.
-fn genRoot(writer: anytype) !void {
+fn genRoot(writer: *std.Io.Writer) !void {
try writer.print(
\\
\\
@@ -236,7 +240,7 @@ fn genRoot(writer: anytype) !void {
/// assuming these will be
fn genUi(
alloc: Allocator,
- writer: anytype,
+ writer: *std.Io.Writer,
files: *const std.ArrayListUnmanaged([]const u8),
) !void {
try writer.print(
diff --git a/src/apprt/gtk/cgroup.zig b/src/apprt/gtk/cgroup.zig
index 23c4d545e..697126798 100644
--- a/src/apprt/gtk/cgroup.zig
+++ b/src/apprt/gtk/cgroup.zig
@@ -50,7 +50,7 @@ pub fn init(
) orelse "";
if (!std.mem.eql(u8, original, current)) break :transient current;
alloc.free(current);
- std.time.sleep(25 * std.time.ns_per_ms);
+ std.Thread.sleep(25 * std.time.ns_per_ms);
};
errdefer alloc.free(transient);
log.info("transient scope created cgroup={s}", .{transient});
@@ -101,21 +101,21 @@ fn enableControllers(alloc: Allocator, cgroup: []const u8) !void {
defer alloc.free(raw);
// Build our string builder for enabling all controllers
- var builder = std.ArrayList(u8).init(alloc);
+ var builder: std.Io.Writer.Allocating = .init(alloc);
defer builder.deinit();
// Controllers are space-separated
var it = std.mem.splitScalar(u8, raw, ' ');
while (it.next()) |controller| {
- try builder.append('+');
- try builder.appendSlice(controller);
- if (it.rest().len > 0) try builder.append(' ');
+ try builder.writer.writeByte('+');
+ try builder.writer.writeAll(controller);
+ if (it.rest().len > 0) try builder.writer.writeByte(' ');
}
// Enable them all
try internal_os.cgroup.configureControllers(
cgroup,
- builder.items,
+ builder.written(),
);
}
diff --git a/src/apprt/gtk/class.zig b/src/apprt/gtk/class.zig
index 4b46f8365..942666cf4 100644
--- a/src/apprt/gtk/class.zig
+++ b/src/apprt/gtk/class.zig
@@ -282,7 +282,7 @@ pub fn Common(
fn setter(self: *Self, value: ?[:0]const u8) void {
const priv = private(self);
if (@field(priv, name)) |v| {
- glib.free(@constCast(@ptrCast(v)));
+ glib.free(@ptrCast(@constCast(v)));
}
// We don't need to copy this because it was already
diff --git a/src/apprt/gtk/class/application.zig b/src/apprt/gtk/class/application.zig
index 90c72681d..af56130d3 100644
--- a/src/apprt/gtk/class/application.zig
+++ b/src/apprt/gtk/class/application.zig
@@ -1044,7 +1044,9 @@ pub const Application = extern struct {
defer file.close();
log.info("loading gtk-custom-css path={s}", .{path});
- const contents = try file.reader().readAllAlloc(
+ var buf: [4096]u8 = undefined;
+ var reader = file.reader(&buf);
+ const contents = try reader.interface.readAlloc(
alloc,
5 * 1024 * 1024, // 5MB,
);
@@ -1115,8 +1117,8 @@ pub const Application = extern struct {
// This should really never, never happen. Its not critical enough
// to actually crash, but this is a bug somewhere. An accelerator
// for a trigger can't possibly be more than 1024 bytes.
- error.NoSpaceLeft => {
- log.warn("accelerator somehow longer than 1024 bytes: {}", .{trigger});
+ error.WriteFailed => {
+ log.warn("accelerator somehow longer than 1024 bytes: {f}", .{trigger});
return;
},
};
diff --git a/src/apprt/gtk/class/command_palette.zig b/src/apprt/gtk/class/command_palette.zig
index 8b7bb328c..6da49115e 100644
--- a/src/apprt/gtk/class/command_palette.zig
+++ b/src/apprt/gtk/class/command_palette.zig
@@ -485,10 +485,11 @@ const Command = extern struct {
const command = priv.command orelse return null;
- priv.action_key = std.fmt.allocPrintZ(
+ priv.action_key = std.fmt.allocPrintSentinel(
priv.arena.allocator(),
- "{}",
+ "{f}",
.{command.action},
+ 0,
) catch null;
return priv.action_key;
diff --git a/src/apprt/gtk/class/config.zig b/src/apprt/gtk/class/config.zig
index 2b98c68b5..eadd3b7b8 100644
--- a/src/apprt/gtk/class/config.zig
+++ b/src/apprt/gtk/class/config.zig
@@ -117,10 +117,10 @@ pub const Config = extern struct {
errdefer text_buf.unref();
var buf: [4095:0]u8 = undefined;
- var fbs = std.io.fixedBufferStream(&buf);
+ var writer: std.Io.Writer = .fixed(&buf);
for (config._diagnostics.items()) |diag| {
- fbs.reset();
- diag.write(fbs.writer()) catch |err| {
+ writer.end = 0;
+ diag.format(&writer) catch |err| {
log.warn(
"error writing diagnostic to buffer err={}",
.{err},
@@ -128,7 +128,7 @@ pub const Config = extern struct {
continue;
};
- text_buf.insertAtCursor(&buf, @intCast(fbs.pos));
+ text_buf.insertAtCursor(&buf, @intCast(writer.end));
text_buf.insertAtCursor("\n", 1);
}
diff --git a/src/apprt/gtk/class/global_shortcuts.zig b/src/apprt/gtk/class/global_shortcuts.zig
index 18280cfe9..9c67be7c1 100644
--- a/src/apprt/gtk/class/global_shortcuts.zig
+++ b/src/apprt/gtk/class/global_shortcuts.zig
@@ -188,9 +188,9 @@ pub const GlobalShortcuts = extern struct {
// If there isn't space to translate the trigger, then our
// buffer might be too small (but 1024 is insane!). In any case
// we don't want to stop registering globals.
- error.NoSpaceLeft => {
+ error.WriteFailed => {
log.warn(
- "buffer too small to translate trigger, ignoring={}",
+ "buffer too small to translate trigger, ignoring={f}",
.{entry.key_ptr.*},
);
continue;
@@ -257,7 +257,7 @@ pub const GlobalShortcuts = extern struct {
const trigger = entry.key_ptr.*.ptr;
const action = std.fmt.bufPrintZ(
&action_buf,
- "{}",
+ "{f}",
.{entry.value_ptr.*},
) catch continue;
diff --git a/src/apprt/gtk/class/resize_overlay.zig b/src/apprt/gtk/class/resize_overlay.zig
index 9bb9a0a7c..f6e0c1442 100644
--- a/src/apprt/gtk/class/resize_overlay.zig
+++ b/src/apprt/gtk/class/resize_overlay.zig
@@ -172,7 +172,7 @@ pub const ResizeOverlay = extern struct {
/// overlay if it is currently hidden; you must call schedule.
pub fn setLabel(self: *Self, label: ?[:0]const u8) void {
const priv = self.private();
- if (priv.label_text) |v| glib.free(@constCast(@ptrCast(v)));
+ if (priv.label_text) |v| glib.free(@ptrCast(@constCast(v)));
priv.label_text = null;
if (label) |v| priv.label_text = glib.ext.dupeZ(u8, v);
self.as(gobject.Object).notifyByPspec(properties.label.impl.param_spec);
@@ -285,7 +285,7 @@ pub const ResizeOverlay = extern struct {
fn finalize(self: *Self) callconv(.c) void {
const priv = self.private();
if (priv.label_text) |v| {
- glib.free(@constCast(@ptrCast(v)));
+ glib.free(@ptrCast(@constCast(v)));
priv.label_text = null;
}
diff --git a/src/apprt/gtk/class/split_tree.zig b/src/apprt/gtk/class/split_tree.zig
index 977a7eab2..a498ca5dc 100644
--- a/src/apprt/gtk/class/split_tree.zig
+++ b/src/apprt/gtk/class/split_tree.zig
@@ -268,7 +268,7 @@ pub const SplitTree = extern struct {
);
defer new_tree.deinit();
log.debug(
- "new split at={} direction={} old_tree={} new_tree={}",
+ "new split at={} direction={} old_tree={f} new_tree={f}",
.{ handle, direction, old_tree, &new_tree },
);
diff --git a/src/apprt/gtk/class/surface.zig b/src/apprt/gtk/class/surface.zig
index 401e542e4..5ca964fe3 100644
--- a/src/apprt/gtk/class/surface.zig
+++ b/src/apprt/gtk/class/surface.zig
@@ -1375,11 +1375,11 @@ pub const Surface = extern struct {
defer arena.deinit();
const alloc = arena.allocator();
- var env_to_remove = std.ArrayList([]const u8).init(alloc);
- var env_to_update = std.ArrayList(struct {
+ var env_to_remove: std.ArrayList([]const u8) = .empty;
+ var env_to_update: std.ArrayList(struct {
key: []const u8,
value: []const u8,
- }).init(alloc);
+ }) = .empty;
var it = env_map.iterator();
while (it.next()) |entry| {
@@ -1392,13 +1392,11 @@ pub const Surface = extern struct {
// Any env var starting with SNAP must be removed
if (std.mem.startsWith(u8, key, "SNAP_")) {
- try env_to_remove.append(key);
+ try env_to_remove.append(alloc, key);
continue;
}
- var filtered_paths = std.ArrayList([]const u8).init(alloc);
- defer filtered_paths.deinit();
-
+ var filtered_paths: std.ArrayList([]const u8) = .empty;
var modified = false;
var paths = std.mem.splitAny(u8, value, ":");
while (paths.next()) |path| {
@@ -1411,15 +1409,15 @@ pub const Surface = extern struct {
break;
}
};
- if (include) try filtered_paths.append(path);
+ if (include) try filtered_paths.append(alloc, path);
}
if (modified) {
if (filtered_paths.items.len > 0) {
const new_value = try std.mem.join(alloc, ":", filtered_paths.items);
- try env_to_update.append(.{ .key = key, .value = new_value });
+ try env_to_update.append(alloc, .{ .key = key, .value = new_value });
} else {
- try env_to_remove.append(key);
+ try env_to_remove.append(alloc, key);
}
}
}
@@ -1626,7 +1624,7 @@ pub const Surface = extern struct {
priv.core_surface = null;
}
if (priv.mouse_hover_url) |v| {
- glib.free(@constCast(@ptrCast(v)));
+ glib.free(@ptrCast(@constCast(v)));
priv.mouse_hover_url = null;
}
if (priv.default_size) |v| {
@@ -1642,15 +1640,15 @@ pub const Surface = extern struct {
priv.min_size = null;
}
if (priv.pwd) |v| {
- glib.free(@constCast(@ptrCast(v)));
+ glib.free(@ptrCast(@constCast(v)));
priv.pwd = null;
}
if (priv.title) |v| {
- glib.free(@constCast(@ptrCast(v)));
+ glib.free(@ptrCast(@constCast(v)));
priv.title = null;
}
if (priv.title_override) |v| {
- glib.free(@constCast(@ptrCast(v)));
+ glib.free(@ptrCast(@constCast(v)));
priv.title_override = null;
}
self.clearCgroup();
@@ -1674,7 +1672,7 @@ pub const Surface = extern struct {
/// title. For manually set titles see `setTitleOverride`.
pub fn setTitle(self: *Self, title: ?[:0]const u8) void {
const priv = self.private();
- if (priv.title) |v| glib.free(@constCast(@ptrCast(v)));
+ if (priv.title) |v| glib.free(@ptrCast(@constCast(v)));
priv.title = null;
if (title) |v| priv.title = glib.ext.dupeZ(u8, v);
self.as(gobject.Object).notifyByPspec(properties.title.impl.param_spec);
@@ -1684,7 +1682,7 @@ pub const Surface = extern struct {
/// unless this is unset (null).
pub fn setTitleOverride(self: *Self, title: ?[:0]const u8) void {
const priv = self.private();
- if (priv.title_override) |v| glib.free(@constCast(@ptrCast(v)));
+ if (priv.title_override) |v| glib.free(@ptrCast(@constCast(v)));
priv.title_override = null;
if (title) |v| priv.title_override = glib.ext.dupeZ(u8, v);
self.as(gobject.Object).notifyByPspec(properties.@"title-override".impl.param_spec);
@@ -1698,7 +1696,7 @@ pub const Surface = extern struct {
/// Set the pwd for this surface, copies the value.
pub fn setPwd(self: *Self, pwd: ?[:0]const u8) void {
const priv = self.private();
- if (priv.pwd) |v| glib.free(@constCast(@ptrCast(v)));
+ if (priv.pwd) |v| glib.free(@ptrCast(@constCast(v)));
priv.pwd = null;
if (pwd) |v| priv.pwd = glib.ext.dupeZ(u8, v);
self.as(gobject.Object).notifyByPspec(properties.pwd.impl.param_spec);
@@ -1783,7 +1781,7 @@ pub const Surface = extern struct {
pub fn setMouseHoverUrl(self: *Self, url: ?[:0]const u8) void {
const priv = self.private();
- if (priv.mouse_hover_url) |v| glib.free(@constCast(@ptrCast(v)));
+ if (priv.mouse_hover_url) |v| glib.free(@ptrCast(@constCast(v)));
priv.mouse_hover_url = null;
if (url) |v| priv.mouse_hover_url = glib.ext.dupeZ(u8, v);
self.as(gobject.Object).notifyByPspec(properties.@"mouse-hover-url".impl.param_spec);
@@ -2117,13 +2115,11 @@ pub const Surface = extern struct {
const alloc = Application.default().allocator();
if (ext.gValueHolds(value, gdk.FileList.getGObjectType())) {
- var data = std.ArrayList(u8).init(alloc);
- defer data.deinit();
+ var stream: std.Io.Writer.Allocating = .init(alloc);
+ defer stream.deinit();
- var shell_escape_writer: internal_os.ShellEscapeWriter(std.ArrayList(u8).Writer) = .{
- .child_writer = data.writer(),
- };
- const writer = shell_escape_writer.writer();
+ var shell_escape_writer: internal_os.ShellEscapeWriter = .init(&stream.writer);
+ const writer = &shell_escape_writer.writer;
const list: ?*glib.SList = list: {
const unboxed = value.getBoxed() orelse return 0;
@@ -2151,7 +2147,7 @@ pub const Surface = extern struct {
}
}
- const string = data.toOwnedSliceSentinel(0) catch |err| {
+ const string = stream.toOwnedSliceSentinel(0) catch |err| {
log.err("unable to convert to a slice: {}", .{err});
return 0;
};
@@ -2164,13 +2160,11 @@ pub const Surface = extern struct {
const object = value.getObject() orelse return 0;
const file = gobject.ext.cast(gio.File, object) orelse return 0;
const path = file.getPath() orelse return 0;
- var data = std.ArrayList(u8).init(alloc);
- defer data.deinit();
+ var stream: std.Io.Writer.Allocating = .init(alloc);
+ defer stream.deinit();
- var shell_escape_writer: internal_os.ShellEscapeWriter(std.ArrayList(u8).Writer) = .{
- .child_writer = data.writer(),
- };
- const writer = shell_escape_writer.writer();
+ var shell_escape_writer: internal_os.ShellEscapeWriter = .init(&stream.writer);
+ const writer = &shell_escape_writer.writer;
writer.writeAll(std.mem.span(path)) catch |err| {
log.err("unable to write path to buffer: {}", .{err});
return 0;
@@ -2180,7 +2174,7 @@ pub const Surface = extern struct {
return 0;
};
- const string = data.toOwnedSliceSentinel(0) catch |err| {
+ const string = stream.toOwnedSliceSentinel(0) catch |err| {
log.err("unable to convert to a slice: {}", .{err});
return 0;
};
diff --git a/src/apprt/gtk/class/surface_title_dialog.zig b/src/apprt/gtk/class/surface_title_dialog.zig
index de36f3090..6d3bf33de 100644
--- a/src/apprt/gtk/class/surface_title_dialog.zig
+++ b/src/apprt/gtk/class/surface_title_dialog.zig
@@ -136,7 +136,7 @@ pub const SurfaceTitleDialog = extern struct {
fn finalize(self: *Self) callconv(.c) void {
const priv = self.private();
if (priv.initial_value) |v| {
- glib.free(@constCast(@ptrCast(v)));
+ glib.free(@ptrCast(@constCast(v)));
priv.initial_value = null;
}
diff --git a/src/apprt/gtk/class/tab.zig b/src/apprt/gtk/class/tab.zig
index 373507507..941fa00a9 100644
--- a/src/apprt/gtk/class/tab.zig
+++ b/src/apprt/gtk/class/tab.zig
@@ -270,11 +270,11 @@ pub const Tab = extern struct {
fn finalize(self: *Self) callconv(.c) void {
const priv = self.private();
if (priv.tooltip) |v| {
- glib.free(@constCast(@ptrCast(v)));
+ glib.free(@ptrCast(@constCast(v)));
priv.tooltip = null;
}
if (priv.title) |v| {
- glib.free(@constCast(@ptrCast(v)));
+ glib.free(@ptrCast(@constCast(v)));
priv.title = null;
}
@@ -405,22 +405,21 @@ pub const Tab = extern struct {
};
// Use an allocator to build up our string as we write it.
- var buf: std.ArrayList(u8) = .init(Application.default().allocator());
+ var buf: std.Io.Writer.Allocating = .init(Application.default().allocator());
defer buf.deinit();
- const writer = buf.writer();
// If our bell is ringing, then we prefix the bell icon to the title.
if (bell_ringing and config.@"bell-features".title) {
- writer.writeAll("🔔 ") catch {};
+ buf.writer.writeAll("🔔 ") catch {};
}
// If we're zoomed, prefix with the magnifying glass emoji.
if (zoomed) {
- writer.writeAll("🔍 ") catch {};
+ buf.writer.writeAll("🔍 ") catch {};
}
- writer.writeAll(plain) catch return glib.ext.dupeZ(u8, plain);
- return glib.ext.dupeZ(u8, buf.items);
+ buf.writer.writeAll(plain) catch return glib.ext.dupeZ(u8, plain);
+ return glib.ext.dupeZ(u8, buf.written());
}
const C = Common(Self, Private);
diff --git a/src/apprt/gtk/gtk_version.zig b/src/apprt/gtk/gtk_version.zig
index 6f3d733a5..71edb076d 100644
--- a/src/apprt/gtk/gtk_version.zig
+++ b/src/apprt/gtk/gtk_version.zig
@@ -26,7 +26,7 @@ pub fn getRuntimeVersion() std.SemanticVersion {
}
pub fn logVersion() void {
- log.info("GTK version build={} runtime={}", .{
+ log.info("GTK version build={f} runtime={f}", .{
comptime_version,
getRuntimeVersion(),
});
diff --git a/src/apprt/gtk/ipc/DBus.zig b/src/apprt/gtk/ipc/DBus.zig
index d14d86ce6..fa4a6723e 100644
--- a/src/apprt/gtk/ipc/DBus.zig
+++ b/src/apprt/gtk/ipc/DBus.zig
@@ -29,7 +29,10 @@ payload_builder: *glib.VariantBuilder,
parameters_builder: *glib.VariantBuilder,
/// Initialize the helper.
-pub fn init(alloc: Allocator, target: apprt.ipc.Target, action: [:0]const u8) (Allocator.Error || std.posix.WriteError || apprt.ipc.Errors)!Self {
+pub fn init(alloc: Allocator, target: apprt.ipc.Target, action: [:0]const u8) (Allocator.Error || std.Io.Writer.Error || apprt.ipc.Errors)!Self {
+ var buf: [256]u8 = undefined;
+ var stderr_writer = std.fs.File.stderr().writer(&buf);
+ const stderr = &stderr_writer.interface;
// Get the appropriate bus name and object path for contacting the
// Ghostty instance we're interested in.
@@ -37,7 +40,7 @@ pub fn init(alloc: Allocator, target: apprt.ipc.Target, action: [:0]const u8) (A
.class => |class| result: {
// Force the usage of the class specified on the CLI to determine the
// bus name and object path.
- const object_path = try std.fmt.allocPrintZ(alloc, "/{s}", .{class});
+ const object_path = try std.fmt.allocPrintSentinel(alloc, "/{s}", .{class}, 0);
std.mem.replaceScalar(u8, object_path, '.', '/');
std.mem.replaceScalar(u8, object_path, '-', '_');
@@ -54,14 +57,14 @@ pub fn init(alloc: Allocator, target: apprt.ipc.Target, action: [:0]const u8) (A
}
if (gio.Application.idIsValid(bus_name.ptr) == 0) {
- const stderr = std.io.getStdErr().writer();
try stderr.print("D-Bus bus name is not valid: {s}\n", .{bus_name});
+ try stderr.flush();
return error.IPCFailed;
}
if (glib.Variant.isObjectPath(object_path.ptr) == 0) {
- const stderr = std.io.getStdErr().writer();
try stderr.print("D-Bus object path is not valid: {s}\n", .{object_path});
+ try stderr.flush();
return error.IPCFailed;
}
@@ -72,17 +75,17 @@ pub fn init(alloc: Allocator, target: apprt.ipc.Target, action: [:0]const u8) (A
const dbus_ = gio.busGetSync(.session, null, &err_);
if (err_) |err| {
- const stderr = std.io.getStdErr().writer();
try stderr.print(
"Unable to establish connection to D-Bus session bus: {s}\n",
.{err.f_message orelse "(unknown)"},
);
+ try stderr.flush();
return error.IPCFailed;
}
break :dbus dbus_ orelse {
- const stderr = std.io.getStdErr().writer();
try stderr.print("gio.busGetSync returned null\n", .{});
+ try stderr.flush();
return error.IPCFailed;
};
};
@@ -128,7 +131,11 @@ pub fn addParameter(self: *Self, variant: *glib.Variant) void {
/// Send the IPC to the remote Ghostty. Once it completes, nothing further
/// should be done with this object other than call `deinit`.
-pub fn send(self: *Self) (std.posix.WriteError || apprt.ipc.Errors)!void {
+pub fn send(self: *Self) (std.Io.Writer.Error || apprt.ipc.Errors)!void {
+ var buf: [256]u8 = undefined;
+ var stderr_writer = std.fs.File.stderr().writer(&buf);
+ const stderr = &stderr_writer.interface;
+
// finish building the parameters
const parameters = self.parameters_builder.end();
@@ -167,11 +174,11 @@ pub fn send(self: *Self) (std.posix.WriteError || apprt.ipc.Errors)!void {
defer if (result_) |result| result.unref();
if (err_) |err| {
- const stderr = std.io.getStdErr().writer();
try stderr.print(
"D-Bus method call returned an error err={s}\n",
.{err.f_message orelse "(unknown)"},
);
+ try stderr.flush();
return error.IPCFailed;
}
}
diff --git a/src/apprt/gtk/ipc/new_window.zig b/src/apprt/gtk/ipc/new_window.zig
index 55e2e0e01..19c46e3aa 100644
--- a/src/apprt/gtk/ipc/new_window.zig
+++ b/src/apprt/gtk/ipc/new_window.zig
@@ -20,7 +20,7 @@ const DBus = @import("DBus.zig");
// ```
// gdbus call --session --dest com.mitchellh.ghostty --object-path /com/mitchellh/ghostty --method org.gtk.Actions.Activate new-window-command '[<@as ["echo" "hello"]>]' []
// ```
-pub fn newWindow(alloc: Allocator, target: apprt.ipc.Target, value: apprt.ipc.Action.NewWindow) (Allocator.Error || std.posix.WriteError || apprt.ipc.Errors)!bool {
+pub fn newWindow(alloc: Allocator, target: apprt.ipc.Target, value: apprt.ipc.Action.NewWindow) (Allocator.Error || std.Io.Writer.Error || apprt.ipc.Errors)!bool {
var dbus = try DBus.init(
alloc,
target,
diff --git a/src/apprt/gtk/key.zig b/src/apprt/gtk/key.zig
index a00b0312e..bf0f0e2f6 100644
--- a/src/apprt/gtk/key.zig
+++ b/src/apprt/gtk/key.zig
@@ -12,9 +12,8 @@ const winproto = @import("winproto.zig");
pub fn accelFromTrigger(
buf: []u8,
trigger: input.Binding.Trigger,
-) error{NoSpaceLeft}!?[:0]const u8 {
- var buf_stream = std.io.fixedBufferStream(buf);
- const writer = buf_stream.writer();
+) error{WriteFailed}!?[:0]const u8 {
+ var writer: std.Io.Writer = .fixed(buf);
// Modifiers
if (trigger.mods.shift) try writer.writeAll("");
@@ -23,11 +22,11 @@ pub fn accelFromTrigger(
if (trigger.mods.super) try writer.writeAll("");
// Write our key
- if (!try writeTriggerKey(writer, trigger)) return null;
+ if (!try writeTriggerKey(&writer, trigger)) return null;
// We need to make the string null terminated.
try writer.writeByte(0);
- const slice = buf_stream.getWritten();
+ const slice = writer.buffered();
return slice[0 .. slice.len - 1 :0];
}
@@ -36,9 +35,8 @@ pub fn accelFromTrigger(
pub fn xdgShortcutFromTrigger(
buf: []u8,
trigger: input.Binding.Trigger,
-) error{NoSpaceLeft}!?[:0]const u8 {
- var buf_stream = std.io.fixedBufferStream(buf);
- const writer = buf_stream.writer();
+) error{WriteFailed}!?[:0]const u8 {
+ var writer: std.Io.Writer = .fixed(buf);
// Modifiers
if (trigger.mods.shift) try writer.writeAll("SHIFT+");
@@ -52,15 +50,18 @@ pub fn xdgShortcutFromTrigger(
// to *X11's* keysyms (which I assume is a subset of libxkbcommon's).
// I haven't been able to any evidence to back up that assumption but
// this works for now
- if (!try writeTriggerKey(writer, trigger)) return null;
+ if (!try writeTriggerKey(&writer, trigger)) return null;
// We need to make the string null terminated.
try writer.writeByte(0);
- const slice = buf_stream.getWritten();
+ const slice = writer.buffered();
return slice[0 .. slice.len - 1 :0];
}
-fn writeTriggerKey(writer: anytype, trigger: input.Binding.Trigger) error{NoSpaceLeft}!bool {
+fn writeTriggerKey(
+ writer: *std.Io.Writer,
+ trigger: input.Binding.Trigger,
+) error{WriteFailed}!bool {
switch (trigger.key) {
.physical => |k| {
const keyval = keyvalFromKey(k) orelse return false;
diff --git a/src/benchmark/CodepointWidth.zig b/src/benchmark/CodepointWidth.zig
index 9bbc2def7..552df8d1f 100644
--- a/src/benchmark/CodepointWidth.zig
+++ b/src/benchmark/CodepointWidth.zig
@@ -10,7 +10,6 @@ const assert = std.debug.assert;
const Allocator = std.mem.Allocator;
const Benchmark = @import("Benchmark.zig");
const options = @import("options.zig");
-const uucode = @import("uucode");
const UTF8Decoder = @import("../terminal/UTF8Decoder.zig");
const simd = @import("../simd/main.zig");
const table = @import("../unicode/main.zig").table;
@@ -48,9 +47,6 @@ pub const Mode = enum {
/// Test our lookup table implementation.
table,
-
- /// Using uucode, with custom `width` extension based on `wcwidth`.
- uucode,
};
/// Create a new terminal stream handler for the given arguments.
@@ -75,7 +71,6 @@ pub fn benchmark(self: *CodepointWidth) Benchmark {
.wcwidth => stepWcwidth,
.table => stepTable,
.simd => stepSimd,
- .uucode => stepUucode,
},
.setupFn = setup,
.teardownFn = teardown,
@@ -112,12 +107,15 @@ fn stepWcwidth(ptr: *anyopaque) Benchmark.Error!void {
const self: *CodepointWidth = @ptrCast(@alignCast(ptr));
const f = self.data_f orelse return;
- var r = std.io.bufferedReader(f.reader());
+ var read_buf: [4096]u8 = undefined;
+ var f_reader = f.reader(&read_buf);
+ var r = &f_reader.interface;
+
var d: UTF8Decoder = .{};
var buf: [4096]u8 align(std.atomic.cache_line) = undefined;
while (true) {
- const n = r.read(&buf) catch |err| {
- log.warn("error reading data file err={}", .{err});
+ const n = r.readSliceShort(&buf) catch {
+ log.warn("error reading data file err={?}", .{f_reader.err});
return error.BenchmarkFailed;
};
if (n == 0) break; // EOF reached
@@ -136,12 +134,15 @@ fn stepTable(ptr: *anyopaque) Benchmark.Error!void {
const self: *CodepointWidth = @ptrCast(@alignCast(ptr));
const f = self.data_f orelse return;
- var r = std.io.bufferedReader(f.reader());
+ var read_buf: [4096]u8 = undefined;
+ var f_reader = f.reader(&read_buf);
+ var r = &f_reader.interface;
+
var d: UTF8Decoder = .{};
var buf: [4096]u8 align(std.atomic.cache_line) = undefined;
while (true) {
- const n = r.read(&buf) catch |err| {
- log.warn("error reading data file err={}", .{err});
+ const n = r.readSliceShort(&buf) catch {
+ log.warn("error reading data file err={?}", .{f_reader.err});
return error.BenchmarkFailed;
};
if (n == 0) break; // EOF reached
@@ -165,12 +166,15 @@ fn stepSimd(ptr: *anyopaque) Benchmark.Error!void {
const self: *CodepointWidth = @ptrCast(@alignCast(ptr));
const f = self.data_f orelse return;
- var r = std.io.bufferedReader(f.reader());
+ var read_buf: [4096]u8 = undefined;
+ var f_reader = f.reader(&read_buf);
+ var r = &f_reader.interface;
+
var d: UTF8Decoder = .{};
var buf: [4096]u8 align(std.atomic.cache_line) = undefined;
while (true) {
- const n = r.read(&buf) catch |err| {
- log.warn("error reading data file err={}", .{err});
+ const n = r.readSliceShort(&buf) catch {
+ log.warn("error reading data file err={?}", .{f_reader.err});
return error.BenchmarkFailed;
};
if (n == 0) break; // EOF reached
@@ -185,35 +189,6 @@ fn stepSimd(ptr: *anyopaque) Benchmark.Error!void {
}
}
-fn stepUucode(ptr: *anyopaque) Benchmark.Error!void {
- const self: *CodepointWidth = @ptrCast(@alignCast(ptr));
-
- const f = self.data_f orelse return;
- var r = std.io.bufferedReader(f.reader());
- var d: UTF8Decoder = .{};
- var buf: [4096]u8 align(std.atomic.cache_line) = undefined;
- while (true) {
- const n = r.read(&buf) catch |err| {
- log.warn("error reading data file err={}", .{err});
- return error.BenchmarkFailed;
- };
- if (n == 0) break; // EOF reached
-
- for (buf[0..n]) |c| {
- const cp_, const consumed = d.next(c);
- assert(consumed);
- if (cp_) |cp| {
- // This is the same trick we do in terminal.zig so we
- // keep it here.
- std.mem.doNotOptimizeAway(if (cp <= 0xFF)
- 1
- else
- uucode.get(.width, @intCast(cp)));
- }
- }
- }
-}
-
test CodepointWidth {
const testing = std.testing;
const alloc = testing.allocator;
diff --git a/src/benchmark/GraphemeBreak.zig b/src/benchmark/GraphemeBreak.zig
index e576c71ef..a1b3380f0 100644
--- a/src/benchmark/GraphemeBreak.zig
+++ b/src/benchmark/GraphemeBreak.zig
@@ -8,7 +8,6 @@ const assert = std.debug.assert;
const Allocator = std.mem.Allocator;
const Benchmark = @import("Benchmark.zig");
const options = @import("options.zig");
-const uucode = @import("uucode");
const UTF8Decoder = @import("../terminal/UTF8Decoder.zig");
const unicode = @import("../unicode/main.zig");
@@ -39,9 +38,6 @@ pub const Mode = enum {
/// Ghostty's table-based approach.
table,
-
- /// uucode implementation
- uucode,
};
/// Create a new terminal stream handler for the given arguments.
@@ -64,7 +60,6 @@ pub fn benchmark(self: *GraphemeBreak) Benchmark {
.stepFn = switch (self.opts.mode) {
.noop => stepNoop,
.table => stepTable,
- .uucode => stepUucode,
},
.setupFn = setup,
.teardownFn = teardown,
@@ -95,12 +90,15 @@ fn stepNoop(ptr: *anyopaque) Benchmark.Error!void {
const self: *GraphemeBreak = @ptrCast(@alignCast(ptr));
const f = self.data_f orelse return;
- var r = std.io.bufferedReader(f.reader());
+ var read_buf: [4096]u8 = undefined;
+ var f_reader = f.reader(&read_buf);
+ var r = &f_reader.interface;
+
var d: UTF8Decoder = .{};
var buf: [4096]u8 align(std.atomic.cache_line) = undefined;
while (true) {
- const n = r.read(&buf) catch |err| {
- log.warn("error reading data file err={}", .{err});
+ const n = r.readSliceShort(&buf) catch {
+ log.warn("error reading data file err={?}", .{f_reader.err});
return error.BenchmarkFailed;
};
if (n == 0) break; // EOF reached
@@ -115,14 +113,17 @@ fn stepTable(ptr: *anyopaque) Benchmark.Error!void {
const self: *GraphemeBreak = @ptrCast(@alignCast(ptr));
const f = self.data_f orelse return;
- var r = std.io.bufferedReader(f.reader());
+ var read_buf: [4096]u8 = undefined;
+ var f_reader = f.reader(&read_buf);
+ var r = &f_reader.interface;
+
var d: UTF8Decoder = .{};
var state: unicode.GraphemeBreakState = .{};
var cp1: u21 = 0;
var buf: [4096]u8 align(std.atomic.cache_line) = undefined;
while (true) {
- const n = r.read(&buf) catch |err| {
- log.warn("error reading data file err={}", .{err});
+ const n = r.readSliceShort(&buf) catch {
+ log.warn("error reading data file err={?}", .{f_reader.err});
return error.BenchmarkFailed;
};
if (n == 0) break; // EOF reached
@@ -138,33 +139,6 @@ fn stepTable(ptr: *anyopaque) Benchmark.Error!void {
}
}
-fn stepUucode(ptr: *anyopaque) Benchmark.Error!void {
- const self: *GraphemeBreak = @ptrCast(@alignCast(ptr));
-
- const f = self.data_f orelse return;
- var r = std.io.bufferedReader(f.reader());
- var d: UTF8Decoder = .{};
- var state: uucode.grapheme.BreakState = .default;
- var cp1: u21 = 0;
- var buf: [4096]u8 align(std.atomic.cache_line) = undefined;
- while (true) {
- const n = r.read(&buf) catch |err| {
- log.warn("error reading data file err={}", .{err});
- return error.BenchmarkFailed;
- };
- if (n == 0) break; // EOF reached
-
- for (buf[0..n]) |c| {
- const cp_, const consumed = d.next(c);
- assert(consumed);
- if (cp_) |cp2| {
- std.mem.doNotOptimizeAway(uucode.grapheme.isBreak(cp1, @intCast(cp2), &state));
- cp1 = cp2;
- }
- }
- }
-}
-
test GraphemeBreak {
const testing = std.testing;
const alloc = testing.allocator;
diff --git a/src/benchmark/IsSymbol.zig b/src/benchmark/IsSymbol.zig
index 97af0657a..dffa5071a 100644
--- a/src/benchmark/IsSymbol.zig
+++ b/src/benchmark/IsSymbol.zig
@@ -90,7 +90,8 @@ fn stepUucode(ptr: *anyopaque) Benchmark.Error!void {
const self: *IsSymbol = @ptrCast(@alignCast(ptr));
const f = self.data_f orelse return;
- var r = std.io.bufferedReader(f.reader());
+ var read_buf: [4096]u8 = undefined;
+ var r = f.reader(&read_buf);
var d: UTF8Decoder = .{};
var buf: [4096]u8 align(std.atomic.cache_line) = undefined;
while (true) {
@@ -114,7 +115,8 @@ fn stepTable(ptr: *anyopaque) Benchmark.Error!void {
const self: *IsSymbol = @ptrCast(@alignCast(ptr));
const f = self.data_f orelse return;
- var r = std.io.bufferedReader(f.reader());
+ var read_buf: [4096]u8 = undefined;
+ var r = f.reader(&read_buf);
var d: UTF8Decoder = .{};
var buf: [4096]u8 align(std.atomic.cache_line) = undefined;
while (true) {
diff --git a/src/benchmark/TerminalParser.zig b/src/benchmark/TerminalParser.zig
index 3065c1ed6..f13b44552 100644
--- a/src/benchmark/TerminalParser.zig
+++ b/src/benchmark/TerminalParser.zig
@@ -75,14 +75,16 @@ fn step(ptr: *anyopaque) Benchmark.Error!void {
// the benchmark results and... I know writing this that we
// aren't currently IO bound.
const f = self.data_f orelse return;
- var r = std.io.bufferedReader(f.reader());
+ var read_buf: [4096]u8 = undefined;
+ var f_reader = f.reader(&read_buf);
+ var r = &f_reader.interface;
var p: terminalpkg.Parser = .init();
- var buf: [4096]u8 align(std.atomic.cache_line) = undefined;
+ var buf: [4096]u8 = undefined;
while (true) {
- const n = r.read(&buf) catch |err| {
- log.warn("error reading data file err={}", .{err});
+ const n = r.readSliceShort(&buf) catch {
+ log.warn("error reading data file err={?}", .{f_reader.err});
return error.BenchmarkFailed;
};
if (n == 0) break; // EOF reached
diff --git a/src/benchmark/TerminalStream.zig b/src/benchmark/TerminalStream.zig
index 71ab1fdfc..ecce509f3 100644
--- a/src/benchmark/TerminalStream.zig
+++ b/src/benchmark/TerminalStream.zig
@@ -113,17 +113,19 @@ fn step(ptr: *anyopaque) Benchmark.Error!void {
// the benchmark results and... I know writing this that we
// aren't currently IO bound.
const f = self.data_f orelse return;
- var r = std.io.bufferedReader(f.reader());
- var buf: [4096]u8 align(std.atomic.cache_line) = undefined;
+ var read_buf: [4096]u8 = undefined;
+ var f_reader = f.reader(&read_buf);
+ const r = &f_reader.interface;
+
+ var buf: [4096]u8 = undefined;
while (true) {
- const n = r.read(&buf) catch |err| {
- log.warn("error reading data file err={}", .{err});
+ const n = r.readSliceShort(&buf) catch {
+ log.warn("error reading data file err={?}", .{f_reader.err});
return error.BenchmarkFailed;
};
if (n == 0) break; // EOF reached
- const chunk = buf[0..n];
- self.stream.nextSlice(chunk) catch |err| {
+ self.stream.nextSlice(buf[0..n]) catch |err| {
log.warn("error processing data file chunk err={}", .{err});
return error.BenchmarkFailed;
};
diff --git a/src/benchmark/options.zig b/src/benchmark/options.zig
index 867be6afc..049e80f48 100644
--- a/src/benchmark/options.zig
+++ b/src/benchmark/options.zig
@@ -10,7 +10,7 @@ pub fn dataFile(path_: ?[]const u8) !?std.fs.File {
const path = path_ orelse return null;
// Stdin
- if (std.mem.eql(u8, path, "-")) return std.io.getStdIn();
+ if (std.mem.eql(u8, path, "-")) return .stdin();
// Normal file
const file = try std.fs.cwd().openFile(path, .{});
diff --git a/src/build/Config.zig b/src/build/Config.zig
index e0e81e519..643dfe928 100644
--- a/src/build/Config.zig
+++ b/src/build/Config.zig
@@ -477,7 +477,7 @@ pub fn addOptions(self: *const Config, step: *std.Build.Step.Options) !void {
step.addOption(std.SemanticVersion, "app_version", self.version);
step.addOption([:0]const u8, "app_version_string", try std.fmt.bufPrintZ(
&buf,
- "{}",
+ "{f}",
.{self.version},
));
step.addOption(
diff --git a/src/build/GhosttyBench.zig b/src/build/GhosttyBench.zig
index 5859a8bcf..c9cd5dd33 100644
--- a/src/build/GhosttyBench.zig
+++ b/src/build/GhosttyBench.zig
@@ -11,8 +11,8 @@ pub fn init(
b: *std.Build,
deps: *const SharedDeps,
) !GhosttyBench {
- var steps = std.ArrayList(*std.Build.Step.Compile).init(b.allocator);
- errdefer steps.deinit();
+ var steps: std.ArrayList(*std.Build.Step.Compile) = .empty;
+ errdefer steps.deinit(b.allocator);
// Our synthetic data generator
{
@@ -28,7 +28,7 @@ pub fn init(
});
exe.linkLibC();
_ = try deps.add(exe);
- try steps.append(exe);
+ try steps.append(b.allocator, exe);
}
// Our benchmarking application.
@@ -44,7 +44,7 @@ pub fn init(
});
exe.linkLibC();
_ = try deps.add(exe);
- try steps.append(exe);
+ try steps.append(b.allocator, exe);
}
return .{ .steps = steps.items };
diff --git a/src/build/GhosttyDist.zig b/src/build/GhosttyDist.zig
index f8c221350..092322689 100644
--- a/src/build/GhosttyDist.zig
+++ b/src/build/GhosttyDist.zig
@@ -43,10 +43,10 @@ pub fn init(b: *std.Build, cfg: *const Config) !GhosttyDist {
// embed the Ghostty version in the tarball
{
- const version = b.addWriteFiles().add("VERSION", b.fmt("{}", .{cfg.version}));
+ const version = b.addWriteFiles().add("VERSION", b.fmt("{f}", .{cfg.version}));
// --add-file uses the most recent --prefix to determine the path
// in the archive to copy the file (the directory only).
- git_archive.addArg(b.fmt("--prefix=ghostty-{}/", .{
+ git_archive.addArg(b.fmt("--prefix=ghostty-{f}/", .{
cfg.version,
}));
git_archive.addPrefixedFileArg("--add-file=", version);
@@ -65,7 +65,7 @@ pub fn init(b: *std.Build, cfg: *const Config) !GhosttyDist {
// --add-file uses the most recent --prefix to determine the path
// in the archive to copy the file (the directory only).
- git_archive.addArg(b.fmt("--prefix=ghostty-{}/{s}/", .{
+ git_archive.addArg(b.fmt("--prefix=ghostty-{f}/{s}/", .{
cfg.version,
std.fs.path.dirname(resource.dist).?,
}));
@@ -77,11 +77,11 @@ pub fn init(b: *std.Build, cfg: *const Config) !GhosttyDist {
// This is important. Standard source tarballs extract into
// a directory named `project-version`. This is expected by
// standard tooling such as debhelper and rpmbuild.
- b.fmt("--prefix=ghostty-{}/", .{cfg.version}),
+ b.fmt("--prefix=ghostty-{f}/", .{cfg.version}),
"-o",
});
const output = git_archive.addOutputFileArg(b.fmt(
- "ghostty-{}.tar.gz",
+ "ghostty-{f}.tar.gz",
.{cfg.version},
));
git_archive.addArg("HEAD");
@@ -89,7 +89,7 @@ pub fn init(b: *std.Build, cfg: *const Config) !GhosttyDist {
// The install step to put the dist into the build directory.
const install = b.addInstallFile(
output,
- b.fmt("dist/ghostty-{}.tar.gz", .{cfg.version}),
+ b.fmt("dist/ghostty-{f}.tar.gz", .{cfg.version}),
);
// The check step to ensure the archive works.
@@ -101,7 +101,7 @@ pub fn init(b: *std.Build, cfg: *const Config) !GhosttyDist {
// i.e. this is way `build.zig` is.
const extract_dir = check
.addOutputDirectoryArg("ghostty")
- .path(b, b.fmt("ghostty-{}", .{cfg.version}));
+ .path(b, b.fmt("ghostty-{f}", .{cfg.version}));
// Check that tests pass within the extracted directory. This isn't
// a fully hermetic test because we're sharing the Zig cache. In
diff --git a/src/build/GhosttyDocs.zig b/src/build/GhosttyDocs.zig
index b95b56f74..cd75fc061 100644
--- a/src/build/GhosttyDocs.zig
+++ b/src/build/GhosttyDocs.zig
@@ -12,8 +12,8 @@ pub fn init(
b: *std.Build,
deps: *const SharedDeps,
) !GhosttyDocs {
- var steps = std.ArrayList(*std.Build.Step).init(b.allocator);
- errdefer steps.deinit();
+ var steps: std.ArrayList(*std.Build.Step) = .empty;
+ errdefer steps.deinit(b.allocator);
const manpages = [_]struct {
name: []const u8,
@@ -52,7 +52,7 @@ pub fn init(
const generate_markdown_step = b.addRunArtifact(generate_markdown);
const markdown_output = generate_markdown_step.captureStdOut();
- try steps.append(&b.addInstallFile(
+ try steps.append(b.allocator, &b.addInstallFile(
markdown_output,
"share/ghostty/doc/" ++ manpage.name ++ "." ++ manpage.section ++ ".md",
).step);
@@ -67,7 +67,7 @@ pub fn init(
});
generate_html.addFileArg(markdown_output);
- try steps.append(&b.addInstallFile(
+ try steps.append(b.allocator, &b.addInstallFile(
generate_html.captureStdOut(),
"share/ghostty/doc/" ++ manpage.name ++ "." ++ manpage.section ++ ".html",
).step);
@@ -82,7 +82,7 @@ pub fn init(
});
generate_manpage.addFileArg(markdown_output);
- try steps.append(&b.addInstallFile(
+ try steps.append(b.allocator, &b.addInstallFile(
generate_manpage.captureStdOut(),
"share/man/man" ++ manpage.section ++ "/" ++ manpage.name ++ "." ++ manpage.section,
).step);
diff --git a/src/build/GhosttyExe.zig b/src/build/GhosttyExe.zig
index 083aecdb5..3e63b6026 100644
--- a/src/build/GhosttyExe.zig
+++ b/src/build/GhosttyExe.zig
@@ -21,6 +21,8 @@ pub fn init(b: *std.Build, cfg: *const Config, deps: *const SharedDeps) !Ghostty
.omit_frame_pointer = cfg.strip,
.unwind_tables = if (cfg.strip) .none else .sync,
}),
+ // Crashes on x86_64 self-hosted on 0.15.1
+ .use_llvm = true,
});
const install_step = b.addInstallArtifact(exe, .{});
diff --git a/src/build/GhosttyFrameData.zig b/src/build/GhosttyFrameData.zig
index 52c84a66c..def1dbdb3 100644
--- a/src/build/GhosttyFrameData.zig
+++ b/src/build/GhosttyFrameData.zig
@@ -40,7 +40,10 @@ pub fn distResources(b: *std.Build) struct {
} {
const exe = b.addExecutable(.{
.name = "framegen",
- .target = b.graph.host,
+ .root_module = b.createModule(.{
+ .target = b.graph.host,
+ }),
+ .use_llvm = true,
});
exe.addCSourceFile(.{
.file = b.path("src/build/framegen/main.c"),
diff --git a/src/build/GhosttyI18n.zig b/src/build/GhosttyI18n.zig
index b99e60426..8e31f61b3 100644
--- a/src/build/GhosttyI18n.zig
+++ b/src/build/GhosttyI18n.zig
@@ -18,8 +18,8 @@ update_step: *std.Build.Step,
pub fn init(b: *std.Build, cfg: *const Config) !GhosttyI18n {
_ = cfg;
- var steps = std.ArrayList(*std.Build.Step).init(b.allocator);
- defer steps.deinit();
+ var steps: std.ArrayList(*std.Build.Step) = .empty;
+ defer steps.deinit(b.allocator);
inline for (locales) |locale| {
// There is no encoding suffix in the LC_MESSAGES path on FreeBSD,
@@ -33,7 +33,7 @@ pub fn init(b: *std.Build, cfg: *const Config) !GhosttyI18n {
const msgfmt = b.addSystemCommand(&.{ "msgfmt", "-o", "-" });
msgfmt.addFileArg(b.path("po/" ++ locale ++ ".po"));
- try steps.append(&b.addInstallFile(
+ try steps.append(b.allocator, &b.addInstallFile(
msgfmt.captureStdOut(),
std.fmt.comptimePrint(
"share/locale/{s}/LC_MESSAGES/{s}.mo",
@@ -45,7 +45,7 @@ pub fn init(b: *std.Build, cfg: *const Config) !GhosttyI18n {
return .{
.owner = b,
.update_step = try createUpdateStep(b),
- .steps = try steps.toOwnedSlice(),
+ .steps = try steps.toOwnedSlice(b.allocator),
};
}
diff --git a/src/build/GhosttyLib.zig b/src/build/GhosttyLib.zig
index b244a72c5..2ac383544 100644
--- a/src/build/GhosttyLib.zig
+++ b/src/build/GhosttyLib.zig
@@ -28,7 +28,9 @@ pub fn initStatic(
.omit_frame_pointer = deps.config.strip,
.unwind_tables = if (deps.config.strip) .none else .sync,
}),
- .linkage = .static,
+
+ // Fails on self-hosted x86_64 on macOS
+ .use_llvm = true,
});
lib.linkLibC();
@@ -40,7 +42,7 @@ pub fn initStatic(
// Add our dependencies. Get the list of all static deps so we can
// build a combined archive if necessary.
var lib_list = try deps.add(lib);
- try lib_list.append(lib.getEmittedBin());
+ try lib_list.append(b.allocator, lib.getEmittedBin());
if (!deps.config.target.result.os.tag.isDarwin()) return .{
.step = &lib.step,
@@ -69,8 +71,9 @@ pub fn initShared(
b: *std.Build,
deps: *const SharedDeps,
) !GhosttyLib {
- const lib = b.addSharedLibrary(.{
+ const lib = b.addLibrary(.{
.name = "ghostty",
+ .linkage = .dynamic,
.root_module = b.createModule(.{
.root_source_file = b.path("src/main_c.zig"),
.target = deps.config.target,
@@ -79,6 +82,9 @@ pub fn initShared(
.omit_frame_pointer = deps.config.strip,
.unwind_tables = if (deps.config.strip) .none else .sync,
}),
+
+ // Fails on self-hosted x86_64
+ .use_llvm = true,
});
_ = try deps.add(lib);
diff --git a/src/build/GhosttyLibVt.zig b/src/build/GhosttyLibVt.zig
index 9eb945293..1e57da7b1 100644
--- a/src/build/GhosttyLibVt.zig
+++ b/src/build/GhosttyLibVt.zig
@@ -24,8 +24,9 @@ pub fn initShared(
zig: *const GhosttyZig,
) !GhosttyLibVt {
const target = zig.vt.resolved_target.?;
- const lib = b.addSharedLibrary(.{
+ const lib = b.addLibrary(.{
.name = "ghostty-vt",
+ .linkage = .dynamic,
.root_module = zig.vt_c,
.version = std.SemanticVersion{ .major = 0, .minor = 1, .patch = 0 },
});
diff --git a/src/build/GhosttyResources.zig b/src/build/GhosttyResources.zig
index 0db1fd418..7880a98a0 100644
--- a/src/build/GhosttyResources.zig
+++ b/src/build/GhosttyResources.zig
@@ -10,8 +10,8 @@ const RunStep = std.Build.Step.Run;
steps: []*std.Build.Step,
pub fn init(b: *std.Build, cfg: *const Config) !GhosttyResources {
- var steps = std.ArrayList(*std.Build.Step).init(b.allocator);
- errdefer steps.deinit();
+ var steps: std.ArrayList(*std.Build.Step) = .empty;
+ errdefer steps.deinit(b.allocator);
// This is the exe used to generate some build data.
const build_data_exe = b.addExecutable(.{
@@ -49,7 +49,7 @@ pub fn init(b: *std.Build, cfg: *const Config) !GhosttyResources {
"share/terminfo/ghostty.terminfo",
);
- try steps.append(&source_install.step);
+ try steps.append(b.allocator, &source_install.step);
}
// Windows doesn't have the binaries below.
@@ -73,7 +73,7 @@ pub fn init(b: *std.Build, cfg: *const Config) !GhosttyResources {
"share/terminfo/ghostty.termcap",
);
- try steps.append(&cap_install.step);
+ try steps.append(b.allocator, &cap_install.step);
}
// Compile the terminfo source into a terminfo database
@@ -99,7 +99,7 @@ pub fn init(b: *std.Build, cfg: *const Config) !GhosttyResources {
.{ b.install_path, terminfo_share_dir },
));
- try steps.append(&mkdir_step.step);
+ try steps.append(b.allocator, &mkdir_step.step);
// Use cp -R instead of Step.InstallDir because we need to preserve
// symlinks in the terminfo database. Zig's InstallDir step doesn't
@@ -109,7 +109,7 @@ pub fn init(b: *std.Build, cfg: *const Config) !GhosttyResources {
copy_step.addFileArg(path);
copy_step.addArg(b.fmt("{s}/share", .{b.install_path}));
copy_step.step.dependOn(&mkdir_step.step);
- try steps.append(©_step.step);
+ try steps.append(b.allocator, ©_step.step);
}
}
@@ -121,7 +121,7 @@ pub fn init(b: *std.Build, cfg: *const Config) !GhosttyResources {
.install_subdir = b.pathJoin(&.{ "ghostty", "shell-integration" }),
.exclude_extensions = &.{".md"},
});
- try steps.append(&install_step.step);
+ try steps.append(b.allocator, &install_step.step);
}
// Themes
@@ -132,7 +132,7 @@ pub fn init(b: *std.Build, cfg: *const Config) !GhosttyResources {
.install_subdir = b.pathJoin(&.{ "ghostty", "themes" }),
.exclude_extensions = &.{".md"},
});
- try steps.append(&install_step.step);
+ try steps.append(b.allocator, &install_step.step);
}
// Fish shell completions
@@ -147,7 +147,7 @@ pub fn init(b: *std.Build, cfg: *const Config) !GhosttyResources {
.install_dir = .prefix,
.install_subdir = "share/fish/vendor_completions.d",
});
- try steps.append(&install_step.step);
+ try steps.append(b.allocator, &install_step.step);
}
// zsh shell completions
@@ -162,7 +162,7 @@ pub fn init(b: *std.Build, cfg: *const Config) !GhosttyResources {
.install_dir = .prefix,
.install_subdir = "share/zsh/site-functions",
});
- try steps.append(&install_step.step);
+ try steps.append(b.allocator, &install_step.step);
}
// bash shell completions
@@ -177,7 +177,7 @@ pub fn init(b: *std.Build, cfg: *const Config) !GhosttyResources {
.install_dir = .prefix,
.install_subdir = "share/bash-completion/completions",
});
- try steps.append(&install_step.step);
+ try steps.append(b.allocator, &install_step.step);
}
// Vim and Neovim plugin
@@ -210,14 +210,14 @@ pub fn init(b: *std.Build, cfg: *const Config) !GhosttyResources {
.install_dir = .prefix,
.install_subdir = "share/vim/vimfiles",
});
- try steps.append(&vim_step.step);
+ try steps.append(b.allocator, &vim_step.step);
const neovim_step = b.addInstallDirectory(.{
.source_dir = wf.getDirectory(),
.install_dir = .prefix,
.install_subdir = "share/nvim/site",
});
- try steps.append(&neovim_step.step);
+ try steps.append(b.allocator, &neovim_step.step);
}
// Sublime syntax highlighting for bat cli tool
@@ -237,7 +237,7 @@ pub fn init(b: *std.Build, cfg: *const Config) !GhosttyResources {
.install_dir = .prefix,
.install_subdir = "share/bat/syntaxes",
});
- try steps.append(&install_step.step);
+ try steps.append(b.allocator, &install_step.step);
}
// App (Linux)
@@ -286,16 +286,17 @@ fn addLinuxAppResources(
// second element of the tuple.
const Template = struct { std.Build.LazyPath, []const u8 };
const templates: []const Template = templates: {
- var ts: std.ArrayList(Template) = .init(b.allocator);
+ var ts: std.ArrayList(Template) = .empty;
+ defer ts.deinit(b.allocator);
// Desktop file so that we have an icon and other metadata
- try ts.append(.{
+ try ts.append(b.allocator, .{
b.path("dist/linux/app.desktop.in"),
b.fmt("share/applications/{s}.desktop", .{app_id}),
});
// Service for DBus activation.
- try ts.append(.{
+ try ts.append(b.allocator, .{
if (cfg.flatpak)
b.path("dist/linux/dbus.service.flatpak.in")
else
@@ -320,7 +321,7 @@ fn addLinuxAppResources(
// See the following code:
//
// https://github.com/flatpak/xdg-desktop-portal/blob/7d4d48cf079147c8887da17ec6c3954acd5a285c/src/xdp-utils.c#L152-L220
- if (!cfg.flatpak) try ts.append(.{
+ if (!cfg.flatpak) try ts.append(b.allocator, .{
b.path("dist/linux/systemd.service.in"),
b.fmt(
"{s}/systemd/user/app-{s}.service",
@@ -333,12 +334,12 @@ fn addLinuxAppResources(
// AppStream metainfo so that application has rich metadata
// within app stores
- try ts.append(.{
+ try ts.append(b.allocator, .{
b.path("dist/linux/com.mitchellh.ghostty.metainfo.xml.in"),
b.fmt("share/metainfo/{s}.metainfo.xml", .{app_id}),
});
- break :templates ts.items;
+ break :templates try ts.toOwnedSlice(b.allocator);
};
// Process all our templates
@@ -361,65 +362,65 @@ fn addLinuxAppResources(
template[1],
);
- try steps.append(©.step);
+ try steps.append(b.allocator, ©.step);
}
// Right click menu action for Plasma desktop
- try steps.append(&b.addInstallFile(
+ try steps.append(b.allocator, &b.addInstallFile(
b.path("dist/linux/ghostty_dolphin.desktop"),
"share/kio/servicemenus/com.mitchellh.ghostty.desktop",
).step);
// Right click menu action for Nautilus. Note that this _must_ be named
// `ghostty.py`. Using the full app id causes problems (see #5468).
- try steps.append(&b.addInstallFile(
+ try steps.append(b.allocator, &b.addInstallFile(
b.path("dist/linux/ghostty_nautilus.py"),
"share/nautilus-python/extensions/ghostty.py",
).step);
// Various icons that our application can use, including the icon
// that will be used for the desktop.
- try steps.append(&b.addInstallFile(
+ try steps.append(b.allocator, &b.addInstallFile(
b.path("images/gnome/16.png"),
"share/icons/hicolor/16x16/apps/com.mitchellh.ghostty.png",
).step);
- try steps.append(&b.addInstallFile(
+ try steps.append(b.allocator, &b.addInstallFile(
b.path("images/gnome/32.png"),
"share/icons/hicolor/32x32/apps/com.mitchellh.ghostty.png",
).step);
- try steps.append(&b.addInstallFile(
+ try steps.append(b.allocator, &b.addInstallFile(
b.path("images/gnome/128.png"),
"share/icons/hicolor/128x128/apps/com.mitchellh.ghostty.png",
).step);
- try steps.append(&b.addInstallFile(
+ try steps.append(b.allocator, &b.addInstallFile(
b.path("images/gnome/256.png"),
"share/icons/hicolor/256x256/apps/com.mitchellh.ghostty.png",
).step);
- try steps.append(&b.addInstallFile(
+ try steps.append(b.allocator, &b.addInstallFile(
b.path("images/gnome/512.png"),
"share/icons/hicolor/512x512/apps/com.mitchellh.ghostty.png",
).step);
// Flatpaks only support icons up to 512x512.
if (!cfg.flatpak) {
- try steps.append(&b.addInstallFile(
+ try steps.append(b.allocator, &b.addInstallFile(
b.path("images/gnome/1024.png"),
"share/icons/hicolor/1024x1024/apps/com.mitchellh.ghostty.png",
).step);
}
- try steps.append(&b.addInstallFile(
+ try steps.append(b.allocator, &b.addInstallFile(
b.path("images/gnome/32.png"),
"share/icons/hicolor/16x16@2/apps/com.mitchellh.ghostty.png",
).step);
- try steps.append(&b.addInstallFile(
+ try steps.append(b.allocator, &b.addInstallFile(
b.path("images/gnome/64.png"),
"share/icons/hicolor/32x32@2/apps/com.mitchellh.ghostty.png",
).step);
- try steps.append(&b.addInstallFile(
+ try steps.append(b.allocator, &b.addInstallFile(
b.path("images/gnome/256.png"),
"share/icons/hicolor/128x128@2/apps/com.mitchellh.ghostty.png",
).step);
- try steps.append(&b.addInstallFile(
+ try steps.append(b.allocator, &b.addInstallFile(
b.path("images/gnome/512.png"),
"share/icons/hicolor/256x256@2/apps/com.mitchellh.ghostty.png",
).step);
diff --git a/src/build/GhosttyWebdata.zig b/src/build/GhosttyWebdata.zig
index b0201c3ff..145bb91fa 100644
--- a/src/build/GhosttyWebdata.zig
+++ b/src/build/GhosttyWebdata.zig
@@ -12,8 +12,8 @@ pub fn init(
b: *std.Build,
deps: *const SharedDeps,
) !GhosttyWebdata {
- var steps = std.ArrayList(*std.Build.Step).init(b.allocator);
- errdefer steps.deinit();
+ var steps: std.ArrayList(*std.Build.Step) = .empty;
+ errdefer steps.deinit(b.allocator);
{
const webgen_config = b.addExecutable(.{
@@ -43,7 +43,7 @@ pub fn init(
const webgen_config_step = b.addRunArtifact(webgen_config);
const webgen_config_out = webgen_config_step.captureStdOut();
- try steps.append(&b.addInstallFile(
+ try steps.append(b.allocator, &b.addInstallFile(
webgen_config_out,
"share/ghostty/webdata/config.mdx",
).step);
@@ -52,8 +52,10 @@ pub fn init(
{
const webgen_actions = b.addExecutable(.{
.name = "webgen_actions",
- .root_source_file = b.path("src/main.zig"),
- .target = b.graph.host,
+ .root_module = b.createModule(.{
+ .root_source_file = b.path("src/main.zig"),
+ .target = b.graph.host,
+ }),
});
deps.help_strings.addImport(webgen_actions);
@@ -72,7 +74,7 @@ pub fn init(
const webgen_actions_step = b.addRunArtifact(webgen_actions);
const webgen_actions_out = webgen_actions_step.captureStdOut();
- try steps.append(&b.addInstallFile(
+ try steps.append(b.allocator, &b.addInstallFile(
webgen_actions_out,
"share/ghostty/webdata/actions.mdx",
).step);
@@ -81,8 +83,10 @@ pub fn init(
{
const webgen_commands = b.addExecutable(.{
.name = "webgen_commands",
- .root_source_file = b.path("src/main.zig"),
- .target = b.graph.host,
+ .root_module = b.createModule(.{
+ .root_source_file = b.path("src/main.zig"),
+ .target = b.graph.host,
+ }),
});
deps.help_strings.addImport(webgen_commands);
@@ -101,7 +105,7 @@ pub fn init(
const webgen_commands_step = b.addRunArtifact(webgen_commands);
const webgen_commands_out = webgen_commands_step.captureStdOut();
- try steps.append(&b.addInstallFile(
+ try steps.append(b.allocator, &b.addInstallFile(
webgen_commands_out,
"share/ghostty/webdata/commands.mdx",
).step);
diff --git a/src/build/MetallibStep.zig b/src/build/MetallibStep.zig
index 6999f8f31..fcf3055f8 100644
--- a/src/build/MetallibStep.zig
+++ b/src/build/MetallibStep.zig
@@ -44,7 +44,7 @@ pub fn create(b: *std.Build, opts: Options) ?*MetallibStep {
const self = b.allocator.create(MetallibStep) catch @panic("OOM");
const min_version = if (opts.target.query.os_version_min) |v|
- b.fmt("{}", .{v.semver})
+ b.fmt("{f}", .{v.semver})
else switch (opts.target.result.os.tag) {
.macos => "10.14",
.ios => "11.0",
diff --git a/src/build/SharedDeps.zig b/src/build/SharedDeps.zig
index 9461d48b7..785830ab9 100644
--- a/src/build/SharedDeps.zig
+++ b/src/build/SharedDeps.zig
@@ -113,8 +113,8 @@ pub fn add(
// We maintain a list of our static libraries and return it so that
// we can build a single fat static library for the final app.
- var static_libs = LazyPathList.init(b.allocator);
- errdefer static_libs.deinit();
+ var static_libs: LazyPathList = .empty;
+ errdefer static_libs.deinit(b.allocator);
// WARNING: This is a hack!
// If we're cross-compiling to Darwin then we don't add any deps.
@@ -154,6 +154,7 @@ pub fn add(
} else {
step.linkLibrary(freetype_dep.artifact("freetype"));
try static_libs.append(
+ b.allocator,
freetype_dep.artifact("freetype").getEmittedBin(),
);
}
@@ -178,6 +179,7 @@ pub fn add(
} else {
step.linkLibrary(harfbuzz_dep.artifact("harfbuzz"));
try static_libs.append(
+ b.allocator,
harfbuzz_dep.artifact("harfbuzz").getEmittedBin(),
);
}
@@ -201,6 +203,7 @@ pub fn add(
} else {
step.linkLibrary(fontconfig_dep.artifact("fontconfig"));
try static_libs.append(
+ b.allocator,
fontconfig_dep.artifact("fontconfig").getEmittedBin(),
);
}
@@ -218,6 +221,7 @@ pub fn add(
})) |libpng_dep| {
step.linkLibrary(libpng_dep.artifact("png"));
try static_libs.append(
+ b.allocator,
libpng_dep.artifact("png").getEmittedBin(),
);
}
@@ -231,6 +235,7 @@ pub fn add(
})) |zlib_dep| {
step.linkLibrary(zlib_dep.artifact("z"));
try static_libs.append(
+ b.allocator,
zlib_dep.artifact("z").getEmittedBin(),
);
}
@@ -250,6 +255,7 @@ pub fn add(
} else {
step.linkLibrary(oniguruma_dep.artifact("oniguruma"));
try static_libs.append(
+ b.allocator,
oniguruma_dep.artifact("oniguruma").getEmittedBin(),
);
}
@@ -270,6 +276,7 @@ pub fn add(
} else {
step.linkLibrary(glslang_dep.artifact("glslang"));
try static_libs.append(
+ b.allocator,
glslang_dep.artifact("glslang").getEmittedBin(),
);
}
@@ -289,6 +296,7 @@ pub fn add(
} else {
step.linkLibrary(spirv_cross_dep.artifact("spirv_cross"));
try static_libs.append(
+ b.allocator,
spirv_cross_dep.artifact("spirv_cross").getEmittedBin(),
);
}
@@ -307,6 +315,7 @@ pub fn add(
);
step.linkLibrary(sentry_dep.artifact("sentry"));
try static_libs.append(
+ b.allocator,
sentry_dep.artifact("sentry").getEmittedBin(),
);
@@ -316,6 +325,7 @@ pub fn add(
.optimize = optimize,
})) |breakpad_dep| {
try static_libs.append(
+ b.allocator,
breakpad_dep.artifact("breakpad").getEmittedBin(),
);
}
@@ -443,6 +453,7 @@ pub fn add(
macos_dep.artifact("macos"),
);
try static_libs.append(
+ b.allocator,
macos_dep.artifact("macos").getEmittedBin(),
);
}
@@ -461,6 +472,7 @@ pub fn add(
})) |libintl_dep| {
step.linkLibrary(libintl_dep.artifact("intl"));
try static_libs.append(
+ b.allocator,
libintl_dep.artifact("intl").getEmittedBin(),
);
}
@@ -473,7 +485,10 @@ pub fn add(
})) |cimgui_dep| {
step.root_module.addImport("cimgui", cimgui_dep.module("cimgui"));
step.linkLibrary(cimgui_dep.artifact("cimgui"));
- try static_libs.append(cimgui_dep.artifact("cimgui").getEmittedBin());
+ try static_libs.append(
+ b.allocator,
+ cimgui_dep.artifact("cimgui").getEmittedBin(),
+ );
}
// Fonts
@@ -697,6 +712,7 @@ pub fn addSimd(
})) |simdutf_dep| {
m.linkLibrary(simdutf_dep.artifact("simdutf"));
if (static_libs) |v| try v.append(
+ b.allocator,
simdutf_dep.artifact("simdutf").getEmittedBin(),
);
}
@@ -708,7 +724,10 @@ pub fn addSimd(
.optimize = optimize,
})) |highway_dep| {
m.linkLibrary(highway_dep.artifact("highway"));
- if (static_libs) |v| try v.append(highway_dep.artifact("highway").getEmittedBin());
+ if (static_libs) |v| try v.append(
+ b.allocator,
+ highway_dep.artifact("highway").getEmittedBin(),
+ );
}
// utfcpp - This is used as a dependency on our hand-written C++ code
@@ -717,7 +736,10 @@ pub fn addSimd(
.optimize = optimize,
})) |utfcpp_dep| {
m.linkLibrary(utfcpp_dep.artifact("utfcpp"));
- if (static_libs) |v| try v.append(utfcpp_dep.artifact("utfcpp").getEmittedBin());
+ if (static_libs) |v| try v.append(
+ b.allocator,
+ utfcpp_dep.artifact("utfcpp").getEmittedBin(),
+ );
}
// SIMD C++ files
@@ -761,16 +783,20 @@ pub fn gtkNgDistResources(
const gresource_xml = gresource_xml: {
const xml_exe = b.addExecutable(.{
.name = "generate_gresource_xml",
- .root_source_file = b.path("src/apprt/gtk/build/gresource.zig"),
- .target = b.graph.host,
+ .root_module = b.createModule(.{
+ .root_source_file = b.path("src/apprt/gtk/build/gresource.zig"),
+ .target = b.graph.host,
+ }),
});
const xml_run = b.addRunArtifact(xml_exe);
// Run our blueprint compiler across all of our blueprint files.
const blueprint_exe = b.addExecutable(.{
.name = "gtk_blueprint_compiler",
- .root_source_file = b.path("src/apprt/gtk/build/blueprint.zig"),
- .target = b.graph.host,
+ .root_module = b.createModule(.{
+ .root_source_file = b.path("src/apprt/gtk/build/blueprint.zig"),
+ .target = b.graph.host,
+ }),
});
blueprint_exe.linkLibC();
blueprint_exe.linkSystemLibrary2("gtk4", dynamic_link_opts);
diff --git a/src/build/UnicodeTables.zig b/src/build/UnicodeTables.zig
index 9972c851a..aba3e8f24 100644
--- a/src/build/UnicodeTables.zig
+++ b/src/build/UnicodeTables.zig
@@ -21,6 +21,9 @@ pub fn init(b: *std.Build, uucode_tables: std.Build.LazyPath) !UnicodeTables {
.omit_frame_pointer = false,
.unwind_tables = .sync,
}),
+
+ // TODO: x86_64 self-hosted crashes
+ .use_llvm = true,
});
const symbols_exe = b.addExecutable(.{
@@ -32,6 +35,9 @@ pub fn init(b: *std.Build, uucode_tables: std.Build.LazyPath) !UnicodeTables {
.omit_frame_pointer = false,
.unwind_tables = .sync,
}),
+
+ // TODO: x86_64 self-hosted crashes
+ .use_llvm = true,
});
if (b.lazyDependency("uucode", .{
diff --git a/src/build/docker/debian/Dockerfile b/src/build/docker/debian/Dockerfile
index 73c7da7c8..815d395cd 100644
--- a/src/build/docker/debian/Dockerfile
+++ b/src/build/docker/debian/Dockerfile
@@ -29,10 +29,10 @@ COPY ./build.zig /src
# Install zig
# https://ziglang.org/download/
-RUN export ZIG_VERSION=$(sed -n -e 's/^.*requireZig("\(.*\)").*$/\1/p' build.zig) && curl -L -o /tmp/zig.tar.xz "https://ziglang.org/download/$ZIG_VERSION/zig-linux-$(uname -m)-$ZIG_VERSION.tar.xz" && \
+RUN export ZIG_VERSION=$(sed -n -e 's/^.*requireZig("\(.*\)").*$/\1/p' build.zig) && curl -L -o /tmp/zig.tar.xz "https://ziglang.org/download/$ZIG_VERSION/zig-$(uname -m)-linux-$ZIG_VERSION.tar.xz" && \
tar -xf /tmp/zig.tar.xz -C /opt && \
rm /tmp/zig.tar.xz && \
- ln -s "/opt/zig-linux-$(uname -m)-$ZIG_VERSION/zig" /usr/local/bin/zig
+ ln -s "/opt/zig-$(uname -m)-linux-$ZIG_VERSION/zig" /usr/local/bin/zig
COPY . /src
diff --git a/src/build/mdgen/main_ghostty_1.zig b/src/build/mdgen/main_ghostty_1.zig
index b3663de8d..2bb413d93 100644
--- a/src/build/mdgen/main_ghostty_1.zig
+++ b/src/build/mdgen/main_ghostty_1.zig
@@ -2,12 +2,15 @@ const std = @import("std");
const gen = @import("mdgen.zig");
pub fn main() !void {
- var gpa = std.heap.GeneralPurposeAllocator(.{}){};
+ var gpa: std.heap.GeneralPurposeAllocator(.{}) = .init;
const alloc = gpa.allocator();
- const writer = std.io.getStdOut().writer();
+ var buffer: [1024]u8 = undefined;
+ var stdout_writer = std.fs.File.stdout().writer(&buffer);
+ const writer = &stdout_writer.interface;
try gen.substitute(alloc, @embedFile("ghostty_1_header.md"), writer);
try gen.genActions(writer);
try gen.genConfig(writer, true);
try gen.substitute(alloc, @embedFile("ghostty_1_footer.md"), writer);
+ try writer.flush();
}
diff --git a/src/build/mdgen/main_ghostty_5.zig b/src/build/mdgen/main_ghostty_5.zig
index 77c72b946..2123b0bce 100644
--- a/src/build/mdgen/main_ghostty_5.zig
+++ b/src/build/mdgen/main_ghostty_5.zig
@@ -2,12 +2,15 @@ const std = @import("std");
const gen = @import("mdgen.zig");
pub fn main() !void {
- var gpa = std.heap.GeneralPurposeAllocator(.{}){};
+ var gpa: std.heap.GeneralPurposeAllocator(.{}) = .init;
const alloc = gpa.allocator();
- const output = std.io.getStdOut().writer();
- try gen.substitute(alloc, @embedFile("ghostty_5_header.md"), output);
- try gen.genConfig(output, false);
- try gen.genKeybindActions(output);
- try gen.substitute(alloc, @embedFile("ghostty_5_footer.md"), output);
+ var buffer: [1024]u8 = undefined;
+ var stdout_writer = std.fs.File.stdout().writer(&buffer);
+ const writer = &stdout_writer.interface;
+ try gen.substitute(alloc, @embedFile("ghostty_5_header.md"), writer);
+ try gen.genConfig(writer, false);
+ try gen.genKeybindActions(writer);
+ try gen.substitute(alloc, @embedFile("ghostty_5_footer.md"), writer);
+ try writer.flush();
}
diff --git a/src/build/mdgen/mdgen.zig b/src/build/mdgen/mdgen.zig
index 53ed02067..530c8964f 100644
--- a/src/build/mdgen/mdgen.zig
+++ b/src/build/mdgen/mdgen.zig
@@ -5,7 +5,7 @@ const Config = @import("../../config/Config.zig");
const Action = @import("../../cli/ghostty.zig").Action;
const KeybindAction = @import("../../input/Binding.zig").Action;
-pub fn substitute(alloc: std.mem.Allocator, input: []const u8, writer: anytype) !void {
+pub fn substitute(alloc: std.mem.Allocator, input: []const u8, writer: *std.Io.Writer) !void {
const output = try alloc.alloc(u8, std.mem.replacementSize(
u8,
input,
@@ -18,7 +18,7 @@ pub fn substitute(alloc: std.mem.Allocator, input: []const u8, writer: anytype)
try writer.writeAll(output);
}
-pub fn genConfig(writer: anytype, cli: bool) !void {
+pub fn genConfig(writer: *std.Io.Writer, cli: bool) !void {
try writer.writeAll(
\\
\\# CONFIGURATION OPTIONS
@@ -48,7 +48,7 @@ pub fn genConfig(writer: anytype, cli: bool) !void {
}
}
-pub fn genActions(writer: anytype) !void {
+pub fn genActions(writer: *std.Io.Writer) !void {
try writer.writeAll(
\\
\\# COMMAND LINE ACTIONS
@@ -83,7 +83,7 @@ pub fn genActions(writer: anytype) !void {
}
}
-pub fn genKeybindActions(writer: anytype) !void {
+pub fn genKeybindActions(writer: *std.Io.Writer) !void {
try writer.writeAll(
\\
\\# KEYBIND ACTIONS
diff --git a/src/build/webgen/main_actions.zig b/src/build/webgen/main_actions.zig
index 5002a5bac..85357b972 100644
--- a/src/build/webgen/main_actions.zig
+++ b/src/build/webgen/main_actions.zig
@@ -3,6 +3,8 @@ const help_strings = @import("help_strings");
const helpgen_actions = @import("../../input/helpgen_actions.zig");
pub fn main() !void {
- const output = std.io.getStdOut().writer();
- try helpgen_actions.generate(output, .markdown, true, std.heap.page_allocator);
+ var buffer: [2048]u8 = undefined;
+ var stdout_writer = std.fs.File.stdout().writer(&buffer);
+ const stdout = &stdout_writer.interface;
+ try helpgen_actions.generate(stdout, .markdown, true, std.heap.page_allocator);
}
diff --git a/src/build/webgen/main_commands.zig b/src/build/webgen/main_commands.zig
index ad5c75734..65f144522 100644
--- a/src/build/webgen/main_commands.zig
+++ b/src/build/webgen/main_commands.zig
@@ -3,14 +3,16 @@ const Action = @import("../../cli/ghostty.zig").Action;
const help_strings = @import("help_strings");
pub fn main() !void {
- const output = std.io.getStdOut().writer();
- try genActions(output);
+ var buffer: [2048]u8 = undefined;
+ var stdout_writer = std.fs.File.stdout().writer(&buffer);
+ const stdout = &stdout_writer.interface;
+ try genActions(stdout);
}
// Note: as a shortcut for defining inline editOnGithubLinks per cli action the user
// is directed to the folder view on Github. This includes a README pointing them to
// the files to edit.
-pub fn genActions(writer: anytype) !void {
+pub fn genActions(writer: *std.Io.Writer) !void {
// Write the header
try writer.writeAll(
\\---
diff --git a/src/build/webgen/main_config.zig b/src/build/webgen/main_config.zig
index 1bde2f9cc..1363fadc4 100644
--- a/src/build/webgen/main_config.zig
+++ b/src/build/webgen/main_config.zig
@@ -3,11 +3,13 @@ const Config = @import("../../config/Config.zig");
const help_strings = @import("help_strings");
pub fn main() !void {
- const output = std.io.getStdOut().writer();
- try genConfig(output);
+ var buffer: [2048]u8 = undefined;
+ var stdout_writer = std.fs.File.stdout().writer(&buffer);
+ const stdout = &stdout_writer.interface;
+ try genConfig(stdout);
}
-pub fn genConfig(writer: anytype) !void {
+pub fn genConfig(writer: *std.Io.Writer) !void {
// Write the header
try writer.writeAll(
\\---
@@ -122,7 +124,7 @@ pub fn genConfig(writer: anytype) !void {
}
}
-fn endBlock(writer: anytype, block: anytype) !void {
+fn endBlock(writer: *std.Io.Writer, block: anytype) !void {
if (block) |v| switch (v) {
.text => {},
.code => try writer.writeAll("```\n"),
diff --git a/src/cli/args.zig b/src/cli/args.zig
index b8f393864..a34560b78 100644
--- a/src/cli/args.zig
+++ b/src/cli/args.zig
@@ -162,10 +162,11 @@ pub fn parse(
error.InvalidField => "unknown field",
error.ValueRequired => formatValueRequired(T, arena_alloc, key) catch "value required",
error.InvalidValue => formatInvalidValue(T, arena_alloc, key, value) catch "invalid value",
- else => try std.fmt.allocPrintZ(
+ else => try std.fmt.allocPrintSentinel(
arena_alloc,
"unknown error {}",
.{err},
+ 0,
),
};
@@ -235,14 +236,16 @@ fn formatValueRequired(
comptime T: type,
arena_alloc: std.mem.Allocator,
key: []const u8,
-) std.mem.Allocator.Error![:0]const u8 {
- var buf = std.ArrayList(u8).init(arena_alloc);
- errdefer buf.deinit();
- const writer = buf.writer();
+) std.Io.Writer.Error![:0]const u8 {
+ var stream: std.Io.Writer.Allocating = .init(arena_alloc);
+ const writer = &stream.writer;
+
try writer.print("value required", .{});
try formatValues(T, key, writer);
try writer.writeByte(0);
- return buf.items[0 .. buf.items.len - 1 :0];
+
+ const written = stream.written();
+ return written[0 .. written.len - 1 :0];
}
fn formatInvalidValue(
@@ -250,17 +253,23 @@ fn formatInvalidValue(
arena_alloc: std.mem.Allocator,
key: []const u8,
value: ?[]const u8,
-) std.mem.Allocator.Error![:0]const u8 {
- var buf = std.ArrayList(u8).init(arena_alloc);
- errdefer buf.deinit();
- const writer = buf.writer();
+) std.Io.Writer.Error![:0]const u8 {
+ var stream: std.Io.Writer.Allocating = .init(arena_alloc);
+ const writer = &stream.writer;
+
try writer.print("invalid value \"{?s}\"", .{value});
try formatValues(T, key, writer);
try writer.writeByte(0);
- return buf.items[0 .. buf.items.len - 1 :0];
+
+ const written = stream.written();
+ return written[0 .. written.len - 1 :0];
}
-fn formatValues(comptime T: type, key: []const u8, writer: anytype) std.mem.Allocator.Error!void {
+fn formatValues(
+ comptime T: type,
+ key: []const u8,
+ writer: *std.Io.Writer,
+) std.Io.Writer.Error!void {
@setEvalBranchQuota(2000);
const typeinfo = @typeInfo(T);
inline for (typeinfo.@"struct".fields) |f| {
@@ -324,7 +333,7 @@ pub fn parseIntoField(
return;
}
const raw = field.default_value_ptr orelse break :default;
- const ptr: *const field.type = @alignCast(@ptrCast(raw));
+ const ptr: *const field.type = @ptrCast(@alignCast(raw));
@field(dst, field.name) = ptr.*;
return;
}
@@ -542,8 +551,8 @@ pub fn parseAutoStruct(
const key = std.mem.trim(u8, entry[0..idx], whitespace);
// used if we need to decode a double-quoted string.
- var buf: std.ArrayListUnmanaged(u8) = .empty;
- defer buf.deinit(alloc);
+ var buf: std.Io.Writer.Allocating = .init(alloc);
+ defer buf.deinit();
const value = value: {
const value = std.mem.trim(u8, entry[idx + 1 ..], whitespace);
@@ -554,10 +563,9 @@ pub fn parseAutoStruct(
value[value.len - 1] == '"')
{
// Decode a double-quoted string as a Zig string literal.
- const writer = buf.writer(alloc);
- const parsed = try std.zig.string_literal.parseWrite(writer, value);
+ const parsed = try std.zig.string_literal.parseWrite(&buf.writer, value);
if (parsed == .failure) return error.InvalidValue;
- break :value buf.items;
+ break :value buf.written();
}
break :value value;
@@ -586,7 +594,7 @@ pub fn parseAutoStruct(
break :default @field(default, field.name);
} else {
const default_ptr = field.default_value_ptr orelse return error.InvalidValue;
- const typed_ptr: *const field.type = @alignCast(@ptrCast(default_ptr));
+ const typed_ptr: *const field.type = @ptrCast(@alignCast(default_ptr));
break :default typed_ptr.*;
}
};
@@ -795,15 +803,13 @@ test "parse: diagnostic location" {
} = .{};
defer if (data._arena) |arena| arena.deinit();
- var fbs = std.io.fixedBufferStream(
+ var r: std.Io.Reader = .fixed(
\\a=42
\\what
\\b=two
);
- const r = fbs.reader();
- const Iter = LineIterator(@TypeOf(r));
- var iter: Iter = .{ .r = r, .filepath = "test" };
+ var iter: LineIterator = .{ .r = &r, .filepath = "test" };
try parse(@TypeOf(data), testing.allocator, &data, &iter);
try testing.expect(data._arena != null);
try testing.expectEqualStrings("42", data.a);
@@ -1208,18 +1214,7 @@ test "parseIntoField: struct with basic fields" {
try testing.expectEqual(84, data.value.b);
try testing.expectEqual(24, data.value.c);
- // Set with explicit default
- data.value = try parseAutoStruct(
- @TypeOf(data.value),
- alloc,
- "a:hello",
- .{ .a = "oh no", .b = 42 },
- );
- try testing.expectEqualStrings("hello", data.value.a);
- try testing.expectEqual(42, data.value.b);
- try testing.expectEqual(12, data.value.c);
-
- // Missing required field
+ // Missing require dfield
try testing.expectError(
error.InvalidValue,
parseIntoField(@TypeOf(data), alloc, &data, "value", "a:hello"),
@@ -1395,115 +1390,119 @@ test "ArgsIterator" {
/// Returns an iterator (implements "next") that reads CLI args by line.
/// Each CLI arg is expected to be a single line. This is used to implement
/// configuration files.
-pub fn LineIterator(comptime ReaderType: type) type {
- return struct {
- const Self = @This();
+pub const LineIterator = struct {
+ const Self = @This();
- /// The maximum size a single line can be. We don't expect any
- /// CLI arg to exceed this size. Can't wait to git blame this in
- /// like 4 years and be wrong about this.
- pub const MAX_LINE_SIZE = 4096;
+ /// The maximum size a single line can be. We don't expect any
+ /// CLI arg to exceed this size. Can't wait to git blame this in
+ /// like 4 years and be wrong about this.
+ pub const MAX_LINE_SIZE = 4096;
- /// Our stateful reader.
- r: ReaderType,
+ /// Our stateful reader.
+ r: *std.Io.Reader,
- /// Filepath that is used for diagnostics. This is only used for
- /// diagnostic messages so it can be formatted however you want.
- /// It is prefixed to the messages followed by the line number.
- filepath: []const u8 = "",
+ /// Filepath that is used for diagnostics. This is only used for
+ /// diagnostic messages so it can be formatted however you want.
+ /// It is prefixed to the messages followed by the line number.
+ filepath: []const u8 = "",
- /// The current line that we're on. This is 1-indexed because
- /// lines are generally 1-indexed in the real world. The value
- /// can be zero if we haven't read any lines yet.
- line: usize = 0,
+ /// The current line that we're on. This is 1-indexed because
+ /// lines are generally 1-indexed in the real world. The value
+ /// can be zero if we haven't read any lines yet.
+ line: usize = 0,
- /// This is the buffer where we store the current entry that
- /// is formatted to be compatible with the parse function.
- entry: [MAX_LINE_SIZE]u8 = [_]u8{ '-', '-' } ++ ([_]u8{0} ** (MAX_LINE_SIZE - 2)),
+ /// This is the buffer where we store the current entry that
+ /// is formatted to be compatible with the parse function.
+ entry: [MAX_LINE_SIZE]u8 = [_]u8{ '-', '-' } ++ ([_]u8{0} ** (MAX_LINE_SIZE - 2)),
- pub fn next(self: *Self) ?[]const u8 {
- // TODO: detect "--" prefixed lines and give a friendlier error
- const buf = buf: {
- while (true) {
- // Read the full line
- var entry = self.r.readUntilDelimiterOrEof(self.entry[2..], '\n') catch |err| switch (err) {
- inline else => |e| {
- log.warn("cannot read from \"{s}\": {}", .{ self.filepath, e });
- return null;
- },
- } orelse return null;
+ pub fn init(reader: *std.Io.Reader) Self {
+ return .{ .r = reader };
+ }
- // Increment our line counter
- self.line += 1;
+ pub fn next(self: *Self) ?[]const u8 {
+ // First prime the reader.
+ // File readers at least are initialized with a size of 0,
+ // and this will actually prompt the reader to get the actual
+ // size of the file, which will be used in the EOF check below.
+ //
+ // This will also optimize reads down the line as we're
+ // more likely to beworking with buffered data.
+ self.r.fillMore() catch {};
- // Trim any whitespace (including CR) around it
- const trim = std.mem.trim(u8, entry, whitespace ++ "\r");
- if (trim.len != entry.len) {
- std.mem.copyForwards(u8, entry, trim);
- entry = entry[0..trim.len];
- }
+ var writer: std.Io.Writer = .fixed(self.entry[2..]);
- // Ignore blank lines and comments
- if (entry.len == 0 or entry[0] == '#') continue;
+ var entry = while (self.r.seek != self.r.end) {
+ // Reset write head
+ writer.end = 0;
- // Trim spaces around '='
- if (mem.indexOf(u8, entry, "=")) |idx| {
- const key = std.mem.trim(u8, entry[0..idx], whitespace);
- const value = value: {
- var value = std.mem.trim(u8, entry[idx + 1 ..], whitespace);
+ _ = self.r.streamDelimiterEnding(&writer, '\n') catch |e| {
+ log.warn("cannot read from \"{s}\": {}", .{ self.filepath, e });
+ return null;
+ };
+ _ = self.r.discardDelimiterInclusive('\n') catch {};
- // Detect a quoted string.
- if (value.len >= 2 and
- value[0] == '"' and
- value[value.len - 1] == '"')
- {
- // Trim quotes since our CLI args processor expects
- // quotes to already be gone.
- value = value[1 .. value.len - 1];
- }
+ var entry = writer.buffered();
+ self.line += 1;
- break :value value;
- };
+ // Trim any whitespace (including CR) around it
+ const trim = std.mem.trim(u8, entry, whitespace ++ "\r");
+ if (trim.len != entry.len) {
+ std.mem.copyForwards(u8, entry, trim);
+ entry = entry[0..trim.len];
+ }
- const len = key.len + value.len + 1;
- if (entry.len != len) {
- std.mem.copyForwards(u8, entry, key);
- entry[key.len] = '=';
- std.mem.copyForwards(u8, entry[key.len + 1 ..], value);
- entry = entry[0..len];
- }
- }
+ // Ignore blank lines and comments
+ if (entry.len == 0 or entry[0] == '#') continue;
+ break entry;
+ } else return null;
- break :buf entry;
+ if (mem.indexOf(u8, entry, "=")) |idx| {
+ const key = std.mem.trim(u8, entry[0..idx], whitespace);
+ const value = value: {
+ var value = std.mem.trim(u8, entry[idx + 1 ..], whitespace);
+
+ // Detect a quoted string.
+ if (value.len >= 2 and
+ value[0] == '"' and
+ value[value.len - 1] == '"')
+ {
+ // Trim quotes since our CLI args processor expects
+ // quotes to already be gone.
+ value = value[1 .. value.len - 1];
}
+
+ break :value value;
};
- // We need to reslice so that we include our '--' at the beginning
- // of our buffer so that we can trick the CLI parser to treat it
- // as CLI args.
- return self.entry[0 .. buf.len + 2];
+ const len = key.len + value.len + 1;
+ if (entry.len != len) {
+ std.mem.copyForwards(u8, entry, key);
+ entry[key.len] = '=';
+ std.mem.copyForwards(u8, entry[key.len + 1 ..], value);
+ entry = entry[0..len];
+ }
}
- /// Returns a location for a diagnostic message.
- pub fn location(
- self: *const Self,
- alloc: Allocator,
- ) Allocator.Error!?diags.Location {
- // If we have no filepath then we have no location.
- if (self.filepath.len == 0) return null;
+ // We need to reslice so that we include our '--' at the beginning
+ // of our buffer so that we can trick the CLI parser to treat it
+ // as CLI args.
+ return self.entry[0 .. entry.len + 2];
+ }
- return .{ .file = .{
- .path = try alloc.dupe(u8, self.filepath),
- .line = self.line,
- } };
- }
- };
-}
+ /// Returns a location for a diagnostic message.
+ pub fn location(
+ self: *const Self,
+ alloc: Allocator,
+ ) Allocator.Error!?diags.Location {
+ // If we have no filepath then we have no location.
+ if (self.filepath.len == 0) return null;
-// Constructs a LineIterator (see docs for that).
-fn lineIterator(reader: anytype) LineIterator(@TypeOf(reader)) {
- return .{ .r = reader };
-}
+ return .{ .file = .{
+ .path = try alloc.dupe(u8, self.filepath),
+ .line = self.line,
+ } };
+ }
+};
/// An iterator valid for arg parsing from a slice.
pub const SliceIterator = struct {
@@ -1526,7 +1525,7 @@ pub fn sliceIterator(slice: []const []const u8) SliceIterator {
test "LineIterator" {
const testing = std.testing;
- var fbs = std.io.fixedBufferStream(
+ var reader: std.Io.Reader = .fixed(
\\A
\\B=42
\\C
@@ -1541,7 +1540,7 @@ test "LineIterator" {
\\F= "value "
);
- var iter = lineIterator(fbs.reader());
+ var iter: LineIterator = .init(&reader);
try testing.expectEqualStrings("--A", iter.next().?);
try testing.expectEqualStrings("--B=42", iter.next().?);
try testing.expectEqualStrings("--C", iter.next().?);
@@ -1554,9 +1553,9 @@ test "LineIterator" {
test "LineIterator end in newline" {
const testing = std.testing;
- var fbs = std.io.fixedBufferStream("A\n\n");
+ var reader: std.Io.Reader = .fixed("A\n\n");
- var iter = lineIterator(fbs.reader());
+ var iter: LineIterator = .init(&reader);
try testing.expectEqualStrings("--A", iter.next().?);
try testing.expectEqual(@as(?[]const u8, null), iter.next());
try testing.expectEqual(@as(?[]const u8, null), iter.next());
@@ -1564,9 +1563,9 @@ test "LineIterator end in newline" {
test "LineIterator spaces around '='" {
const testing = std.testing;
- var fbs = std.io.fixedBufferStream("A = B\n\n");
+ var reader: std.Io.Reader = .fixed("A = B\n\n");
- var iter = lineIterator(fbs.reader());
+ var iter: LineIterator = .init(&reader);
try testing.expectEqualStrings("--A=B", iter.next().?);
try testing.expectEqual(@as(?[]const u8, null), iter.next());
try testing.expectEqual(@as(?[]const u8, null), iter.next());
@@ -1574,18 +1573,18 @@ test "LineIterator spaces around '='" {
test "LineIterator no value" {
const testing = std.testing;
- var fbs = std.io.fixedBufferStream("A = \n\n");
+ var reader: std.Io.Reader = .fixed("A = \n\n");
- var iter = lineIterator(fbs.reader());
+ var iter: LineIterator = .init(&reader);
try testing.expectEqualStrings("--A=", iter.next().?);
try testing.expectEqual(@as(?[]const u8, null), iter.next());
}
test "LineIterator with CRLF line endings" {
const testing = std.testing;
- var fbs = std.io.fixedBufferStream("A\r\nB = C\r\n");
+ var reader: std.Io.Reader = .fixed("A\r\nB = C\r\n");
- var iter = lineIterator(fbs.reader());
+ var iter: LineIterator = .init(&reader);
try testing.expectEqualStrings("--A", iter.next().?);
try testing.expectEqualStrings("--B=C", iter.next().?);
try testing.expectEqual(@as(?[]const u8, null), iter.next());
diff --git a/src/cli/boo.zig b/src/cli/boo.zig
index 72b282ef6..756b6d77a 100644
--- a/src/cli/boo.zig
+++ b/src/cli/boo.zig
@@ -6,7 +6,7 @@ const Allocator = std.mem.Allocator;
const help_strings = @import("help_strings");
const vaxis = @import("vaxis");
-const framedata = @import("framedata");
+const framedata = @embedFile("framedata");
const vxfw = vaxis.vxfw;
@@ -218,17 +218,20 @@ var frames: []const []const u8 = undefined;
/// Decompress the frames into a slice of individual frames
fn decompressFrames(gpa: Allocator) !void {
- var fbs = std.io.fixedBufferStream(framedata.compressed);
- var list = std.ArrayList(u8).init(gpa);
+ var src: std.Io.Reader = .fixed(framedata);
- try std.compress.flate.decompress(fbs.reader(), list.writer());
- decompressed_data = try list.toOwnedSlice();
+ // var buf: [std.compress.flate.max_window_len]u8 = undefined;
+ var decompress: std.compress.flate.Decompress = .init(&src, .raw, &.{});
- var frame_list = try std.ArrayList([]const u8).initCapacity(gpa, 235);
+ var out: std.Io.Writer.Allocating = .init(gpa);
+ _ = try decompress.reader.streamRemaining(&out.writer);
+ decompressed_data = try out.toOwnedSlice();
+
+ var frame_list: std.ArrayList([]const u8) = try .initCapacity(gpa, 235);
var frame_iter = std.mem.splitScalar(u8, decompressed_data, '\x01');
while (frame_iter.next()) |frame| {
- try frame_list.append(frame);
+ try frame_list.append(gpa, frame);
}
- frames = try frame_list.toOwnedSlice();
+ frames = try frame_list.toOwnedSlice(gpa);
}
diff --git a/src/cli/crash_report.zig b/src/cli/crash_report.zig
index c6a383563..f0940fdab 100644
--- a/src/cli/crash_report.zig
+++ b/src/cli/crash_report.zig
@@ -38,21 +38,35 @@ pub fn run(alloc_gpa: Allocator) !u8 {
try args.parse(Options, alloc_gpa, &opts, &iter);
}
+ var buffer: [1024]u8 = undefined;
+ var stdout_file: std.fs.File = .stdout();
+ var stdout_writer = stdout_file.writer(&buffer);
+ const stdout = &stdout_writer.interface;
+
+ const result = runInner(alloc, &stdout_file, stdout);
+ stdout.flush() catch {};
+ return result;
+}
+
+fn runInner(
+ alloc: Allocator,
+ stdout_file: *std.fs.File,
+ stdout: *std.Io.Writer,
+) !u8 {
const crash_dir = try crash.defaultDir(alloc);
- var reports = std.ArrayList(crash.Report).init(alloc);
+ var reports: std.ArrayList(crash.Report) = .empty;
+ errdefer reports.deinit(alloc);
var it = try crash_dir.iterator();
- while (try it.next()) |report| try reports.append(.{
+ while (try it.next()) |report| try reports.append(alloc, .{
.name = try alloc.dupe(u8, report.name),
.mtime = report.mtime,
});
- const stdout = std.io.getStdOut();
-
// If we have no reports, then we're done. If we have a tty then we
// print a message, otherwise we do nothing.
if (reports.items.len == 0) {
- if (std.posix.isatty(stdout.handle)) {
+ if (std.posix.isatty(stdout_file.handle)) {
try stdout.writeAll("No crash reports! 👻\n");
}
return 0;
@@ -60,16 +74,15 @@ pub fn run(alloc_gpa: Allocator) !u8 {
std.mem.sort(crash.Report, reports.items, {}, lt);
- const writer = stdout.writer();
for (reports.items) |report| {
var buf: [128]u8 = undefined;
const now = std.time.nanoTimestamp();
const diff = now - report.mtime;
const since = if (diff <= 0) "now" else s: {
const d = Config.Duration{ .duration = @intCast(diff) };
- break :s try std.fmt.bufPrint(&buf, "{s} ago", .{d.round(std.time.ns_per_s)});
+ break :s try std.fmt.bufPrint(&buf, "{f} ago", .{d.round(std.time.ns_per_s)});
};
- try writer.print("{s} ({s})\n", .{ report.name, since });
+ try stdout.print("{s} ({s})\n", .{ report.name, since });
}
return 0;
diff --git a/src/cli/diagnostics.zig b/src/cli/diagnostics.zig
index 2c6cb3b30..2af8bb4f8 100644
--- a/src/cli/diagnostics.zig
+++ b/src/cli/diagnostics.zig
@@ -16,7 +16,7 @@ pub const Diagnostic = struct {
message: [:0]const u8,
/// Write the full user-friendly diagnostic message to the writer.
- pub fn write(self: *const Diagnostic, writer: anytype) !void {
+ pub fn format(self: *const Diagnostic, writer: *std.Io.Writer) !void {
switch (self.location) {
.none => {},
.cli => |index| try writer.print("cli:{}:", .{index}),
@@ -157,11 +157,14 @@ pub const DiagnosticList = struct {
errdefer _ = self.list.pop();
if (comptime precompute_enabled) {
- var buf = std.ArrayList(u8).init(alloc);
- defer buf.deinit();
- try diag.write(buf.writer());
+ var stream: std.Io.Writer.Allocating = .init(alloc);
+ defer stream.deinit();
+ diag.format(&stream.writer) catch |err| switch (err) {
+ // WriteFailed in this instance can only mean an OOM
+ error.WriteFailed => return error.OutOfMemory,
+ };
- const owned: [:0]const u8 = try buf.toOwnedSliceSentinel(0);
+ const owned: [:0]const u8 = try stream.toOwnedSliceSentinel(0);
errdefer alloc.free(owned);
try self.precompute.messages.append(alloc, owned);
diff --git a/src/cli/edit_config.zig b/src/cli/edit_config.zig
index 116843037..f103ca4a0 100644
--- a/src/cli/edit_config.zig
+++ b/src/cli/edit_config.zig
@@ -47,7 +47,9 @@ pub fn run(alloc: Allocator) !u8 {
// not using `exec` anymore and because this command isn't performance
// critical where setting up the defer cleanup is a problem.
- const stderr = std.io.getStdErr().writer();
+ var buffer: [1024]u8 = undefined;
+ var stderr_writer = std.fs.File.stderr().writer(&buffer);
+ const stderr = &stderr_writer.interface;
var opts: Options = .{};
defer opts.deinit();
@@ -58,6 +60,13 @@ pub fn run(alloc: Allocator) !u8 {
try args.parse(Options, alloc, &opts, &iter);
}
+ const result = runInner(alloc, stderr);
+ // Flushing *shouldn't* fail but...
+ stderr.flush() catch {};
+ return result;
+}
+
+fn runInner(alloc: Allocator, stderr: *std.Io.Writer) !u8 {
// We load the configuration once because that will write our
// default configuration files to disk. We don't use the config.
var config = try Config.load(alloc);
@@ -133,23 +142,13 @@ pub fn run(alloc: Allocator) !u8 {
// so this is not a big deal.
comptime assert(builtin.link_libc);
- var buf: std.ArrayListUnmanaged(u8) = .empty;
- errdefer buf.deinit(alloc);
-
- const writer = buf.writer(alloc);
- var shellescape: internal_os.ShellEscapeWriter(std.ArrayListUnmanaged(u8).Writer) = .init(writer);
- var shellescapewriter = shellescape.writer();
-
- try writer.writeAll(editor);
- try writer.writeByte(' ');
- try shellescapewriter.writeAll(path);
-
- const command = try buf.toOwnedSliceSentinel(alloc, 0);
- defer alloc.free(command);
-
+ const editorZ = try alloc.dupeZ(u8, editor);
+ defer alloc.free(editorZ);
+ const pathZ = try alloc.dupeZ(u8, path);
+ defer alloc.free(pathZ);
const err = std.posix.execvpeZ(
- "sh",
- &.{ "sh", "-c", command },
+ editorZ,
+ &.{ editorZ, pathZ },
std.c.environ,
);
diff --git a/src/cli/ghostty.zig b/src/cli/ghostty.zig
index adb715d68..f6ac7d93d 100644
--- a/src/cli/ghostty.zig
+++ b/src/cli/ghostty.zig
@@ -107,12 +107,18 @@ pub const Action = enum {
// for all commands by just changing this one place.
if (std.mem.eql(u8, field.name, @tagName(self))) {
- const stdout = std.io.getStdOut().writer();
+ var buffer: [1024]u8 = undefined;
+ var stdout_writer = std.fs.File.stdout().writer(&buffer);
+ const stdout = &stdout_writer.interface;
const text = @field(help_strings.Action, field.name) ++ "\n";
stdout.writeAll(text) catch |write_err| {
std.log.warn("failed to write help text: {}\n", .{write_err});
break :err 1;
};
+ stdout.flush() catch |flush_err| {
+ std.log.warn("failed to flush help text: {}\n", .{flush_err});
+ break :err 1;
+ };
break :err 0;
}
diff --git a/src/cli/help.zig b/src/cli/help.zig
index 0528dc1c2..a2b4dde80 100644
--- a/src/cli/help.zig
+++ b/src/cli/help.zig
@@ -30,7 +30,9 @@ pub fn run(alloc: Allocator) !u8 {
try args.parse(Options, alloc, &opts, &iter);
}
- const stdout = std.io.getStdOut().writer();
+ var buffer: [2048]u8 = undefined;
+ var stdout_writer = std.fs.File.stdout().writer(&buffer);
+ const stdout = &stdout_writer.interface;
try stdout.writeAll(
\\Usage: ghostty [+action] [options]
\\
@@ -70,6 +72,7 @@ pub fn run(alloc: Allocator) !u8 {
\\where `` is one of actions listed above.
\\
);
+ try stdout.flush();
return 0;
}
diff --git a/src/cli/list_actions.zig b/src/cli/list_actions.zig
index 6f5ce06a2..682eed251 100644
--- a/src/cli/list_actions.zig
+++ b/src/cli/list_actions.zig
@@ -37,8 +37,15 @@ pub fn run(alloc: Allocator) !u8 {
try args.parse(Options, alloc, &opts, &iter);
}
- const stdout = std.io.getStdOut().writer();
- try helpgen_actions.generate(stdout, .plaintext, opts.docs, std.heap.page_allocator);
+ var stdout: std.fs.File = .stdout();
+ var buffer: [4096]u8 = undefined;
+ var stdout_writer = stdout.writer(&buffer);
+ try helpgen_actions.generate(
+ &stdout_writer.interface,
+ .plaintext,
+ opts.docs,
+ std.heap.page_allocator,
+ );
return 0;
}
diff --git a/src/cli/list_colors.zig b/src/cli/list_colors.zig
index 63945de99..50c12a693 100644
--- a/src/cli/list_colors.zig
+++ b/src/cli/list_colors.zig
@@ -39,11 +39,9 @@ pub fn run(alloc: Allocator) !u8 {
try args.parse(Options, alloc, &opts, &iter);
}
- const stdout = std.io.getStdOut();
-
- var keys = std.ArrayList([]const u8).init(alloc);
- defer keys.deinit();
- for (x11_color.map.keys()) |key| try keys.append(key);
+ var keys: std.ArrayList([]const u8) = .empty;
+ defer keys.deinit(alloc);
+ for (x11_color.map.keys()) |key| try keys.append(alloc, key);
std.mem.sortUnstable([]const u8, keys.items, {}, struct {
fn lessThan(_: void, lhs: []const u8, rhs: []const u8) bool {
@@ -52,12 +50,15 @@ pub fn run(alloc: Allocator) !u8 {
}.lessThan);
// Despite being under the posix namespace, this also works on Windows as of zig 0.13.0
+ var stdout: std.fs.File = .stdout();
if (tui.can_pretty_print and !opts.plain and std.posix.isatty(stdout.handle)) {
var arena = std.heap.ArenaAllocator.init(alloc);
defer arena.deinit();
return prettyPrint(arena.allocator(), keys.items);
} else {
- const writer = stdout.writer();
+ var buffer: [4096]u8 = undefined;
+ var stdout_writer = stdout.writer(&buffer);
+ const writer = &stdout_writer.interface;
for (keys.items) |name| {
const rgb = x11_color.map.get(name).?;
try writer.print("{s} = #{x:0>2}{x:0>2}{x:0>2}\n", .{
@@ -74,19 +75,17 @@ pub fn run(alloc: Allocator) !u8 {
fn prettyPrint(alloc: Allocator, keys: [][]const u8) !u8 {
// Set up vaxis
- var tty = try vaxis.Tty.init();
+ var buf: [1024]u8 = undefined;
+ var tty = try vaxis.Tty.init(&buf);
defer tty.deinit();
var vx = try vaxis.init(alloc, .{});
- defer vx.deinit(alloc, tty.anyWriter());
+ defer vx.deinit(alloc, tty.writer());
// We know we are ghostty, so let's enable mode 2027. Vaxis normally does this but you need an
// event loop to auto-enable it.
vx.caps.unicode = .unicode;
- try tty.anyWriter().writeAll(vaxis.ctlseqs.unicode_set);
- defer tty.anyWriter().writeAll(vaxis.ctlseqs.unicode_reset) catch {};
-
- var buf_writer = tty.bufferedWriter();
- const writer = buf_writer.writer().any();
+ try tty.writer().writeAll(vaxis.ctlseqs.unicode_set);
+ defer tty.writer().writeAll(vaxis.ctlseqs.unicode_reset) catch {};
const winsize: vaxis.Winsize = switch (builtin.os.tag) {
// We use some default, it doesn't really matter for what
@@ -100,7 +99,7 @@ fn prettyPrint(alloc: Allocator, keys: [][]const u8) !u8 {
else => try vaxis.Tty.getWinsize(tty.fd),
};
- try vx.resize(alloc, tty.anyWriter(), winsize);
+ try vx.resize(alloc, tty.writer(), winsize);
const win = vx.window();
@@ -203,11 +202,8 @@ fn prettyPrint(alloc: Allocator, keys: [][]const u8) !u8 {
}
// output the data
- try vx.prettyPrint(writer);
+ try vx.prettyPrint(tty.writer());
}
- // be sure to flush!
- try buf_writer.flush();
-
return 0;
}
diff --git a/src/cli/list_fonts.zig b/src/cli/list_fonts.zig
index 58246d3ad..396c4e8a6 100644
--- a/src/cli/list_fonts.zig
+++ b/src/cli/list_fonts.zig
@@ -77,7 +77,9 @@ fn runArgs(alloc_gpa: Allocator, argsIter: anytype) !u8 {
// Its possible to build Ghostty without font discovery!
if (comptime font.Discover == void) {
- const stderr = std.io.getStdErr().writer();
+ var buffer: [1024]u8 = undefined;
+ var stderr_writer = std.fs.File.stderr().writer(&buffer);
+ const stderr = &stderr_writer.interface;
try stderr.print(
\\Ghostty was built without a font discovery mechanism. This is a compile-time
\\option. Please review how Ghostty was built from source, contact the
@@ -85,15 +87,18 @@ fn runArgs(alloc_gpa: Allocator, argsIter: anytype) !u8 {
,
.{},
);
+ try stderr.flush();
return 1;
}
- const stdout = std.io.getStdOut().writer();
+ var buffer: [2048]u8 = undefined;
+ var stdout_writer = std.fs.File.stdout().writer(&buffer);
+ const stdout = &stdout_writer.interface;
// We'll be putting our fonts into a list categorized by family
// so it is easier to read the output.
- var families = std.ArrayList([]const u8).init(alloc);
- var map = std.StringHashMap(std.ArrayListUnmanaged([]const u8)).init(alloc);
+ var families: std.ArrayList([]const u8) = .empty;
+ var map: std.StringHashMap(std.ArrayListUnmanaged([]const u8)) = .init(alloc);
// Look up all available fonts
var disco = font.Discover.init();
@@ -123,7 +128,7 @@ fn runArgs(alloc_gpa: Allocator, argsIter: anytype) !u8 {
const gop = try map.getOrPut(family);
if (!gop.found_existing) {
- try families.append(family);
+ try families.append(alloc, family);
gop.value_ptr.* = .{};
}
try gop.value_ptr.append(alloc, full_name);
@@ -155,5 +160,6 @@ fn runArgs(alloc_gpa: Allocator, argsIter: anytype) !u8 {
try stdout.print("\n", .{});
}
+ try stdout.flush();
return 0;
}
diff --git a/src/cli/list_keybinds.zig b/src/cli/list_keybinds.zig
index 94f445eea..a8899a4f5 100644
--- a/src/cli/list_keybinds.zig
+++ b/src/cli/list_keybinds.zig
@@ -64,27 +64,38 @@ pub fn run(alloc: Allocator) !u8 {
var config = if (opts.default) try Config.default(alloc) else try Config.load(alloc);
defer config.deinit();
- const stdout = std.io.getStdOut();
+ var buffer: [1024]u8 = undefined;
+ const stdout: std.fs.File = .stdout();
+ var stdout_writer = stdout.writer(&buffer);
+ const writer = &stdout_writer.interface;
- // Despite being under the posix namespace, this also works on Windows as of zig 0.13.0
- if (tui.can_pretty_print and !opts.plain and std.posix.isatty(stdout.handle)) {
+ if (tui.can_pretty_print and !opts.plain and stdout.isTty()) {
var arena = std.heap.ArenaAllocator.init(alloc);
defer arena.deinit();
return prettyPrint(arena.allocator(), config.keybind);
} else {
try config.keybind.formatEntryDocs(
- configpkg.entryFormatter("keybind", stdout.writer()),
+ configpkg.entryFormatter("keybind", writer),
opts.docs,
);
}
+ // Don't forget to flush!
+ try writer.flush();
return 0;
}
-const TriggerList = std.SinglyLinkedList(Binding.Trigger);
+const TriggerNode = struct {
+ data: Binding.Trigger,
+ node: std.SinglyLinkedList.Node = .{},
+
+ pub fn get(node: *std.SinglyLinkedList.Node) *TriggerNode {
+ return @fieldParentPtr("node", node);
+ }
+};
const ChordBinding = struct {
- triggers: TriggerList,
+ triggers: std.SinglyLinkedList,
action: Binding.Action,
// Order keybinds based on various properties
@@ -109,7 +120,8 @@ const ChordBinding = struct {
const lhs_count: usize = blk: {
var count: usize = 0;
var maybe_trigger = lhs.triggers.first;
- while (maybe_trigger) |trigger| : (maybe_trigger = trigger.next) {
+ while (maybe_trigger) |node| : (maybe_trigger = node.next) {
+ const trigger: *TriggerNode = .get(node);
if (trigger.data.mods.super) count += 1;
if (trigger.data.mods.ctrl) count += 1;
if (trigger.data.mods.shift) count += 1;
@@ -120,7 +132,8 @@ const ChordBinding = struct {
const rhs_count: usize = blk: {
var count: usize = 0;
var maybe_trigger = rhs.triggers.first;
- while (maybe_trigger) |trigger| : (maybe_trigger = trigger.next) {
+ while (maybe_trigger) |node| : (maybe_trigger = node.next) {
+ const trigger: *TriggerNode = .get(node);
if (trigger.data.mods.super) count += 1;
if (trigger.data.mods.ctrl) count += 1;
if (trigger.data.mods.shift) count += 1;
@@ -137,8 +150,8 @@ const ChordBinding = struct {
var l_trigger = lhs.triggers.first;
var r_trigger = rhs.triggers.first;
while (l_trigger != null and r_trigger != null) {
- const l_int = l_trigger.?.data.mods.int();
- const r_int = r_trigger.?.data.mods.int();
+ const l_int = TriggerNode.get(l_trigger.?).data.mods.int();
+ const r_int = TriggerNode.get(r_trigger.?).data.mods.int();
if (l_int != r_int) {
return l_int > r_int;
@@ -154,13 +167,13 @@ const ChordBinding = struct {
while (l_trigger != null and r_trigger != null) {
const lhs_key: c_int = blk: {
- switch (l_trigger.?.data.key) {
+ switch (TriggerNode.get(l_trigger.?).data.key) {
.physical => |key| break :blk @intFromEnum(key),
.unicode => |key| break :blk @intCast(key),
}
};
const rhs_key: c_int = blk: {
- switch (r_trigger.?.data.key) {
+ switch (TriggerNode.get(r_trigger.?).data.key) {
.physical => |key| break :blk @intFromEnum(key),
.unicode => |key| break :blk @intCast(key),
}
@@ -186,19 +199,18 @@ const ChordBinding = struct {
fn prettyPrint(alloc: Allocator, keybinds: Config.Keybinds) !u8 {
// Set up vaxis
- var tty = try vaxis.Tty.init();
+ var buf: [1024]u8 = undefined;
+ var tty = try vaxis.Tty.init(&buf);
defer tty.deinit();
var vx = try vaxis.init(alloc, .{});
- defer vx.deinit(alloc, tty.anyWriter());
+ const writer = tty.writer();
+ defer vx.deinit(alloc, writer);
// We know we are ghostty, so let's enable mode 2027. Vaxis normally does this but you need an
// event loop to auto-enable it.
vx.caps.unicode = .unicode;
- try tty.anyWriter().writeAll(vaxis.ctlseqs.unicode_set);
- defer tty.anyWriter().writeAll(vaxis.ctlseqs.unicode_reset) catch {};
-
- var buf_writer = tty.bufferedWriter();
- const writer = buf_writer.writer().any();
+ try writer.writeAll(vaxis.ctlseqs.unicode_set);
+ defer writer.writeAll(vaxis.ctlseqs.unicode_reset) catch {};
const winsize: vaxis.Winsize = switch (builtin.os.tag) {
// We use some default, it doesn't really matter for what
@@ -212,7 +224,7 @@ fn prettyPrint(alloc: Allocator, keybinds: Config.Keybinds) !u8 {
else => try vaxis.Tty.getWinsize(tty.fd),
};
- try vx.resize(alloc, tty.anyWriter(), winsize);
+ try vx.resize(alloc, writer, winsize);
const win = vx.window();
@@ -234,7 +246,9 @@ fn prettyPrint(alloc: Allocator, keybinds: Config.Keybinds) !u8 {
var result: vaxis.Window.PrintResult = .{ .col = 0, .row = 0, .overflow = false };
var maybe_trigger = bind.triggers.first;
- while (maybe_trigger) |trigger| : (maybe_trigger = trigger.next) {
+ while (maybe_trigger) |node| : (maybe_trigger = node.next) {
+ const trigger: *TriggerNode = .get(node);
+
if (trigger.data.mods.super) {
result = win.printSegment(.{ .text = "super", .style = super_style }, .{ .col_offset = result.col });
result = win.printSegment(.{ .text = " + " }, .{ .col_offset = result.col });
@@ -252,18 +266,18 @@ fn prettyPrint(alloc: Allocator, keybinds: Config.Keybinds) !u8 {
result = win.printSegment(.{ .text = " + " }, .{ .col_offset = result.col });
}
const key = switch (trigger.data.key) {
- .physical => |k| try std.fmt.allocPrint(alloc, "{s}", .{@tagName(k)}),
+ .physical => |k| try std.fmt.allocPrint(alloc, "{t}", .{k}),
.unicode => |c| try std.fmt.allocPrint(alloc, "{u}", .{c}),
};
result = win.printSegment(.{ .text = key }, .{ .col_offset = result.col });
// Print a separator between chorded keys
- if (trigger.next != null) {
+ if (trigger.node.next != null) {
result = win.printSegment(.{ .text = " > ", .style = .{ .bold = true, .fg = .{ .index = 6 } } }, .{ .col_offset = result.col });
}
}
- const action = try std.fmt.allocPrint(alloc, "{}", .{bind.action});
+ const action = try std.fmt.allocPrint(alloc, "{f}", .{bind.action});
// If our action has an argument, we print the argument in a different color
if (std.mem.indexOfScalar(u8, action, ':')) |idx| {
_ = win.print(&.{
@@ -276,29 +290,33 @@ fn prettyPrint(alloc: Allocator, keybinds: Config.Keybinds) !u8 {
}
try vx.prettyPrint(writer);
}
- try buf_writer.flush();
+ try writer.flush();
return 0;
}
-fn iterateBindings(alloc: Allocator, iter: anytype, win: *const vaxis.Window) !struct { []ChordBinding, u16 } {
+fn iterateBindings(
+ alloc: Allocator,
+ iter: anytype,
+ win: *const vaxis.Window,
+) !struct { []ChordBinding, u16 } {
var widest_chord: u16 = 0;
- var bindings = std.ArrayList(ChordBinding).init(alloc);
+ var bindings: std.ArrayList(ChordBinding) = .empty;
while (iter.next()) |bind| {
const width = blk: {
- var buf = std.ArrayList(u8).init(alloc);
+ var buf: std.Io.Writer.Allocating = .init(alloc);
const t = bind.key_ptr.*;
- if (t.mods.super) try std.fmt.format(buf.writer(), "super + ", .{});
- if (t.mods.ctrl) try std.fmt.format(buf.writer(), "ctrl + ", .{});
- if (t.mods.alt) try std.fmt.format(buf.writer(), "alt + ", .{});
- if (t.mods.shift) try std.fmt.format(buf.writer(), "shift + ", .{});
+ if (t.mods.super) try buf.writer.print("super + ", .{});
+ if (t.mods.ctrl) try buf.writer.print("ctrl + ", .{});
+ if (t.mods.alt) try buf.writer.print("alt + ", .{});
+ if (t.mods.shift) try buf.writer.print("shift + ", .{});
switch (t.key) {
- .physical => |k| try std.fmt.format(buf.writer(), "{s}", .{@tagName(k)}),
- .unicode => |c| try std.fmt.format(buf.writer(), "{u}", .{c}),
+ .physical => |k| try buf.writer.print("{t}", .{k}),
+ .unicode => |c| try buf.writer.print("{u}", .{c}),
}
- break :blk win.gwidth(buf.items);
+ break :blk win.gwidth(buf.written());
};
switch (bind.value_ptr.*) {
@@ -310,28 +328,28 @@ fn iterateBindings(alloc: Allocator, iter: anytype, win: *const vaxis.Window) !s
// Prepend the current keybind onto the list of sub-binds
for (sub_bindings) |*nb| {
- const prepend_node = try alloc.create(TriggerList.Node);
- prepend_node.* = TriggerList.Node{ .data = bind.key_ptr.* };
- nb.triggers.prepend(prepend_node);
+ const prepend_node = try alloc.create(TriggerNode);
+ prepend_node.* = .{ .data = bind.key_ptr.* };
+ nb.triggers.prepend(&prepend_node.node);
}
// Add the longest sub-bind width to the current bind width along with a padding
// of 5 for the ' > ' spacer
widest_chord = @max(widest_chord, width + max_width + 5);
- try bindings.appendSlice(sub_bindings);
+ try bindings.appendSlice(alloc, sub_bindings);
},
.leaf => |leaf| {
- const node = try alloc.create(TriggerList.Node);
- node.* = TriggerList.Node{ .data = bind.key_ptr.* };
- const triggers = TriggerList{
- .first = node,
- };
+ const node = try alloc.create(TriggerNode);
+ node.* = .{ .data = bind.key_ptr.* };
widest_chord = @max(widest_chord, width);
- try bindings.append(.{ .triggers = triggers, .action = leaf.action });
+ try bindings.append(alloc, .{
+ .triggers = .{ .first = &node.node },
+ .action = leaf.action,
+ });
},
}
}
- return .{ try bindings.toOwnedSlice(), widest_chord };
+ return .{ try bindings.toOwnedSlice(alloc), widest_chord };
}
diff --git a/src/cli/list_themes.zig b/src/cli/list_themes.zig
index 0c0acfe84..cc6cfaf3e 100644
--- a/src/cli/list_themes.zig
+++ b/src/cli/list_themes.zig
@@ -57,9 +57,12 @@ const ThemeListElement = struct {
.host = .{ .raw = "" },
.path = .{ .raw = self.path },
};
- var buf = std.ArrayList(u8).init(alloc);
+ var buf: std.Io.Writer.Allocating = .init(alloc);
errdefer buf.deinit();
- try uri.writeToStream(.{ .scheme = true, .authority = true, .path = true }, buf.writer());
+ try uri.writeToStream(
+ &buf.writer,
+ .{ .scheme = true, .authority = true, .path = true },
+ );
return buf.toOwnedSlice();
}
};
@@ -114,8 +117,14 @@ pub fn run(gpa_alloc: std.mem.Allocator) !u8 {
var arena = std.heap.ArenaAllocator.init(gpa_alloc);
const alloc = arena.allocator();
- const stderr = std.io.getStdErr().writer();
- const stdout = std.io.getStdOut().writer();
+ var stdout_buf: [4096]u8 = undefined;
+ var stdout_file: std.fs.File = .stdout();
+ var stdout_writer = stdout_file.writer(&stdout_buf);
+ const stdout = &stdout_writer.interface;
+
+ var stderr_buf: [4096]u8 = undefined;
+ var stderr_writer = std.fs.File.stderr().writer(&stderr_buf);
+ const stderr = &stderr_writer.interface;
const resources_dir = global_state.resources_dir.app();
if (resources_dir == null)
@@ -124,9 +133,9 @@ pub fn run(gpa_alloc: std.mem.Allocator) !u8 {
var count: usize = 0;
- var themes = std.ArrayList(ThemeListElement).init(alloc);
+ var themes: std.ArrayList(ThemeListElement) = .empty;
- var it = themepkg.LocationIterator{ .arena_alloc = arena.allocator() };
+ var it: themepkg.LocationIterator = .{ .arena_alloc = arena.allocator() };
while (try it.next()) |loc| {
var dir = std.fs.cwd().openDir(loc.dir, .{ .iterate = true }) catch |err| switch (err) {
@@ -148,7 +157,7 @@ pub fn run(gpa_alloc: std.mem.Allocator) !u8 {
count += 1;
const path = try std.fs.path.join(alloc, &.{ loc.dir, entry.name });
- try themes.append(.{
+ try themes.append(alloc, .{
.path = path,
.location = loc.location,
.theme = try alloc.dupe(u8, entry.name),
@@ -166,18 +175,20 @@ pub fn run(gpa_alloc: std.mem.Allocator) !u8 {
std.mem.sortUnstable(ThemeListElement, themes.items, {}, ThemeListElement.lessThan);
- if (tui.can_pretty_print and !opts.plain and std.posix.isatty(std.io.getStdOut().handle)) {
+ if (tui.can_pretty_print and !opts.plain and stdout_file.isTty()) {
try preview(gpa_alloc, themes.items, opts.color);
return 0;
}
for (themes.items) |theme| {
if (opts.path)
- try stdout.print("{s} ({s}) {s}\n", .{ theme.theme, @tagName(theme.location), theme.path })
+ try stdout.print("{s} ({t}) {s}\n", .{ theme.theme, theme.location, theme.path })
else
- try stdout.print("{s} ({s})\n", .{ theme.theme, @tagName(theme.location) });
+ try stdout.print("{s} ({t})\n", .{ theme.theme, theme.location });
}
+ // Don't forget to flush!
+ try stdout.flush();
return 0;
}
@@ -209,23 +220,28 @@ const Preview = struct {
text_input: vaxis.widgets.TextInput,
theme_filter: ColorScheme,
- pub fn init(allocator: std.mem.Allocator, themes: []ThemeListElement, theme_filter: ColorScheme) !*Preview {
+ pub fn init(
+ allocator: std.mem.Allocator,
+ themes: []ThemeListElement,
+ theme_filter: ColorScheme,
+ buf: []u8,
+ ) !*Preview {
const self = try allocator.create(Preview);
self.* = .{
.allocator = allocator,
.should_quit = false,
- .tty = try vaxis.Tty.init(),
+ .tty = try .init(buf),
.vx = try vaxis.init(allocator, .{}),
.mouse = null,
.themes = themes,
- .filtered = try std.ArrayList(usize).initCapacity(allocator, themes.len),
+ .filtered = try .initCapacity(allocator, themes.len),
.current = 0,
.window = 0,
.hex = false,
.mode = .normal,
.color_scheme = .light,
- .text_input = vaxis.widgets.TextInput.init(allocator, &self.vx.unicode),
+ .text_input = .init(allocator, &self.vx.unicode),
.theme_filter = theme_filter,
};
@@ -236,9 +252,9 @@ const Preview = struct {
pub fn deinit(self: *Preview) void {
const allocator = self.allocator;
- self.filtered.deinit();
+ self.filtered.deinit(allocator);
self.text_input.deinit();
- self.vx.deinit(allocator, self.tty.anyWriter());
+ self.vx.deinit(allocator, self.tty.writer());
self.tty.deinit();
allocator.destroy(self);
}
@@ -251,12 +267,14 @@ const Preview = struct {
try loop.init();
try loop.start();
- try self.vx.enterAltScreen(self.tty.anyWriter());
- try self.vx.setTitle(self.tty.anyWriter(), "👻 Ghostty Theme Preview 👻");
- try self.vx.queryTerminal(self.tty.anyWriter(), 1 * std.time.ns_per_s);
- try self.vx.setMouseMode(self.tty.anyWriter(), true);
+ const writer = self.tty.writer();
+
+ try self.vx.enterAltScreen(writer);
+ try self.vx.setTitle(writer, "👻 Ghostty Theme Preview 👻");
+ try self.vx.queryTerminal(writer, 1 * std.time.ns_per_s);
+ try self.vx.setMouseMode(writer, true);
if (self.vx.caps.color_scheme_updates)
- try self.vx.subscribeToColorSchemeUpdates(self.tty.anyWriter());
+ try self.vx.subscribeToColorSchemeUpdates(writer);
while (!self.should_quit) {
var arena = std.heap.ArenaAllocator.init(self.allocator);
@@ -269,9 +287,8 @@ const Preview = struct {
}
try self.draw(alloc);
- var buffered = self.tty.bufferedWriter();
- try self.vx.render(buffered.writer().any());
- try buffered.flush();
+ try self.vx.render(writer);
+ try writer.flush();
}
}
@@ -308,11 +325,11 @@ const Preview = struct {
const string = try std.ascii.allocLowerString(self.allocator, buffer);
defer self.allocator.free(string);
- var tokens = std.ArrayList([]const u8).init(self.allocator);
- defer tokens.deinit();
+ var tokens: std.ArrayList([]const u8) = .empty;
+ defer tokens.deinit(self.allocator);
var it = std.mem.tokenizeScalar(u8, string, ' ');
- while (it.next()) |token| try tokens.append(token);
+ while (it.next()) |token| try tokens.append(self.allocator, token);
for (self.themes, 0..) |*theme, i| {
try theme_config.loadFile(theme_config._arena.?.allocator(), theme.path);
@@ -322,13 +339,13 @@ const Preview = struct {
.to_lower = true,
.plain = true,
});
- if (theme.rank != null) try self.filtered.append(i);
+ if (theme.rank != null) try self.filtered.append(self.allocator, i);
}
} else {
for (self.themes, 0..) |*theme, i| {
try theme_config.loadFile(theme_config._arena.?.allocator(), theme.path);
if (shouldIncludeTheme(self.theme_filter, theme_config)) {
- try self.filtered.append(i);
+ try self.filtered.append(self.allocator, i);
theme.rank = null;
}
}
@@ -421,13 +438,13 @@ const Preview = struct {
self.hex = false;
if (key.matches('c', .{}))
try self.vx.copyToSystemClipboard(
- self.tty.anyWriter(),
+ self.tty.writer(),
self.themes[self.filtered.items[self.current]].theme,
alloc,
)
else if (key.matches('c', .{ .shift = true }))
try self.vx.copyToSystemClipboard(
- self.tty.anyWriter(),
+ self.tty.writer(),
self.themes[self.filtered.items[self.current]].path,
alloc,
);
@@ -471,7 +488,7 @@ const Preview = struct {
},
.color_scheme => |color_scheme| self.color_scheme = color_scheme,
.mouse => |mouse| self.mouse = mouse,
- .winsize => |ws| try self.vx.resize(self.allocator, self.tty.anyWriter(), ws),
+ .winsize => |ws| try self.vx.resize(self.allocator, self.tty.writer(), ws),
}
}
@@ -1044,14 +1061,14 @@ const Preview = struct {
);
}
- var buf = std.ArrayList(u8).init(alloc);
+ var buf: std.Io.Writer.Allocating = .init(alloc);
defer buf.deinit();
for (config._diagnostics.items(), 0..) |diag, captured_i| {
const i: u16 = @intCast(captured_i);
- try diag.write(buf.writer());
+ try diag.format(&buf.writer);
_ = child.printSegment(
.{
- .text = buf.items,
+ .text = buf.written(),
.style = self.ui_err(),
},
.{
@@ -1319,7 +1336,7 @@ const Preview = struct {
.{ .text = "const ", .style = color5 },
.{ .text = "stdout ", .style = standard },
.{ .text = "=", .style = color5 },
- .{ .text = " std.io.getStdOut().writer();", .style = standard },
+ .{ .text = " std.Io.getStdOut().writer();", .style = standard },
},
.{
.row_offset = 7,
@@ -1651,7 +1668,13 @@ fn color(config: Config, palette: usize) vaxis.Color {
const lorem_ipsum = @embedFile("lorem_ipsum.txt");
fn preview(allocator: std.mem.Allocator, themes: []ThemeListElement, theme_filter: ColorScheme) !void {
- var app = try Preview.init(allocator, themes, theme_filter);
+ var buf: [4096]u8 = undefined;
+ var app = try Preview.init(
+ allocator,
+ themes,
+ theme_filter,
+ &buf,
+ );
defer app.deinit();
try app.run();
}
diff --git a/src/cli/new_window.zig b/src/cli/new_window.zig
index 343175b4e..f3f4740d1 100644
--- a/src/cli/new_window.zig
+++ b/src/cli/new_window.zig
@@ -26,7 +26,7 @@ pub const Options = struct {
// If it's not `-e` continue with the standard argument parsning.
if (!std.mem.eql(u8, arg, "-e")) return true;
- var arguments: std.ArrayListUnmanaged([:0]const u8) = .empty;
+ var arguments: std.ArrayList([:0]const u8) = .empty;
errdefer {
for (arguments.items) |argument| alloc.free(argument);
arguments.deinit(alloc);
@@ -99,12 +99,21 @@ pub const Options = struct {
pub fn run(alloc: Allocator) !u8 {
var iter = try args.argsIterator(alloc);
defer iter.deinit();
- return try runArgs(alloc, &iter);
+
+ var buffer: [1024]u8 = undefined;
+ var stderr_writer = std.fs.File.stderr().writer(&buffer);
+ const stderr = &stderr_writer.interface;
+
+ const result = runArgs(alloc, &iter, stderr);
+ stderr.flush() catch {};
+ return result;
}
-fn runArgs(alloc_gpa: Allocator, argsIter: anytype) !u8 {
- const stderr = std.io.getStdErr().writer();
-
+fn runArgs(
+ alloc_gpa: Allocator,
+ argsIter: anytype,
+ stderr: *std.Io.Writer,
+) !u8 {
var opts: Options = .{};
defer opts.deinit();
@@ -126,9 +135,7 @@ fn runArgs(alloc_gpa: Allocator, argsIter: anytype) !u8 {
inner: inline for (@typeInfo(Options).@"struct".fields) |field| {
if (field.name[0] == '_') continue :inner;
if (std.mem.eql(u8, field.name, diagnostic.key)) {
- try stderr.writeAll("config error: ");
- try diagnostic.write(stderr);
- try stderr.writeAll("\n");
+ try stderr.print("config error: {f}\n", .{diagnostic});
exit = true;
}
}
diff --git a/src/cli/show_config.zig b/src/cli/show_config.zig
index 3f22c75c2..1b73b77c1 100644
--- a/src/cli/show_config.zig
+++ b/src/cli/show_config.zig
@@ -77,7 +77,10 @@ pub fn run(alloc: Allocator) !u8 {
// For some reason `std.fmt.format` isn't working here but it works in
// tests so we just do configfmt.format.
- const stdout = std.io.getStdOut().writer();
- try configfmt.format("", .{}, stdout);
+ var stdout: std.fs.File = .stdout();
+ var buffer: [4096]u8 = undefined;
+ var stdout_writer = stdout.writer(&buffer);
+ try configfmt.format(&stdout_writer.interface);
+ try stdout_writer.end();
return 0;
}
diff --git a/src/cli/show_face.zig b/src/cli/show_face.zig
index e3b596bcd..9dee777b3 100644
--- a/src/cli/show_face.zig
+++ b/src/cli/show_face.zig
@@ -64,13 +64,32 @@ pub const Options = struct {
pub fn run(alloc: Allocator) !u8 {
var iter = try args.argsIterator(alloc);
defer iter.deinit();
- return try runArgs(alloc, &iter);
+
+ var stdout_buffer: [1024]u8 = undefined;
+ var stdout_writer = std.fs.File.stdout().writer(&stdout_buffer);
+ const stdout = &stdout_writer.interface;
+
+ var stderr_buffer: [1024]u8 = undefined;
+ var stderr_writer = std.fs.File.stdout().writer(&stderr_buffer);
+ const stderr = &stderr_writer.interface;
+
+ const result = runArgs(
+ alloc,
+ &iter,
+ stdout,
+ stderr,
+ );
+ stdout.flush() catch {};
+ stderr.flush() catch {};
+ return result;
}
-fn runArgs(alloc_gpa: Allocator, argsIter: anytype) !u8 {
- const stdout = std.io.getStdOut().writer();
- const stderr = std.io.getStdErr().writer();
-
+fn runArgs(
+ alloc_gpa: Allocator,
+ argsIter: anytype,
+ stdout: *std.Io.Writer,
+ stderr: *std.Io.Writer,
+) !u8 {
// Its possible to build Ghostty without font discovery!
if (comptime font.Discover == void) {
try stderr.print(
@@ -104,9 +123,7 @@ fn runArgs(alloc_gpa: Allocator, argsIter: anytype) !u8 {
inner: inline for (@typeInfo(Options).@"struct".fields) |field| {
if (field.name[0] == '_') continue :inner;
if (std.mem.eql(u8, field.name, diagnostic.key)) {
- try stderr.writeAll("config error: ");
- try diagnostic.write(stderr);
- try stderr.writeAll("\n");
+ try stderr.print("config error: {f}\n", .{diagnostic});
exit = true;
}
}
@@ -138,9 +155,7 @@ fn runArgs(alloc_gpa: Allocator, argsIter: anytype) !u8 {
if (field.name[0] == '_') continue :inner;
if (std.mem.eql(u8, field.name, diagnostic.key) and (diagnostic.location == .none or diagnostic.location == .cli)) continue :outer;
}
- try stderr.writeAll("config error: ");
- try diagnostic.write(stderr);
- try stderr.writeAll("\n");
+ try stderr.print("config error: {f}\n", .{diagnostic});
}
}
@@ -189,8 +204,8 @@ fn runArgs(alloc_gpa: Allocator, argsIter: anytype) !u8 {
fn lookup(
alloc: std.mem.Allocator,
- stdout: anytype,
- stderr: anytype,
+ stdout: *std.Io.Writer,
+ stderr: *std.Io.Writer,
font_grid: *font.SharedGrid,
style: font.Style,
presentation: ?font.Presentation,
diff --git a/src/cli/ssh-cache/DiskCache.zig b/src/cli/ssh-cache/DiskCache.zig
index db138cf37..608155dfd 100644
--- a/src/cli/ssh-cache/DiskCache.zig
+++ b/src/cli/ssh-cache/DiskCache.zig
@@ -57,8 +57,6 @@ pub fn clear(self: DiskCache) !void {
pub const AddResult = enum { added, updated };
-pub const AddError = std.fs.Dir.MakeError || std.fs.File.OpenError || std.fs.File.LockError || std.fs.File.ReadError || std.fs.File.WriteError || std.posix.RealPathError || std.posix.RenameError || Allocator.Error || error{ HostnameIsInvalid, CacheIsLocked };
-
/// Add or update a hostname entry in the cache.
/// Returns AddResult.added for new entries or AddResult.updated for existing ones.
/// The cache file is created if it doesn't exist with secure permissions (0600).
@@ -66,7 +64,7 @@ pub fn add(
self: DiskCache,
alloc: Allocator,
hostname: []const u8,
-) AddError!AddResult {
+) !AddResult {
if (!isValidCacheKey(hostname)) return error.HostnameIsInvalid;
// Create cache directory if needed
@@ -130,15 +128,13 @@ pub fn add(
return result;
}
-pub const RemoveError = std.fs.Dir.OpenError || std.fs.File.OpenError || std.fs.File.ReadError || std.fs.File.WriteError || std.posix.RealPathError || std.posix.RenameError || Allocator.Error || error{ HostnameIsInvalid, CacheIsLocked };
-
/// Remove a hostname entry from the cache.
/// No error is returned if the hostname doesn't exist or the cache file is missing.
pub fn remove(
self: DiskCache,
alloc: Allocator,
hostname: []const u8,
-) RemoveError!void {
+) !void {
if (!isValidCacheKey(hostname)) return error.HostnameIsInvalid;
// Open our file
@@ -199,7 +195,7 @@ pub fn contains(
return entries.contains(hostname);
}
-fn fixupPermissions(file: std.fs.File) !void {
+fn fixupPermissions(file: std.fs.File) (std.fs.File.StatError || std.fs.File.ChmodError)!void {
// Windows does not support chmod
if (comptime builtin.os.tag == .windows) return;
@@ -211,14 +207,12 @@ fn fixupPermissions(file: std.fs.File) !void {
}
}
-pub const WriteCacheFileError = std.fs.Dir.OpenError || std.fs.File.OpenError || std.fs.File.WriteError || std.fs.Dir.RealPathAllocError || std.posix.RealPathError || std.posix.RenameError || error{FileTooBig};
-
fn writeCacheFile(
self: DiskCache,
alloc: Allocator,
entries: std.StringHashMap(Entry),
expire_days: ?u32,
-) WriteCacheFileError!void {
+) !void {
var td: TempDir = try .init();
defer td.deinit();
@@ -227,14 +221,18 @@ fn writeCacheFile(
const tmp_path = try td.dir.realpathAlloc(alloc, "ssh-cache");
defer alloc.free(tmp_path);
- const writer = tmp_file.writer();
+ var buf: [1024]u8 = undefined;
+ var writer = tmp_file.writer(&buf);
var iter = entries.iterator();
while (iter.next()) |kv| {
// Only write non-expired entries
if (kv.value_ptr.isExpired(expire_days)) continue;
- try kv.value_ptr.format(writer);
+ try kv.value_ptr.format(&writer.interface);
}
+ // Don't forget to flush!!
+ try writer.interface.flush();
+
// Atomic replace
try std.fs.renameAbsolute(tmp_path, self.path);
}
@@ -278,8 +276,12 @@ pub fn deinitEntries(
fn readEntries(
alloc: Allocator,
file: std.fs.File,
-) (std.fs.File.ReadError || Allocator.Error || error{FileTooBig})!std.StringHashMap(Entry) {
- const content = try file.readToEndAlloc(alloc, MAX_CACHE_SIZE);
+) !std.StringHashMap(Entry) {
+ var reader = file.reader(&.{});
+ const content = try reader.interface.allocRemaining(
+ alloc,
+ .limited(MAX_CACHE_SIZE),
+ );
defer alloc.free(content);
var entries = std.StringHashMap(Entry).init(alloc);
@@ -403,10 +405,12 @@ test "disk cache clear" {
// Create our path
var td: TempDir = try .init();
defer td.deinit();
+ var buf: [4096]u8 = undefined;
{
var file = try td.dir.createFile("cache", .{});
defer file.close();
- try file.writer().writeAll("HELLO!");
+ var file_writer = file.writer(&buf);
+ try file_writer.interface.writeAll("HELLO!");
}
const path = try td.dir.realpathAlloc(alloc, "cache");
defer alloc.free(path);
@@ -429,10 +433,14 @@ test "disk cache operations" {
// Create our path
var td: TempDir = try .init();
defer td.deinit();
+ var buf: [4096]u8 = undefined;
{
var file = try td.dir.createFile("cache", .{});
defer file.close();
- try file.writer().writeAll("HELLO!");
+ var file_writer = file.writer(&buf);
+ const writer = &file_writer.interface;
+ try writer.writeAll("HELLO!");
+ try writer.flush();
}
const path = try td.dir.realpathAlloc(alloc, "cache");
defer alloc.free(path);
diff --git a/src/cli/ssh-cache/Entry.zig b/src/cli/ssh-cache/Entry.zig
index 3a691be80..f3403dbd4 100644
--- a/src/cli/ssh-cache/Entry.zig
+++ b/src/cli/ssh-cache/Entry.zig
@@ -33,7 +33,7 @@ pub fn parse(line: []const u8) ?Entry {
};
}
-pub fn format(self: Entry, writer: anytype) !void {
+pub fn format(self: Entry, writer: *std.Io.Writer) !void {
try writer.print(
"{s}|{d}|{s}\n",
.{ self.hostname, self.timestamp, self.terminfo_version },
diff --git a/src/cli/ssh_cache.zig b/src/cli/ssh_cache.zig
index 1099f0112..9434e9771 100644
--- a/src/cli/ssh_cache.zig
+++ b/src/cli/ssh_cache.zig
@@ -61,9 +61,30 @@ pub fn run(alloc_gpa: Allocator) !u8 {
try args.parse(Options, alloc_gpa, &opts, &iter);
}
- const stdout = std.io.getStdOut().writer();
- const stderr = std.io.getStdErr().writer();
+ var stdout_buffer: [1024]u8 = undefined;
+ var stdout_file: std.fs.File = .stdout();
+ var stdout_writer = stdout_file.writer(&stdout_buffer);
+ const stdout = &stdout_writer.interface;
+ var stderr_buffer: [1024]u8 = undefined;
+ var stderr_file: std.fs.File = .stderr();
+ var stderr_writer = stderr_file.writer(&stderr_buffer);
+ const stderr = &stderr_writer.interface;
+
+ const result = runInner(alloc, opts, stdout, stderr);
+
+ // Flushing *shouldn't* fail but...
+ stdout.flush() catch {};
+ stderr.flush() catch {};
+ return result;
+}
+
+pub fn runInner(
+ alloc: Allocator,
+ opts: Options,
+ stdout: *std.Io.Writer,
+ stderr: *std.Io.Writer,
+) !u8 {
// Setup our disk cache to the standard location
const cache_path = try DiskCache.defaultPath(alloc, "ghostty");
const cache: DiskCache = .{ .path = cache_path };
@@ -165,7 +186,7 @@ pub fn run(alloc_gpa: Allocator) !u8 {
fn listEntries(
alloc: Allocator,
entries: *const std.StringHashMap(Entry),
- writer: anytype,
+ writer: *std.Io.Writer,
) !void {
if (entries.count() == 0) {
try writer.print("No hosts in cache.\n", .{});
@@ -173,12 +194,12 @@ fn listEntries(
}
// Sort entries by hostname for consistent output
- var items = std.ArrayList(Entry).init(alloc);
- defer items.deinit();
+ var items: std.ArrayList(Entry) = .empty;
+ defer items.deinit(alloc);
var iter = entries.iterator();
while (iter.next()) |kv| {
- try items.append(kv.value_ptr.*);
+ try items.append(alloc, kv.value_ptr.*);
}
std.mem.sort(Entry, items.items, {}, struct {
diff --git a/src/cli/validate_config.zig b/src/cli/validate_config.zig
index 114843e9a..55d861402 100644
--- a/src/cli/validate_config.zig
+++ b/src/cli/validate_config.zig
@@ -40,8 +40,19 @@ pub fn run(alloc: std.mem.Allocator) !u8 {
try args.parse(Options, alloc, &opts, &iter);
}
- const stdout = std.io.getStdOut().writer();
+ var buffer: [1024]u8 = undefined;
+ var stdout_writer = std.fs.File.stdout().writer(&buffer);
+ const stdout = &stdout_writer.interface;
+ const result = runInner(alloc, opts, stdout);
+ try stdout_writer.end();
+ return result;
+}
+fn runInner(
+ alloc: std.mem.Allocator,
+ opts: Options,
+ stdout: *std.Io.Writer,
+) !u8 {
var cfg = try Config.default(alloc);
defer cfg.deinit();
@@ -58,15 +69,9 @@ pub fn run(alloc: std.mem.Allocator) !u8 {
try cfg.finalize();
if (cfg._diagnostics.items().len > 0) {
- var buf = std.ArrayList(u8).init(alloc);
- defer buf.deinit();
-
for (cfg._diagnostics.items()) |diag| {
- try diag.write(buf.writer());
- try stdout.print("{s}\n", .{buf.items});
- buf.clearRetainingCapacity();
+ try stdout.print("{f}\n", .{diag});
}
-
return 1;
}
diff --git a/src/cli/version.zig b/src/cli/version.zig
index 22608fa88..cf8e66fa6 100644
--- a/src/cli/version.zig
+++ b/src/cli/version.zig
@@ -15,8 +15,12 @@ pub const Options = struct {};
/// The `version` command is used to display information about Ghostty. Recognized as
/// either `+version` or `--version`.
pub fn run(alloc: Allocator) !u8 {
- const stdout = std.io.getStdOut().writer();
- const tty = std.io.getStdOut().isTty();
+ var buffer: [1024]u8 = undefined;
+ const stdout_file: std.fs.File = .stdout();
+ var stdout_writer = stdout_file.writer(&buffer);
+
+ const stdout = &stdout_writer.interface;
+ const tty = stdout_file.isTty();
if (tty) if (build_config.version.build) |commit_hash| {
try stdout.print(
@@ -29,7 +33,7 @@ pub fn run(alloc: Allocator) !u8 {
try stdout.print("Version\n", .{});
try stdout.print(" - version: {s}\n", .{build_config.version_string});
- try stdout.print(" - channel: {s}\n", .{@tagName(build_config.release_channel)});
+ try stdout.print(" - channel: {t}\n", .{build_config.release_channel});
try stdout.print("Build Config\n", .{});
try stdout.print(" - Zig version : {s}\n", .{builtin.zig_version_string});
@@ -37,20 +41,20 @@ pub fn run(alloc: Allocator) !u8 {
try stdout.print(" - app runtime : {}\n", .{build_config.app_runtime});
try stdout.print(" - font engine : {}\n", .{build_config.font_backend});
try stdout.print(" - renderer : {}\n", .{renderer.Renderer});
- try stdout.print(" - libxev : {s}\n", .{@tagName(xev.backend)});
+ try stdout.print(" - libxev : {t}\n", .{xev.backend});
if (comptime build_config.app_runtime == .gtk) {
if (comptime builtin.os.tag == .linux) {
const kernel_info = internal_os.getKernelInfo(alloc);
defer if (kernel_info) |k| alloc.free(k);
try stdout.print(" - kernel version: {s}\n", .{kernel_info orelse "Kernel information unavailable"});
}
- try stdout.print(" - desktop env : {s}\n", .{@tagName(internal_os.desktopEnvironment())});
+ try stdout.print(" - desktop env : {t}\n", .{internal_os.desktopEnvironment()});
try stdout.print(" - GTK version :\n", .{});
- try stdout.print(" build : {}\n", .{gtk_version.comptime_version});
- try stdout.print(" runtime : {}\n", .{gtk_version.getRuntimeVersion()});
+ try stdout.print(" build : {f}\n", .{gtk_version.comptime_version});
+ try stdout.print(" runtime : {f}\n", .{gtk_version.getRuntimeVersion()});
try stdout.print(" - libadwaita : enabled\n", .{});
- try stdout.print(" build : {}\n", .{adw_version.comptime_version});
- try stdout.print(" runtime : {}\n", .{adw_version.getRuntimeVersion()});
+ try stdout.print(" build : {f}\n", .{adw_version.comptime_version});
+ try stdout.print(" runtime : {f}\n", .{adw_version.getRuntimeVersion()});
if (comptime build_options.x11) {
try stdout.print(" - libX11 : enabled\n", .{});
} else {
@@ -65,5 +69,8 @@ pub fn run(alloc: Allocator) !u8 {
try stdout.print(" - libwayland : disabled\n", .{});
}
}
+
+ // Don't forget to flush!
+ try stdout.flush();
return 0;
}
diff --git a/src/config/Config.zig b/src/config/Config.zig
index 8f811e9a4..caaf5feb8 100644
--- a/src/config/Config.zig
+++ b/src/config/Config.zig
@@ -3417,10 +3417,10 @@ pub fn loadFile(self: *Config, alloc: Allocator, path: []const u8) !void {
defer file.close();
std.log.info("reading configuration file path={s}", .{path});
- var buf_reader = std.io.bufferedReader(file.reader());
- const reader = buf_reader.reader();
- const Iter = cli.args.LineIterator(@TypeOf(reader));
- var iter: Iter = .{ .r = reader, .filepath = path };
+ var buf: [2048]u8 = undefined;
+ var file_reader = file.reader(&buf);
+ const reader = &file_reader.interface;
+ var iter: cli.args.LineIterator = .{ .r = reader, .filepath = path };
try self.loadIter(alloc, &iter);
try self.expandPaths(std.fs.path.dirname(path).?);
}
@@ -3457,8 +3457,10 @@ fn writeConfigTemplate(path: []const u8) !void {
}
const file = try std.fs.createFileAbsolute(path, .{});
defer file.close();
- try std.fmt.format(
- file.writer(),
+ var buf: [4096]u8 = undefined;
+ var file_writer = file.writer(&buf);
+ const writer = &file_writer.interface;
+ try writer.print(
@embedFile("./config-template"),
.{ .path = path },
);
@@ -3628,17 +3630,17 @@ pub fn loadCliArgs(self: *Config, alloc_gpa: Allocator) !void {
// Next, take all remaining args and use that to build up
// a command to execute.
- var builder = std.ArrayList([:0]const u8).init(arena_alloc);
- errdefer builder.deinit();
+ var builder: std.ArrayList([:0]const u8) = .empty;
+ errdefer builder.deinit(arena_alloc);
for (args) |arg_raw| {
const arg = std.mem.sliceTo(arg_raw, 0);
const copy = try arena_alloc.dupeZ(u8, arg);
try self._replay_steps.append(arena_alloc, .{ .arg = copy });
- try builder.append(copy);
+ try builder.append(arena_alloc, copy);
}
self.@"_xdg-terminal-exec" = true;
- self.@"initial-command" = .{ .direct = try builder.toOwnedSlice() };
+ self.@"initial-command" = .{ .direct = try builder.toOwnedSlice(arena_alloc) };
return;
}
}
@@ -3710,13 +3712,13 @@ pub fn loadRecursiveFiles(self: *Config, alloc_gpa: Allocator) !void {
// PRIOR to the "-e" in our replay steps, since everything
// after "-e" becomes an "initial-command". To do this, we
// dupe the values if we find it.
- var replay_suffix = std.ArrayList(Replay.Step).init(alloc_gpa);
- defer replay_suffix.deinit();
+ var replay_suffix: std.ArrayList(Replay.Step) = .empty;
+ defer replay_suffix.deinit(alloc_gpa);
for (self._replay_steps.items, 0..) |step, i| if (step == .@"-e") {
// We don't need to clone the steps because they should
// all be allocated in our arena and we're keeping our
// arena.
- try replay_suffix.appendSlice(self._replay_steps.items[i..]);
+ try replay_suffix.appendSlice(alloc_gpa, self._replay_steps.items[i..]);
// Remove our old values. Again, don't need to free any
// memory here because its all part of our arena.
@@ -3744,10 +3746,11 @@ pub fn loadRecursiveFiles(self: *Config, alloc_gpa: Allocator) !void {
// We must only load a unique file once
if (try loaded.fetchPut(path, {}) != null) {
const diag: cli.Diagnostic = .{
- .message = try std.fmt.allocPrintZ(
+ .message = try std.fmt.allocPrintSentinel(
arena_alloc,
"config-file {s}: cycle detected",
.{path},
+ 0,
),
};
@@ -3759,10 +3762,11 @@ pub fn loadRecursiveFiles(self: *Config, alloc_gpa: Allocator) !void {
var file = std.fs.openFileAbsolute(path, .{}) catch |err| {
if (err != error.FileNotFound or !optional) {
const diag: cli.Diagnostic = .{
- .message = try std.fmt.allocPrintZ(
+ .message = try std.fmt.allocPrintSentinel(
arena_alloc,
"error opening config-file {s}: {}",
.{ path, err },
+ 0,
),
};
@@ -3778,10 +3782,11 @@ pub fn loadRecursiveFiles(self: *Config, alloc_gpa: Allocator) !void {
.file => {},
else => |kind| {
const diag: cli.Diagnostic = .{
- .message = try std.fmt.allocPrintZ(
+ .message = try std.fmt.allocPrintSentinel(
arena_alloc,
"config-file {s}: not reading because file type is {s}",
.{ path, @tagName(kind) },
+ 0,
),
};
@@ -3792,10 +3797,10 @@ pub fn loadRecursiveFiles(self: *Config, alloc_gpa: Allocator) !void {
}
log.info("loading config-file path={s}", .{path});
- var buf_reader = std.io.bufferedReader(file.reader());
- const reader = buf_reader.reader();
- const Iter = cli.args.LineIterator(@TypeOf(reader));
- var iter: Iter = .{ .r = reader, .filepath = path };
+ var buf: [2048]u8 = undefined;
+ var file_reader = file.reader(&buf);
+ const reader = &file_reader.interface;
+ var iter: cli.args.LineIterator = .{ .r = reader, .filepath = path };
try self.loadIter(alloc_gpa, &iter);
try self.expandPaths(std.fs.path.dirname(path).?);
}
@@ -3944,10 +3949,10 @@ fn loadTheme(self: *Config, theme: Theme) !void {
errdefer new_config.deinit();
// Load our theme
- var buf_reader = std.io.bufferedReader(file.reader());
- const reader = buf_reader.reader();
- const Iter = cli.args.LineIterator(@TypeOf(reader));
- var iter: Iter = .{ .r = reader, .filepath = path };
+ var buf: [2048]u8 = undefined;
+ var file_reader = file.reader(&buf);
+ const reader = &file_reader.interface;
+ var iter: cli.args.LineIterator = .{ .r = reader, .filepath = path };
try new_config.loadIter(alloc_gpa, &iter);
// Setup our replay to be conditional.
@@ -4190,7 +4195,7 @@ pub fn finalize(self: *Config) !void {
if (self.@"quit-after-last-window-closed-delay") |duration| {
if (duration.duration < 5 * std.time.ns_per_s) {
log.warn(
- "quit-after-last-window-closed-delay is set to a very short value ({}), which might cause problems",
+ "quit-after-last-window-closed-delay is set to a very short value ({f}), which might cause problems",
.{duration},
);
}
@@ -4221,22 +4226,23 @@ pub fn parseManuallyHook(
// Build up the command. We don't clean this up because we take
// ownership in our allocator.
- var command: std.ArrayList([:0]const u8) = .init(alloc);
- errdefer command.deinit();
+ var command: std.ArrayList([:0]const u8) = .empty;
+ errdefer command.deinit(alloc);
while (iter.next()) |param| {
const copy = try alloc.dupeZ(u8, param);
try self._replay_steps.append(alloc, .{ .arg = copy });
- try command.append(copy);
+ try command.append(alloc, copy);
}
if (command.items.len == 0) {
try self._diagnostics.append(alloc, .{
.location = try cli.Location.fromIter(iter, alloc),
- .message = try std.fmt.allocPrintZ(
+ .message = try std.fmt.allocPrintSentinel(
alloc,
"missing command after {s}",
.{arg},
+ 0,
),
});
@@ -4371,10 +4377,11 @@ pub fn addDiagnosticFmt(
) Allocator.Error!void {
const alloc = self._arena.?.allocator();
try self._diagnostics.append(alloc, .{
- .message = try std.fmt.allocPrintZ(
+ .message = try std.fmt.allocPrintSentinel(
alloc,
fmt,
args,
+ 0,
),
});
}
@@ -4892,7 +4899,7 @@ pub const Color = struct {
}
/// Used by Formatter
- pub fn formatEntry(self: Color, formatter: anytype) !void {
+ pub fn formatEntry(self: Color, formatter: formatterpkg.EntryFormatter) !void {
var buf: [128]u8 = undefined;
try formatter.formatEntry(
[]const u8,
@@ -4959,12 +4966,12 @@ pub const Color = struct {
test "formatConfig" {
const testing = std.testing;
- var buf = std.ArrayList(u8).init(testing.allocator);
+ var buf: std.Io.Writer.Allocating = .init(testing.allocator);
defer buf.deinit();
var color: Color = .{ .r = 10, .g = 11, .b = 12 };
- try color.formatEntry(formatterpkg.entryFormatter("a", buf.writer()));
- try std.testing.expectEqualSlices(u8, "a = #0a0b0c\n", buf.items);
+ try color.formatEntry(formatterpkg.entryFormatter("a", &buf.writer));
+ try std.testing.expectEqualSlices(u8, "a = #0a0b0c\n", buf.written());
}
test "parseCLI with whitespace" {
@@ -4995,7 +5002,7 @@ pub const TerminalColor = union(enum) {
}
/// Used by Formatter
- pub fn formatEntry(self: TerminalColor, formatter: anytype) !void {
+ pub fn formatEntry(self: TerminalColor, formatter: formatterpkg.EntryFormatter) !void {
switch (self) {
.color => try self.color.formatEntry(formatter),
@@ -5030,12 +5037,12 @@ pub const TerminalColor = union(enum) {
test "formatConfig" {
const testing = std.testing;
- var buf = std.ArrayList(u8).init(testing.allocator);
+ var buf: std.Io.Writer.Allocating = .init(testing.allocator);
defer buf.deinit();
var sc: TerminalColor = .@"cell-foreground";
- try sc.formatEntry(formatterpkg.entryFormatter("a", buf.writer()));
- try testing.expectEqualSlices(u8, "a = cell-foreground\n", buf.items);
+ try sc.formatEntry(formatterpkg.entryFormatter("a", &buf.writer));
+ try testing.expectEqualSlices(u8, "a = cell-foreground\n", buf.written());
}
};
@@ -5051,7 +5058,7 @@ pub const BoldColor = union(enum) {
}
/// Used by Formatter
- pub fn formatEntry(self: BoldColor, formatter: anytype) !void {
+ pub fn formatEntry(self: BoldColor, formatter: formatterpkg.EntryFormatter) !void {
switch (self) {
.color => try self.color.formatEntry(formatter),
.bright => try formatter.formatEntry(
@@ -5082,12 +5089,12 @@ pub const BoldColor = union(enum) {
test "formatConfig" {
const testing = std.testing;
- var buf = std.ArrayList(u8).init(testing.allocator);
+ var buf: std.Io.Writer.Allocating = .init(testing.allocator);
defer buf.deinit();
var sc: BoldColor = .bright;
- try sc.formatEntry(formatterpkg.entryFormatter("a", buf.writer()));
- try testing.expectEqualSlices(u8, "a = bright\n", buf.items);
+ try sc.formatEntry(formatterpkg.entryFormatter("a", &buf.writer));
+ try testing.expectEqualSlices(u8, "a = bright\n", buf.written());
}
};
@@ -5174,8 +5181,7 @@ pub const ColorList = struct {
// Build up the value of our config. Our buffer size should be
// sized to contain all possible maximum values.
var buf: [1024]u8 = undefined;
- var fbs = std.io.fixedBufferStream(&buf);
- var writer = fbs.writer();
+ var writer: std.Io.Writer = .fixed(&buf);
for (self.colors.items, 0..) |color, i| {
var color_buf: [128]u8 = undefined;
const color_str = try color.formatBuf(&color_buf);
@@ -5185,7 +5191,7 @@ pub const ColorList = struct {
try formatter.formatEntry(
[]const u8,
- fbs.getWritten(),
+ writer.buffered(),
);
}
@@ -5214,7 +5220,7 @@ pub const ColorList = struct {
test "format" {
const testing = std.testing;
- var buf = std.ArrayList(u8).init(testing.allocator);
+ var buf: std.Io.Writer.Allocating = .init(testing.allocator);
defer buf.deinit();
var arena = ArenaAllocator.init(testing.allocator);
@@ -5223,8 +5229,8 @@ pub const ColorList = struct {
var p: Self = .{};
try p.parseCLI(alloc, "black,white");
- try p.formatEntry(formatterpkg.entryFormatter("a", buf.writer()));
- try std.testing.expectEqualSlices(u8, "a = #000000,#ffffff\n", buf.items);
+ try p.formatEntry(formatterpkg.entryFormatter("a", &buf.writer));
+ try std.testing.expectEqualSlices(u8, "a = #000000,#ffffff\n", buf.written());
}
};
@@ -5285,7 +5291,7 @@ pub const Palette = struct {
}
/// Used by Formatter
- pub fn formatEntry(self: Self, formatter: anytype) !void {
+ pub fn formatEntry(self: Self, formatter: formatterpkg.EntryFormatter) !void {
var buf: [128]u8 = undefined;
for (0.., self.value) |k, v| {
try formatter.formatEntry(
@@ -5340,12 +5346,12 @@ pub const Palette = struct {
test "formatConfig" {
const testing = std.testing;
- var buf = std.ArrayList(u8).init(testing.allocator);
+ var buf: std.Io.Writer.Allocating = .init(testing.allocator);
defer buf.deinit();
var list: Self = .{};
- try list.formatEntry(formatterpkg.entryFormatter("a", buf.writer()));
- try std.testing.expectEqualSlices(u8, "a = 0=#1d1f21\n", buf.items[0..14]);
+ try list.formatEntry(formatterpkg.entryFormatter("a", &buf.writer));
+ try std.testing.expectEqualSlices(u8, "a = 0=#1d1f21\n", buf.written()[0..14]);
}
test "parseCLI with whitespace" {
@@ -5439,7 +5445,7 @@ pub const RepeatableString = struct {
}
/// Used by Formatter
- pub fn formatEntry(self: Self, formatter: anytype) !void {
+ pub fn formatEntry(self: Self, formatter: formatterpkg.EntryFormatter) !void {
// If no items, we want to render an empty field.
if (self.list.items.len == 0) {
try formatter.formatEntry(void, {});
@@ -5486,17 +5492,17 @@ pub const RepeatableString = struct {
test "formatConfig empty" {
const testing = std.testing;
- var buf = std.ArrayList(u8).init(testing.allocator);
+ var buf: std.Io.Writer.Allocating = .init(testing.allocator);
defer buf.deinit();
var list: Self = .{};
- try list.formatEntry(formatterpkg.entryFormatter("a", buf.writer()));
- try std.testing.expectEqualSlices(u8, "a = \n", buf.items);
+ try list.formatEntry(formatterpkg.entryFormatter("a", &buf.writer));
+ try std.testing.expectEqualSlices(u8, "a = \n", buf.written());
}
test "formatConfig single item" {
const testing = std.testing;
- var buf = std.ArrayList(u8).init(testing.allocator);
+ var buf: std.Io.Writer.Allocating = .init(testing.allocator);
defer buf.deinit();
var arena = ArenaAllocator.init(testing.allocator);
@@ -5505,13 +5511,13 @@ pub const RepeatableString = struct {
var list: Self = .{};
try list.parseCLI(alloc, "A");
- try list.formatEntry(formatterpkg.entryFormatter("a", buf.writer()));
- try std.testing.expectEqualSlices(u8, "a = A\n", buf.items);
+ try list.formatEntry(formatterpkg.entryFormatter("a", &buf.writer));
+ try std.testing.expectEqualSlices(u8, "a = A\n", buf.written());
}
test "formatConfig multiple items" {
const testing = std.testing;
- var buf = std.ArrayList(u8).init(testing.allocator);
+ var buf: std.Io.Writer.Allocating = .init(testing.allocator);
defer buf.deinit();
var arena = ArenaAllocator.init(testing.allocator);
@@ -5521,8 +5527,8 @@ pub const RepeatableString = struct {
var list: Self = .{};
try list.parseCLI(alloc, "A");
try list.parseCLI(alloc, "B");
- try list.formatEntry(formatterpkg.entryFormatter("a", buf.writer()));
- try std.testing.expectEqualSlices(u8, "a = A\na = B\n", buf.items);
+ try list.formatEntry(formatterpkg.entryFormatter("a", &buf.writer));
+ try std.testing.expectEqualSlices(u8, "a = A\na = B\n", buf.written());
}
};
@@ -5638,7 +5644,7 @@ pub const RepeatableFontVariation = struct {
test "formatConfig single" {
const testing = std.testing;
- var buf = std.ArrayList(u8).init(testing.allocator);
+ var buf: std.Io.Writer.Allocating = .init(testing.allocator);
defer buf.deinit();
var arena = ArenaAllocator.init(testing.allocator);
@@ -5647,8 +5653,8 @@ pub const RepeatableFontVariation = struct {
var list: Self = .{};
try list.parseCLI(alloc, "wght = 200");
- try list.formatEntry(formatterpkg.entryFormatter("a", buf.writer()));
- try std.testing.expectEqualSlices(u8, "a = wght=200\n", buf.items);
+ try list.formatEntry(formatterpkg.entryFormatter("a", &buf.writer));
+ try std.testing.expectEqualSlices(u8, "a = wght=200\n", buf.written());
}
};
@@ -6449,7 +6455,7 @@ pub const Keybinds = struct {
}
/// Like formatEntry but has an option to include docs.
- pub fn formatEntryDocs(self: Keybinds, formatter: anytype, docs: bool) !void {
+ pub fn formatEntryDocs(self: Keybinds, formatter: formatterpkg.EntryFormatter, docs: bool) !void {
if (self.set.bindings.size == 0) {
try formatter.formatEntry(void, {});
return;
@@ -6478,14 +6484,14 @@ pub const Keybinds = struct {
}
}
- var buffer_stream = std.io.fixedBufferStream(&buf);
- std.fmt.format(buffer_stream.writer(), "{}", .{k}) catch return error.OutOfMemory;
- try v.formatEntries(&buffer_stream, formatter);
+ var writer: std.Io.Writer = .fixed(&buf);
+ writer.print("{f}", .{k}) catch return error.OutOfMemory;
+ try v.formatEntries(&writer, formatter);
}
}
/// Used by Formatter
- pub fn formatEntry(self: Keybinds, formatter: anytype) !void {
+ pub fn formatEntry(self: Keybinds, formatter: formatterpkg.EntryFormatter) !void {
try self.formatEntryDocs(formatter, false);
}
@@ -6502,7 +6508,7 @@ pub const Keybinds = struct {
test "formatConfig single" {
const testing = std.testing;
- var buf = std.ArrayList(u8).init(testing.allocator);
+ var buf: std.Io.Writer.Allocating = .init(testing.allocator);
defer buf.deinit();
var arena = ArenaAllocator.init(testing.allocator);
@@ -6511,14 +6517,14 @@ pub const Keybinds = struct {
var list: Keybinds = .{};
try list.parseCLI(alloc, "shift+a=csi:hello");
- try list.formatEntry(formatterpkg.entryFormatter("a", buf.writer()));
- try std.testing.expectEqualSlices(u8, "a = shift+a=csi:hello\n", buf.items);
+ try list.formatEntry(formatterpkg.entryFormatter("a", &buf.writer));
+ try std.testing.expectEqualSlices(u8, "a = shift+a=csi:hello\n", buf.written());
}
// Regression test for https://github.com/ghostty-org/ghostty/issues/2734
test "formatConfig multiple items" {
const testing = std.testing;
- var buf = std.ArrayList(u8).init(testing.allocator);
+ var buf: std.Io.Writer.Allocating = .init(testing.allocator);
defer buf.deinit();
var arena = ArenaAllocator.init(testing.allocator);
@@ -6528,7 +6534,7 @@ pub const Keybinds = struct {
var list: Keybinds = .{};
try list.parseCLI(alloc, "ctrl+z>1=goto_tab:1");
try list.parseCLI(alloc, "ctrl+z>2=goto_tab:2");
- try list.formatEntry(formatterpkg.entryFormatter("keybind", buf.writer()));
+ try list.formatEntry(formatterpkg.entryFormatter("keybind", &buf.writer));
// Note they turn into translated keys because they match
// their ASCII mapping.
@@ -6537,12 +6543,12 @@ pub const Keybinds = struct {
\\keybind = ctrl+z>1=goto_tab:1
\\
;
- try std.testing.expectEqualStrings(want, buf.items);
+ try std.testing.expectEqualStrings(want, buf.written());
}
test "formatConfig multiple items nested" {
const testing = std.testing;
- var buf = std.ArrayList(u8).init(testing.allocator);
+ var buf: std.Io.Writer.Allocating = .init(testing.allocator);
defer buf.deinit();
var arena = ArenaAllocator.init(testing.allocator);
@@ -6554,7 +6560,7 @@ pub const Keybinds = struct {
try list.parseCLI(alloc, "ctrl+a>ctrl+b>w=close_window");
try list.parseCLI(alloc, "ctrl+a>ctrl+c>t=new_tab");
try list.parseCLI(alloc, "ctrl+b>ctrl+d>a=previous_tab");
- try list.formatEntry(formatterpkg.entryFormatter("a", buf.writer()));
+ try list.formatEntry(formatterpkg.entryFormatter("a", &buf.writer));
// NB: This does not currently retain the order of the keybinds.
const want =
@@ -6564,7 +6570,7 @@ pub const Keybinds = struct {
\\a = ctrl+b>ctrl+d>a=previous_tab
\\
;
- try std.testing.expectEqualStrings(want, buf.items);
+ try std.testing.expectEqualStrings(want, buf.written());
}
};
@@ -6790,7 +6796,7 @@ pub const RepeatableCodepointMap = struct {
test "formatConfig single" {
const testing = std.testing;
- var buf = std.ArrayList(u8).init(testing.allocator);
+ var buf: std.Io.Writer.Allocating = .init(testing.allocator);
defer buf.deinit();
var arena = ArenaAllocator.init(testing.allocator);
@@ -6799,13 +6805,13 @@ pub const RepeatableCodepointMap = struct {
var list: Self = .{};
try list.parseCLI(alloc, "U+ABCD=Comic Sans");
- try list.formatEntry(formatterpkg.entryFormatter("a", buf.writer()));
- try std.testing.expectEqualSlices(u8, "a = U+ABCD=Comic Sans\n", buf.items);
+ try list.formatEntry(formatterpkg.entryFormatter("a", &buf.writer));
+ try std.testing.expectEqualSlices(u8, "a = U+ABCD=Comic Sans\n", buf.written());
}
test "formatConfig range" {
const testing = std.testing;
- var buf = std.ArrayList(u8).init(testing.allocator);
+ var buf: std.Io.Writer.Allocating = .init(testing.allocator);
defer buf.deinit();
var arena = ArenaAllocator.init(testing.allocator);
@@ -6814,13 +6820,13 @@ pub const RepeatableCodepointMap = struct {
var list: Self = .{};
try list.parseCLI(alloc, "U+0001 - U+0005=Verdana");
- try list.formatEntry(formatterpkg.entryFormatter("a", buf.writer()));
- try std.testing.expectEqualSlices(u8, "a = U+0001-U+0005=Verdana\n", buf.items);
+ try list.formatEntry(formatterpkg.entryFormatter("a", &buf.writer));
+ try std.testing.expectEqualSlices(u8, "a = U+0001-U+0005=Verdana\n", buf.written());
}
test "formatConfig multiple" {
const testing = std.testing;
- var buf = std.ArrayList(u8).init(testing.allocator);
+ var buf: std.Io.Writer.Allocating = .init(testing.allocator);
defer buf.deinit();
var arena = ArenaAllocator.init(testing.allocator);
@@ -6829,12 +6835,12 @@ pub const RepeatableCodepointMap = struct {
var list: Self = .{};
try list.parseCLI(alloc, "U+0006-U+0009, U+ABCD=Courier");
- try list.formatEntry(formatterpkg.entryFormatter("a", buf.writer()));
+ try list.formatEntry(formatterpkg.entryFormatter("a", &buf.writer));
try std.testing.expectEqualSlices(u8,
\\a = U+0006-U+0009=Courier
\\a = U+ABCD=Courier
\\
- , buf.items);
+ , buf.written());
}
};
@@ -6886,7 +6892,7 @@ pub const FontStyle = union(enum) {
}
/// Used by Formatter
- pub fn formatEntry(self: Self, formatter: anytype) !void {
+ pub fn formatEntry(self: Self, formatter: formatterpkg.EntryFormatter) !void {
switch (self) {
.default, .false => try formatter.formatEntry(
[]const u8,
@@ -6918,7 +6924,7 @@ pub const FontStyle = union(enum) {
test "formatConfig default" {
const testing = std.testing;
- var buf = std.ArrayList(u8).init(testing.allocator);
+ var buf: std.Io.Writer.Allocating = .init(testing.allocator);
defer buf.deinit();
var arena = ArenaAllocator.init(testing.allocator);
@@ -6927,13 +6933,13 @@ pub const FontStyle = union(enum) {
var p: Self = .{ .default = {} };
try p.parseCLI(alloc, "default");
- try p.formatEntry(formatterpkg.entryFormatter("a", buf.writer()));
- try std.testing.expectEqualSlices(u8, "a = default\n", buf.items);
+ try p.formatEntry(formatterpkg.entryFormatter("a", &buf.writer));
+ try std.testing.expectEqualSlices(u8, "a = default\n", buf.written());
}
test "formatConfig false" {
const testing = std.testing;
- var buf = std.ArrayList(u8).init(testing.allocator);
+ var buf: std.Io.Writer.Allocating = .init(testing.allocator);
defer buf.deinit();
var arena = ArenaAllocator.init(testing.allocator);
@@ -6942,13 +6948,13 @@ pub const FontStyle = union(enum) {
var p: Self = .{ .default = {} };
try p.parseCLI(alloc, "false");
- try p.formatEntry(formatterpkg.entryFormatter("a", buf.writer()));
- try std.testing.expectEqualSlices(u8, "a = false\n", buf.items);
+ try p.formatEntry(formatterpkg.entryFormatter("a", &buf.writer));
+ try std.testing.expectEqualSlices(u8, "a = false\n", buf.written());
}
test "formatConfig named" {
const testing = std.testing;
- var buf = std.ArrayList(u8).init(testing.allocator);
+ var buf: std.Io.Writer.Allocating = .init(testing.allocator);
defer buf.deinit();
var arena = ArenaAllocator.init(testing.allocator);
@@ -6957,8 +6963,8 @@ pub const FontStyle = union(enum) {
var p: Self = .{ .default = {} };
try p.parseCLI(alloc, "bold");
- try p.formatEntry(formatterpkg.entryFormatter("a", buf.writer()));
- try std.testing.expectEqualSlices(u8, "a = bold\n", buf.items);
+ try p.formatEntry(formatterpkg.entryFormatter("a", &buf.writer));
+ try std.testing.expectEqualSlices(u8, "a = bold\n", buf.written());
}
};
@@ -7018,7 +7024,7 @@ pub const RepeatableLink = struct {
}
/// Used by Formatter
- pub fn formatEntry(self: Self, formatter: anytype) !void {
+ pub fn formatEntry(self: Self, formatter: formatterpkg.EntryFormatter) !void {
// This currently can't be set so we don't format anything.
_ = self;
_ = formatter;
@@ -7128,7 +7134,10 @@ pub const RepeatableCommand = struct {
}
/// Used by Formatter
- pub fn formatEntry(self: RepeatableCommand, formatter: anytype) !void {
+ pub fn formatEntry(
+ self: RepeatableCommand,
+ formatter: formatterpkg.EntryFormatter,
+ ) !void {
if (self.value.items.len == 0) {
try formatter.formatEntry(void, {});
return;
@@ -7136,22 +7145,23 @@ pub const RepeatableCommand = struct {
for (self.value.items) |item| {
var buf: [4096]u8 = undefined;
- var fbs = std.io.fixedBufferStream(&buf);
- var writer = fbs.writer();
+ var writer: std.Io.Writer = .fixed(&buf);
- writer.writeAll("title:\"") catch return error.OutOfMemory;
- std.zig.stringEscape(item.title, "", .{}, writer) catch return error.OutOfMemory;
- writer.writeAll("\"") catch return error.OutOfMemory;
+ writer.print(
+ "title:\"{f}\"",
+ .{std.zig.fmtString(item.title)},
+ ) catch return error.OutOfMemory;
if (item.description.len > 0) {
- writer.writeAll(",description:\"") catch return error.OutOfMemory;
- std.zig.stringEscape(item.description, "", .{}, writer) catch return error.OutOfMemory;
- writer.writeAll("\"") catch return error.OutOfMemory;
+ writer.print(
+ ",description:\"{f}\"",
+ .{std.zig.fmtString(item.description)},
+ ) catch return error.OutOfMemory;
}
- writer.print(",action:\"{}\"", .{item.action}) catch return error.OutOfMemory;
+ writer.print(",action:\"{f}\"", .{item.action}) catch return error.OutOfMemory;
- try formatter.formatEntry([]const u8, fbs.getWritten());
+ try formatter.formatEntry([]const u8, writer.buffered());
}
}
@@ -7197,17 +7207,17 @@ pub const RepeatableCommand = struct {
test "RepeatableCommand formatConfig empty" {
const testing = std.testing;
- var buf = std.ArrayList(u8).init(testing.allocator);
+ var buf: std.Io.Writer.Allocating = .init(testing.allocator);
defer buf.deinit();
var list: RepeatableCommand = .{};
- try list.formatEntry(formatterpkg.entryFormatter("a", buf.writer()));
- try std.testing.expectEqualSlices(u8, "a = \n", buf.items);
+ try list.formatEntry(formatterpkg.entryFormatter("a", &buf.writer));
+ try std.testing.expectEqualSlices(u8, "a = \n", buf.written());
}
test "RepeatableCommand formatConfig single item" {
const testing = std.testing;
- var buf = std.ArrayList(u8).init(testing.allocator);
+ var buf: std.Io.Writer.Allocating = .init(testing.allocator);
defer buf.deinit();
var arena = ArenaAllocator.init(testing.allocator);
@@ -7216,13 +7226,13 @@ pub const RepeatableCommand = struct {
var list: RepeatableCommand = .{};
try list.parseCLI(alloc, "title:Bobr, action:text:Bober");
- try list.formatEntry(formatterpkg.entryFormatter("a", buf.writer()));
- try std.testing.expectEqualSlices(u8, "a = title:\"Bobr\",action:\"text:Bober\"\n", buf.items);
+ try list.formatEntry(formatterpkg.entryFormatter("a", &buf.writer));
+ try std.testing.expectEqualSlices(u8, "a = title:\"Bobr\",action:\"text:Bober\"\n", buf.written());
}
test "RepeatableCommand formatConfig multiple items" {
const testing = std.testing;
- var buf = std.ArrayList(u8).init(testing.allocator);
+ var buf: std.Io.Writer.Allocating = .init(testing.allocator);
defer buf.deinit();
var arena = ArenaAllocator.init(testing.allocator);
@@ -7232,14 +7242,12 @@ pub const RepeatableCommand = struct {
var list: RepeatableCommand = .{};
try list.parseCLI(alloc, "title:Bobr, action:text:kurwa");
try list.parseCLI(alloc, "title:Ja, description: pierdole, action:text:jakie bydle");
- try list.formatEntry(formatterpkg.entryFormatter("a", buf.writer()));
- try std.testing.expectEqualSlices(u8, "a = title:\"Bobr\",action:\"text:kurwa\"\na = title:\"Ja\",description:\"pierdole\",action:\"text:jakie bydle\"\n", buf.items);
+ try list.formatEntry(formatterpkg.entryFormatter("a", &buf.writer));
+ try std.testing.expectEqualSlices(u8, "a = title:\"Bobr\",action:\"text:kurwa\"\na = title:\"Ja\",description:\"pierdole\",action:\"text:jakie bydle\"\n", buf.written());
}
test "RepeatableCommand parseCLI commas" {
const testing = std.testing;
- var buf = std.ArrayList(u8).init(testing.allocator);
- defer buf.deinit();
var arena = ArenaAllocator.init(testing.allocator);
defer arena.deinit();
@@ -7455,14 +7463,14 @@ pub const MouseScrollMultiplier = struct {
}
/// Used by Formatter
- pub fn formatEntry(self: Self, formatter: anytype) !void {
- var buf: [32]u8 = undefined;
- const formatted = std.fmt.bufPrint(
- &buf,
+ pub fn formatEntry(self: Self, formatter: formatterpkg.EntryFormatter) !void {
+ var buf: [4096]u8 = undefined;
+ var writer: std.Io.Writer = .fixed(&buf);
+ writer.print(
"precision:{d},discrete:{d}",
.{ self.precision, self.discrete },
) catch return error.OutOfMemory;
- try formatter.formatEntry([]const u8, formatted);
+ try formatter.formatEntry([]const u8, writer.buffered());
}
test "parse" {
@@ -7505,12 +7513,12 @@ pub const MouseScrollMultiplier = struct {
test "format entry MouseScrollMultiplier" {
const testing = std.testing;
- var buf = std.ArrayList(u8).init(testing.allocator);
+ var buf: std.Io.Writer.Allocating = .init(testing.allocator);
defer buf.deinit();
var args: Self = .{ .precision = 1.5, .discrete = 2.5 };
- try args.formatEntry(formatterpkg.entryFormatter("mouse-scroll-multiplier", buf.writer()));
- try testing.expectEqualSlices(u8, "mouse-scroll-multiplier = precision:1.5,discrete:2.5\n", buf.items);
+ try args.formatEntry(formatterpkg.entryFormatter("mouse-scroll-multiplier", &buf.writer));
+ try testing.expectEqualSlices(u8, "mouse-scroll-multiplier = precision:1.5,discrete:2.5\n", buf.written());
}
};
@@ -7627,7 +7635,7 @@ pub const QuickTerminalSize = struct {
return error.MissingUnit;
}
- fn format(self: Size, writer: anytype) !void {
+ fn format(self: Size, writer: *std.Io.Writer) !void {
switch (self) {
.percentage => |v| try writer.print("{d}%", .{v}),
.pixels => |v| try writer.print("{}px", .{v}),
@@ -7745,20 +7753,19 @@ pub const QuickTerminalSize = struct {
};
}
- pub fn formatEntry(self: QuickTerminalSize, formatter: anytype) !void {
+ pub fn formatEntry(self: QuickTerminalSize, formatter: formatterpkg.EntryFormatter) !void {
const primary = self.primary orelse return;
var buf: [4096]u8 = undefined;
- var fbs = std.io.fixedBufferStream(&buf);
- const writer = fbs.writer();
+ var writer: std.Io.Writer = .fixed(&buf);
- primary.format(writer) catch return error.OutOfMemory;
+ primary.format(&writer) catch return error.OutOfMemory;
if (self.secondary) |secondary| {
writer.writeByte(',') catch return error.OutOfMemory;
- secondary.format(writer) catch return error.OutOfMemory;
+ secondary.format(&writer) catch return error.OutOfMemory;
}
- try formatter.formatEntry([]const u8, fbs.getWritten());
+ try formatter.formatEntry([]const u8, writer.buffered());
}
test "parse QuickTerminalSize" {
@@ -8318,15 +8325,17 @@ pub const Duration = struct {
return if (value) |v| .{ .duration = v } else error.ValueRequired;
}
- pub fn formatEntry(self: Duration, formatter: anytype) !void {
+ pub fn formatEntry(self: Duration, formatter: formatterpkg.EntryFormatter) !void {
var buf: [64]u8 = undefined;
- var fbs = std.io.fixedBufferStream(&buf);
- const writer = fbs.writer();
- try self.format("", .{}, writer);
- try formatter.formatEntry([]const u8, fbs.getWritten());
+ var writer: std.Io.Writer = .fixed(&buf);
+ try self.format(&writer);
+ try formatter.formatEntry([]const u8, writer.buffered());
}
- pub fn format(self: Duration, comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void {
+ pub fn format(
+ self: Duration,
+ writer: *std.Io.Writer,
+ ) !void {
var value = self.duration;
var i: usize = 0;
for (units) |unit| {
@@ -8393,7 +8402,7 @@ pub const WindowPadding = struct {
}
}
- pub fn formatEntry(self: Self, formatter: anytype) !void {
+ pub fn formatEntry(self: Self, formatter: formatterpkg.EntryFormatter) !void {
var buf: [128]u8 = undefined;
if (self.top_left == self.bottom_right) {
try formatter.formatEntry(
@@ -8555,7 +8564,7 @@ test "test format" {
inline for (Duration.units) |unit| {
const d: Duration = .{ .duration = unit.factor };
var actual_buf: [16]u8 = undefined;
- const actual = try std.fmt.bufPrint(&actual_buf, "{}", .{d});
+ const actual = try std.fmt.bufPrint(&actual_buf, "{f}", .{d});
var expected_buf: [16]u8 = undefined;
const expected = if (!std.mem.eql(u8, unit.name, "us"))
try std.fmt.bufPrint(&expected_buf, "1{s}", .{unit.name})
@@ -8566,12 +8575,12 @@ test "test format" {
}
test "test entryFormatter" {
- var buf = std.ArrayList(u8).init(std.testing.allocator);
+ var buf: std.Io.Writer.Allocating = .init(std.testing.allocator);
defer buf.deinit();
var p: Duration = .{ .duration = std.math.maxInt(u64) };
- try p.formatEntry(formatterpkg.entryFormatter("a", buf.writer()));
- try std.testing.expectEqualStrings("a = 584y 49w 23h 34m 33s 709ms 551µs 615ns\n", buf.items);
+ try p.formatEntry(formatterpkg.entryFormatter("a", &buf.writer));
+ try std.testing.expectEqualStrings("a = 584y 49w 23h 34m 33s 709ms 551µs 615ns\n", buf.written());
}
const TestIterator = struct {
@@ -8681,15 +8690,20 @@ test "clone can then change conditional state" {
// Setup our test theme
var td = try internal_os.TempDir.init();
defer td.deinit();
+ var buf: [4096]u8 = undefined;
{
var file = try td.dir.createFile("theme_light", .{});
defer file.close();
- try file.writer().writeAll(@embedFile("testdata/theme_light"));
+ var writer = file.writer(&buf);
+ try writer.interface.writeAll(@embedFile("testdata/theme_light"));
+ try writer.end();
}
{
var file = try td.dir.createFile("theme_dark", .{});
defer file.close();
- try file.writer().writeAll(@embedFile("testdata/theme_dark"));
+ var writer = file.writer(&buf);
+ try writer.interface.writeAll(@embedFile("testdata/theme_dark"));
+ try writer.end();
}
var light_buf: [std.fs.max_path_bytes]u8 = undefined;
const light = try td.dir.realpath("theme_light", &light_buf);
@@ -8815,10 +8829,13 @@ test "theme loading" {
// Setup our test theme
var td = try internal_os.TempDir.init();
defer td.deinit();
+ var buf: [4096]u8 = undefined;
{
var file = try td.dir.createFile("theme", .{});
defer file.close();
- try file.writer().writeAll(@embedFile("testdata/theme_simple"));
+ var writer = file.writer(&buf);
+ try writer.interface.writeAll(@embedFile("testdata/theme_simple"));
+ try writer.end();
}
var path_buf: [std.fs.max_path_bytes]u8 = undefined;
const path = try td.dir.realpath("theme", &path_buf);
@@ -8851,10 +8868,13 @@ test "theme loading preserves conditional state" {
// Setup our test theme
var td = try internal_os.TempDir.init();
defer td.deinit();
+ var buf: [4096]u8 = undefined;
{
var file = try td.dir.createFile("theme", .{});
defer file.close();
- try file.writer().writeAll(@embedFile("testdata/theme_simple"));
+ var writer = file.writer(&buf);
+ try writer.interface.writeAll(@embedFile("testdata/theme_simple"));
+ try writer.end();
}
var path_buf: [std.fs.max_path_bytes]u8 = undefined;
const path = try td.dir.realpath("theme", &path_buf);
@@ -8881,10 +8901,13 @@ test "theme priority is lower than config" {
// Setup our test theme
var td = try internal_os.TempDir.init();
defer td.deinit();
+ var buf: [4096]u8 = undefined;
{
var file = try td.dir.createFile("theme", .{});
defer file.close();
- try file.writer().writeAll(@embedFile("testdata/theme_simple"));
+ var writer = file.writer(&buf);
+ try writer.interface.writeAll(@embedFile("testdata/theme_simple"));
+ try writer.end();
}
var path_buf: [std.fs.max_path_bytes]u8 = undefined;
const path = try td.dir.realpath("theme", &path_buf);
@@ -8915,15 +8938,20 @@ test "theme loading correct light/dark" {
// Setup our test theme
var td = try internal_os.TempDir.init();
defer td.deinit();
+ var buf: [4096]u8 = undefined;
{
var file = try td.dir.createFile("theme_light", .{});
defer file.close();
- try file.writer().writeAll(@embedFile("testdata/theme_light"));
+ var writer = file.writer(&buf);
+ try writer.interface.writeAll(@embedFile("testdata/theme_light"));
+ try writer.end();
}
{
var file = try td.dir.createFile("theme_dark", .{});
defer file.close();
- try file.writer().writeAll(@embedFile("testdata/theme_dark"));
+ var writer = file.writer(&buf);
+ try writer.interface.writeAll(@embedFile("testdata/theme_dark"));
+ try writer.end();
}
var light_buf: [std.fs.max_path_bytes]u8 = undefined;
const light = try td.dir.realpath("theme_light", &light_buf);
diff --git a/src/config/RepeatableStringMap.zig b/src/config/RepeatableStringMap.zig
index 6f143e95d..d5e634333 100644
--- a/src/config/RepeatableStringMap.zig
+++ b/src/config/RepeatableStringMap.zig
@@ -104,7 +104,7 @@ pub fn equal(self: RepeatableStringMap, other: RepeatableStringMap) bool {
}
/// Used by formatter
-pub fn formatEntry(self: RepeatableStringMap, formatter: anytype) !void {
+pub fn formatEntry(self: RepeatableStringMap, formatter: formatterpkg.EntryFormatter) !void {
// If no items, we want to render an empty field.
if (self.map.count() == 0) {
try formatter.formatEntry(void, {});
@@ -146,12 +146,12 @@ test "RepeatableStringMap: parseCLI" {
test "RepeatableStringMap: formatConfig empty" {
const testing = std.testing;
- var buf = std.ArrayList(u8).init(testing.allocator);
+ var buf: std.Io.Writer.Allocating = .init(testing.allocator);
defer buf.deinit();
var list: RepeatableStringMap = .{};
- try list.formatEntry(formatterpkg.entryFormatter("a", buf.writer()));
- try std.testing.expectEqualSlices(u8, "a = \n", buf.items);
+ try list.formatEntry(formatterpkg.entryFormatter("a", &buf.writer));
+ try std.testing.expectEqualSlices(u8, "a = \n", buf.written());
}
test "RepeatableStringMap: formatConfig single item" {
@@ -162,20 +162,20 @@ test "RepeatableStringMap: formatConfig single item" {
const alloc = arena.allocator();
{
- var buf = std.ArrayList(u8).init(testing.allocator);
+ var buf: std.Io.Writer.Allocating = .init(testing.allocator);
defer buf.deinit();
var map: RepeatableStringMap = .{};
try map.parseCLI(alloc, "A=B");
- try map.formatEntry(formatterpkg.entryFormatter("a", buf.writer()));
- try std.testing.expectEqualSlices(u8, "a = A=B\n", buf.items);
+ try map.formatEntry(formatterpkg.entryFormatter("a", &buf.writer));
+ try std.testing.expectEqualSlices(u8, "a = A=B\n", buf.written());
}
{
- var buf = std.ArrayList(u8).init(testing.allocator);
+ var buf: std.Io.Writer.Allocating = .init(testing.allocator);
defer buf.deinit();
var map: RepeatableStringMap = .{};
try map.parseCLI(alloc, " A = B ");
- try map.formatEntry(formatterpkg.entryFormatter("a", buf.writer()));
- try std.testing.expectEqualSlices(u8, "a = A=B\n", buf.items);
+ try map.formatEntry(formatterpkg.entryFormatter("a", &buf.writer));
+ try std.testing.expectEqualSlices(u8, "a = A=B\n", buf.written());
}
}
@@ -187,12 +187,12 @@ test "RepeatableStringMap: formatConfig multiple items" {
const alloc = arena.allocator();
{
- var buf = std.ArrayList(u8).init(testing.allocator);
+ var buf: std.Io.Writer.Allocating = .init(testing.allocator);
defer buf.deinit();
var list: RepeatableStringMap = .{};
try list.parseCLI(alloc, "A=B");
try list.parseCLI(alloc, "B = C");
- try list.formatEntry(formatterpkg.entryFormatter("a", buf.writer()));
- try std.testing.expectEqualSlices(u8, "a = A=B\na = B=C\n", buf.items);
+ try list.formatEntry(formatterpkg.entryFormatter("a", &buf.writer));
+ try std.testing.expectEqualSlices(u8, "a = A=B\na = B=C\n", buf.written());
}
}
diff --git a/src/config/command.zig b/src/config/command.zig
index 9efeb199e..e0cdc641b 100644
--- a/src/config/command.zig
+++ b/src/config/command.zig
@@ -166,21 +166,20 @@ pub const Command = union(enum) {
};
}
- pub fn formatEntry(self: Self, formatter: anytype) !void {
+ pub fn formatEntry(self: Self, formatter: formatterpkg.EntryFormatter) !void {
switch (self) {
.shell => |v| try formatter.formatEntry([]const u8, v),
.direct => |v| {
var buf: [4096]u8 = undefined;
- var fbs = std.io.fixedBufferStream(&buf);
- const writer = fbs.writer();
+ var writer: std.Io.Writer = .fixed(&buf);
writer.writeAll("direct:") catch return error.OutOfMemory;
for (v) |arg| {
writer.writeAll(arg) catch return error.OutOfMemory;
writer.writeByte(' ') catch return error.OutOfMemory;
}
- const written = fbs.getWritten();
+ const written = writer.buffered();
try formatter.formatEntry(
[]const u8,
written[0..@intCast(written.len - 1)],
@@ -292,13 +291,13 @@ pub const Command = union(enum) {
defer arena.deinit();
const alloc = arena.allocator();
- var buf = std.ArrayList(u8).init(alloc);
+ var buf: std.Io.Writer.Allocating = .init(alloc);
defer buf.deinit();
var v: Self = undefined;
try v.parseCLI(alloc, "echo hello");
- try v.formatEntry(formatterpkg.entryFormatter("a", buf.writer()));
- try std.testing.expectEqualSlices(u8, "a = echo hello\n", buf.items);
+ try v.formatEntry(formatterpkg.entryFormatter("a", &buf.writer));
+ try std.testing.expectEqualSlices(u8, "a = echo hello\n", buf.written());
}
test "Command: formatConfig direct" {
@@ -307,13 +306,13 @@ pub const Command = union(enum) {
defer arena.deinit();
const alloc = arena.allocator();
- var buf = std.ArrayList(u8).init(alloc);
+ var buf: std.Io.Writer.Allocating = .init(alloc);
defer buf.deinit();
var v: Self = undefined;
try v.parseCLI(alloc, "direct: echo hello");
- try v.formatEntry(formatterpkg.entryFormatter("a", buf.writer()));
- try std.testing.expectEqualSlices(u8, "a = direct:echo hello\n", buf.items);
+ try v.formatEntry(formatterpkg.entryFormatter("a", &buf.writer));
+ try std.testing.expectEqualSlices(u8, "a = direct:echo hello\n", buf.written());
}
};
diff --git a/src/config/edit.zig b/src/config/edit.zig
index 38dc98169..07bb7ee5a 100644
--- a/src/config/edit.zig
+++ b/src/config/edit.zig
@@ -89,8 +89,8 @@ fn configPath(alloc_arena: Allocator) ![]const u8 {
/// Returns a const list of possible paths the main config file could be
/// in for the current OS.
fn configPathCandidates(alloc_arena: Allocator) ![]const []const u8 {
- var paths = try std.ArrayList([]const u8).initCapacity(alloc_arena, 2);
- errdefer paths.deinit();
+ var paths: std.ArrayList([]const u8) = try .initCapacity(alloc_arena, 2);
+ errdefer paths.deinit(alloc_arena);
if (comptime builtin.os.tag == .macos) {
paths.appendAssumeCapacity(try internal_os.macos.appSupportDir(
diff --git a/src/config/formatter.zig b/src/config/formatter.zig
index a42395c19..dcf99167d 100644
--- a/src/config/formatter.zig
+++ b/src/config/formatter.zig
@@ -8,38 +8,36 @@ const Key = @import("key.zig").Key;
/// Returns a single entry formatter for the given field name and writer.
pub fn entryFormatter(
name: []const u8,
- writer: anytype,
-) EntryFormatter(@TypeOf(writer)) {
+ writer: *std.Io.Writer,
+) EntryFormatter {
return .{ .name = name, .writer = writer };
}
/// The entry formatter type for a given writer.
-pub fn EntryFormatter(comptime WriterType: type) type {
- return struct {
- name: []const u8,
- writer: WriterType,
+pub const EntryFormatter = struct {
+ name: []const u8,
+ writer: *std.Io.Writer,
- pub fn formatEntry(
- self: @This(),
- comptime T: type,
- value: T,
- ) !void {
- return formatter.formatEntry(
- T,
- self.name,
- value,
- self.writer,
- );
- }
- };
-}
+ pub fn formatEntry(
+ self: @This(),
+ comptime T: type,
+ value: T,
+ ) !void {
+ return formatter.formatEntry(
+ T,
+ self.name,
+ value,
+ self.writer,
+ );
+ }
+};
/// Format a single type with the given name and value.
pub fn formatEntry(
comptime T: type,
name: []const u8,
value: T,
- writer: anytype,
+ writer: *std.Io.Writer,
) !void {
switch (@typeInfo(T)) {
.bool, .int => {
@@ -53,7 +51,7 @@ pub fn formatEntry(
},
.@"enum" => {
- try writer.print("{s} = {s}\n", .{ name, @tagName(value) });
+ try writer.print("{s} = {t}\n", .{ name, value });
return;
},
@@ -143,19 +141,14 @@ pub const FileFormatter = struct {
/// Implements std.fmt so it can be used directly with std.fmt.
pub fn format(
self: FileFormatter,
- comptime layout: []const u8,
- opts: std.fmt.FormatOptions,
- writer: anytype,
- ) !void {
+ writer: *std.Io.Writer,
+ ) std.Io.Writer.Error!void {
@setEvalBranchQuota(10_000);
- _ = layout;
- _ = opts;
-
// If we're change-tracking then we need the default config to
// compare against.
var default: ?Config = if (self.changed)
- try .default(self.alloc)
+ Config.default(self.alloc) catch return error.WriteFailed
else
null;
defer if (default) |*v| v.deinit();
@@ -179,12 +172,12 @@ pub const FileFormatter = struct {
}
}
- try formatEntry(
+ formatEntry(
field.type,
field.name,
value,
writer,
- );
+ ) catch return error.WriteFailed;
if (do_docs) try writer.print("\n", .{});
}
@@ -198,7 +191,7 @@ test "format default config" {
var cfg = try Config.default(alloc);
defer cfg.deinit();
- var buf = std.ArrayList(u8).init(alloc);
+ var buf: std.Io.Writer.Allocating = .init(alloc);
defer buf.deinit();
// We just make sure this works without errors. We aren't asserting output.
@@ -206,9 +199,9 @@ test "format default config" {
.alloc = alloc,
.config = &cfg,
};
- try std.fmt.format(buf.writer(), "{}", .{fmt});
+ try fmt.format(&buf.writer);
- //std.log.warn("{s}", .{buf.items});
+ //std.log.warn("{s}", .{buf.written()});
}
test "format default config changed" {
@@ -218,7 +211,7 @@ test "format default config changed" {
defer cfg.deinit();
cfg.@"font-size" = 42;
- var buf = std.ArrayList(u8).init(alloc);
+ var buf: std.Io.Writer.Allocating = .init(alloc);
defer buf.deinit();
// We just make sure this works without errors. We aren't asserting output.
@@ -227,26 +220,26 @@ test "format default config changed" {
.config = &cfg,
.changed = true,
};
- try std.fmt.format(buf.writer(), "{}", .{fmt});
+ try fmt.format(&buf.writer);
- //std.log.warn("{s}", .{buf.items});
+ //std.log.warn("{s}", .{buf.written()});
}
test "formatEntry bool" {
const testing = std.testing;
{
- var buf = std.ArrayList(u8).init(testing.allocator);
+ var buf: std.Io.Writer.Allocating = .init(testing.allocator);
defer buf.deinit();
- try formatEntry(bool, "a", true, buf.writer());
- try testing.expectEqualStrings("a = true\n", buf.items);
+ try formatEntry(bool, "a", true, &buf.writer);
+ try testing.expectEqualStrings("a = true\n", buf.written());
}
{
- var buf = std.ArrayList(u8).init(testing.allocator);
+ var buf: std.Io.Writer.Allocating = .init(testing.allocator);
defer buf.deinit();
- try formatEntry(bool, "a", false, buf.writer());
- try testing.expectEqualStrings("a = false\n", buf.items);
+ try formatEntry(bool, "a", false, &buf.writer);
+ try testing.expectEqualStrings("a = false\n", buf.written());
}
}
@@ -254,10 +247,10 @@ test "formatEntry int" {
const testing = std.testing;
{
- var buf = std.ArrayList(u8).init(testing.allocator);
+ var buf: std.Io.Writer.Allocating = .init(testing.allocator);
defer buf.deinit();
- try formatEntry(u8, "a", 123, buf.writer());
- try testing.expectEqualStrings("a = 123\n", buf.items);
+ try formatEntry(u8, "a", 123, &buf.writer);
+ try testing.expectEqualStrings("a = 123\n", buf.written());
}
}
@@ -265,10 +258,10 @@ test "formatEntry float" {
const testing = std.testing;
{
- var buf = std.ArrayList(u8).init(testing.allocator);
+ var buf: std.Io.Writer.Allocating = .init(testing.allocator);
defer buf.deinit();
- try formatEntry(f64, "a", 0.7, buf.writer());
- try testing.expectEqualStrings("a = 0.7\n", buf.items);
+ try formatEntry(f64, "a", 0.7, &buf.writer);
+ try testing.expectEqualStrings("a = 0.7\n", buf.written());
}
}
@@ -277,10 +270,10 @@ test "formatEntry enum" {
const Enum = enum { one, two, three };
{
- var buf = std.ArrayList(u8).init(testing.allocator);
+ var buf: std.Io.Writer.Allocating = .init(testing.allocator);
defer buf.deinit();
- try formatEntry(Enum, "a", .two, buf.writer());
- try testing.expectEqualStrings("a = two\n", buf.items);
+ try formatEntry(Enum, "a", .two, &buf.writer);
+ try testing.expectEqualStrings("a = two\n", buf.written());
}
}
@@ -288,10 +281,10 @@ test "formatEntry void" {
const testing = std.testing;
{
- var buf = std.ArrayList(u8).init(testing.allocator);
+ var buf: std.Io.Writer.Allocating = .init(testing.allocator);
defer buf.deinit();
- try formatEntry(void, "a", {}, buf.writer());
- try testing.expectEqualStrings("a = \n", buf.items);
+ try formatEntry(void, "a", {}, &buf.writer);
+ try testing.expectEqualStrings("a = \n", buf.written());
}
}
@@ -299,17 +292,17 @@ test "formatEntry optional" {
const testing = std.testing;
{
- var buf = std.ArrayList(u8).init(testing.allocator);
+ var buf: std.Io.Writer.Allocating = .init(testing.allocator);
defer buf.deinit();
- try formatEntry(?bool, "a", null, buf.writer());
- try testing.expectEqualStrings("a = \n", buf.items);
+ try formatEntry(?bool, "a", null, &buf.writer);
+ try testing.expectEqualStrings("a = \n", buf.written());
}
{
- var buf = std.ArrayList(u8).init(testing.allocator);
+ var buf: std.Io.Writer.Allocating = .init(testing.allocator);
defer buf.deinit();
- try formatEntry(?bool, "a", false, buf.writer());
- try testing.expectEqualStrings("a = false\n", buf.items);
+ try formatEntry(?bool, "a", false, &buf.writer);
+ try testing.expectEqualStrings("a = false\n", buf.written());
}
}
@@ -317,10 +310,10 @@ test "formatEntry string" {
const testing = std.testing;
{
- var buf = std.ArrayList(u8).init(testing.allocator);
+ var buf: std.Io.Writer.Allocating = .init(testing.allocator);
defer buf.deinit();
- try formatEntry([]const u8, "a", "hello", buf.writer());
- try testing.expectEqualStrings("a = hello\n", buf.items);
+ try formatEntry([]const u8, "a", "hello", &buf.writer);
+ try testing.expectEqualStrings("a = hello\n", buf.written());
}
}
@@ -332,9 +325,9 @@ test "formatEntry packed struct" {
};
{
- var buf = std.ArrayList(u8).init(testing.allocator);
+ var buf: std.Io.Writer.Allocating = .init(testing.allocator);
defer buf.deinit();
- try formatEntry(Value, "a", .{}, buf.writer());
- try testing.expectEqualStrings("a = one,no-two\n", buf.items);
+ try formatEntry(Value, "a", .{}, &buf.writer);
+ try testing.expectEqualStrings("a = one,no-two\n", buf.written());
}
}
diff --git a/src/config/io.zig b/src/config/io.zig
index 8be4be551..9d9a127e8 100644
--- a/src/config/io.zig
+++ b/src/config/io.zig
@@ -94,10 +94,9 @@ pub const ReadableIO = union(enum) {
};
}
- pub fn formatEntry(self: Self, formatter: anytype) !void {
+ pub fn formatEntry(self: Self, formatter: formatterpkg.EntryFormatter) !void {
var buf: [4096]u8 = undefined;
- var fbs = std.io.fixedBufferStream(&buf);
- const writer = fbs.writer();
+ var writer: std.Io.Writer = .fixed(&buf);
switch (self) {
inline else => |v, tag| {
writer.writeAll(@tagName(tag)) catch return error.OutOfMemory;
@@ -106,10 +105,9 @@ pub const ReadableIO = union(enum) {
},
}
- const written = fbs.getWritten();
try formatter.formatEntry(
[]const u8,
- written,
+ writer.buffered(),
);
}
@@ -144,13 +142,13 @@ pub const ReadableIO = union(enum) {
defer arena.deinit();
const alloc = arena.allocator();
- var buf = std.ArrayList(u8).init(alloc);
+ var buf: std.Io.Writer.Allocating = .init(alloc);
defer buf.deinit();
var v: Self = undefined;
try v.parseCLI(alloc, "raw:foo");
- try v.formatEntry(formatterpkg.entryFormatter("a", buf.writer()));
- try std.testing.expectEqualSlices(u8, "a = raw:foo\n", buf.items);
+ try v.formatEntry(formatterpkg.entryFormatter("a", &buf.writer));
+ try std.testing.expectEqualSlices(u8, "a = raw:foo\n", buf.written());
}
};
@@ -222,7 +220,7 @@ pub const RepeatableReadableIO = struct {
/// Used by Formatter
pub fn formatEntry(
self: Self,
- formatter: anytype,
+ formatter: formatterpkg.EntryFormatter,
) !void {
if (self.list.items.len == 0) {
try formatter.formatEntry(void, {});
diff --git a/src/config/path.zig b/src/config/path.zig
index 651dbdb3a..aeba69b94 100644
--- a/src/config/path.zig
+++ b/src/config/path.zig
@@ -79,7 +79,7 @@ pub const Path = union(enum) {
}
/// Used by formatter.
- pub fn formatEntry(self: *const Path, formatter: anytype) !void {
+ pub fn formatEntry(self: *const Path, formatter: formatterpkg.EntryFormatter) !void {
var buf: [std.fs.max_path_bytes + 1]u8 = undefined;
const value = switch (self.*) {
.optional => |path| std.fmt.bufPrint(
@@ -154,10 +154,11 @@ pub const Path = union(enum) {
&buf,
) catch |err| {
try diags.append(arena_alloc, .{
- .message = try std.fmt.allocPrintZ(
+ .message = try std.fmt.allocPrintSentinel(
arena_alloc,
"error expanding home directory for path {s}: {}",
.{ path, err },
+ 0,
),
});
@@ -194,10 +195,11 @@ pub const Path = union(enum) {
}
try diags.append(arena_alloc, .{
- .message = try std.fmt.allocPrintZ(
+ .message = try std.fmt.allocPrintSentinel(
arena_alloc,
"error resolving file path {s}: {}",
.{ path, err },
+ 0,
),
});
@@ -306,7 +308,7 @@ pub const Path = union(enum) {
test "formatConfig single item" {
const testing = std.testing;
- var buf = std.ArrayList(u8).init(testing.allocator);
+ var buf: std.Io.Writer.Allocating = .init(testing.allocator);
defer buf.deinit();
var arena = ArenaAllocator.init(testing.allocator);
@@ -315,13 +317,13 @@ pub const Path = union(enum) {
var item: Path = undefined;
try item.parseCLI(alloc, "A");
- try item.formatEntry(formatterpkg.entryFormatter("a", buf.writer()));
- try std.testing.expectEqualSlices(u8, "a = A\n", buf.items);
+ try item.formatEntry(formatterpkg.entryFormatter("a", &buf.writer));
+ try std.testing.expectEqualSlices(u8, "a = A\n", buf.written());
}
test "formatConfig multiple items" {
const testing = std.testing;
- var buf = std.ArrayList(u8).init(testing.allocator);
+ var buf: std.Io.Writer.Allocating = .init(testing.allocator);
defer buf.deinit();
var arena = ArenaAllocator.init(testing.allocator);
@@ -331,8 +333,8 @@ pub const Path = union(enum) {
var item: Path = undefined;
try item.parseCLI(alloc, "A");
try item.parseCLI(alloc, "?B");
- try item.formatEntry(formatterpkg.entryFormatter("a", buf.writer()));
- try std.testing.expectEqualSlices(u8, "a = ?B\n", buf.items);
+ try item.formatEntry(formatterpkg.entryFormatter("a", &buf.writer));
+ try std.testing.expectEqualSlices(u8, "a = ?B\n", buf.written());
}
};
@@ -382,7 +384,7 @@ pub const RepeatablePath = struct {
}
/// Used by Formatter
- pub fn formatEntry(self: RepeatablePath, formatter: anytype) !void {
+ pub fn formatEntry(self: RepeatablePath, formatter: formatterpkg.EntryFormatter) !void {
if (self.value.items.len == 0) {
try formatter.formatEntry(void, {});
return;
@@ -453,17 +455,17 @@ pub const RepeatablePath = struct {
test "formatConfig empty" {
const testing = std.testing;
- var buf = std.ArrayList(u8).init(testing.allocator);
+ var buf: std.Io.Writer.Allocating = .init(testing.allocator);
defer buf.deinit();
var list: RepeatablePath = .{};
- try list.formatEntry(formatterpkg.entryFormatter("a", buf.writer()));
- try std.testing.expectEqualSlices(u8, "a = \n", buf.items);
+ try list.formatEntry(formatterpkg.entryFormatter("a", &buf.writer));
+ try std.testing.expectEqualSlices(u8, "a = \n", buf.written());
}
test "formatConfig single item" {
const testing = std.testing;
- var buf = std.ArrayList(u8).init(testing.allocator);
+ var buf: std.Io.Writer.Allocating = .init(testing.allocator);
defer buf.deinit();
var arena = ArenaAllocator.init(testing.allocator);
@@ -472,13 +474,13 @@ pub const RepeatablePath = struct {
var list: RepeatablePath = .{};
try list.parseCLI(alloc, "A");
- try list.formatEntry(formatterpkg.entryFormatter("a", buf.writer()));
- try std.testing.expectEqualSlices(u8, "a = A\n", buf.items);
+ try list.formatEntry(formatterpkg.entryFormatter("a", &buf.writer));
+ try std.testing.expectEqualSlices(u8, "a = A\n", buf.written());
}
test "formatConfig multiple items" {
const testing = std.testing;
- var buf = std.ArrayList(u8).init(testing.allocator);
+ var buf: std.Io.Writer.Allocating = .init(testing.allocator);
defer buf.deinit();
var arena = ArenaAllocator.init(testing.allocator);
@@ -488,7 +490,7 @@ pub const RepeatablePath = struct {
var list: RepeatablePath = .{};
try list.parseCLI(alloc, "A");
try list.parseCLI(alloc, "?B");
- try list.formatEntry(formatterpkg.entryFormatter("a", buf.writer()));
- try std.testing.expectEqualSlices(u8, "a = A\na = ?B\n", buf.items);
+ try list.formatEntry(formatterpkg.entryFormatter("a", &buf.writer));
+ try std.testing.expectEqualSlices(u8, "a = A\na = ?B\n", buf.written());
}
};
diff --git a/src/config/theme.zig b/src/config/theme.zig
index 8fa7c93dc..b1188a5c4 100644
--- a/src/config/theme.zig
+++ b/src/config/theme.zig
@@ -125,10 +125,11 @@ pub fn open(
) orelse return null;
const stat = file.stat() catch |err| {
try diags.append(arena_alloc, .{
- .message = try std.fmt.allocPrintZ(
+ .message = try std.fmt.allocPrintSentinel(
arena_alloc,
"not reading theme from \"{s}\": {}",
.{ theme, err },
+ 0,
),
});
return null;
@@ -137,10 +138,11 @@ pub fn open(
.file => {},
else => {
try diags.append(arena_alloc, .{
- .message = try std.fmt.allocPrintZ(
+ .message = try std.fmt.allocPrintSentinel(
arena_alloc,
"not reading theme from \"{s}\": it is a {s}",
.{ theme, @tagName(stat.kind) },
+ 0,
),
});
return null;
@@ -152,10 +154,11 @@ pub fn open(
const basename = std.fs.path.basename(theme);
if (!std.mem.eql(u8, theme, basename)) {
try diags.append(arena_alloc, .{
- .message = try std.fmt.allocPrintZ(
+ .message = try std.fmt.allocPrintSentinel(
arena_alloc,
"theme \"{s}\" cannot include path separators unless it is an absolute path",
.{theme},
+ 0,
),
});
return null;
@@ -170,10 +173,11 @@ pub fn open(
if (cwd.openFile(path, .{})) |file| {
const stat = file.stat() catch |err| {
try diags.append(arena_alloc, .{
- .message = try std.fmt.allocPrintZ(
+ .message = try std.fmt.allocPrintSentinel(
arena_alloc,
"not reading theme from \"{s}\": {}",
.{ theme, err },
+ 0,
),
});
return null;
@@ -182,10 +186,11 @@ pub fn open(
.file => {},
else => {
try diags.append(arena_alloc, .{
- .message = try std.fmt.allocPrintZ(
+ .message = try std.fmt.allocPrintSentinel(
arena_alloc,
"not reading theme from \"{s}\": it is a {s}",
.{ theme, @tagName(stat.kind) },
+ 0,
),
});
return null;
@@ -202,10 +207,11 @@ pub fn open(
// Anything else is an error we log and give up on.
else => {
try diags.append(arena_alloc, .{
- .message = try std.fmt.allocPrintZ(
+ .message = try std.fmt.allocPrintSentinel(
arena_alloc,
"failed to load theme \"{s}\" from the file \"{s}\": {}",
.{ theme, path, err },
+ 0,
),
});
@@ -222,10 +228,11 @@ pub fn open(
while (try it.next()) |loc| {
const path = try std.fs.path.join(arena_alloc, &.{ loc.dir, theme });
try diags.append(arena_alloc, .{
- .message = try std.fmt.allocPrintZ(
+ .message = try std.fmt.allocPrintSentinel(
arena_alloc,
"theme \"{s}\" not found, tried path \"{s}\"",
.{ theme, path },
+ 0,
),
});
}
@@ -249,17 +256,19 @@ pub fn openAbsolute(
return std.fs.openFileAbsolute(theme, .{}) catch |err| {
switch (err) {
error.FileNotFound => try diags.append(arena_alloc, .{
- .message = try std.fmt.allocPrintZ(
+ .message = try std.fmt.allocPrintSentinel(
arena_alloc,
"failed to load theme from the path \"{s}\"",
.{theme},
+ 0,
),
}),
else => try diags.append(arena_alloc, .{
- .message = try std.fmt.allocPrintZ(
+ .message = try std.fmt.allocPrintSentinel(
arena_alloc,
"failed to load theme from the path \"{s}\": {}",
.{ theme, err },
+ 0,
),
}),
}
diff --git a/src/crash/sentry.zig b/src/crash/sentry.zig
index 820c3e9a1..555b70fe9 100644
--- a/src/crash/sentry.zig
+++ b/src/crash/sentry.zig
@@ -265,8 +265,8 @@ pub const Transport = struct {
const json = envelope.serialize();
defer sentry.free(@ptrCast(json.ptr));
var parsed: crash.Envelope = parsed: {
- var fbs = std.io.fixedBufferStream(json);
- break :parsed try crash.Envelope.parse(alloc, fbs.reader());
+ var reader: std.Io.Reader = .fixed(json);
+ break :parsed try crash.Envelope.parse(alloc, &reader);
};
defer parsed.deinit();
@@ -298,7 +298,10 @@ pub const Transport = struct {
});
const file = try std.fs.cwd().createFile(path, .{});
defer file.close();
- try file.writer().writeAll(json);
+ var buf: [4096]u8 = undefined;
+ var file_writer = file.writer(&buf);
+ try file_writer.interface.writeAll(json);
+ try file_writer.end();
log.warn("crash report written to disk path={s}", .{path});
}
diff --git a/src/crash/sentry_envelope.zig b/src/crash/sentry_envelope.zig
index 6b675554c..08573b739 100644
--- a/src/crash/sentry_envelope.zig
+++ b/src/crash/sentry_envelope.zig
@@ -26,7 +26,7 @@ pub const Envelope = struct {
headers: std.json.ObjectMap,
/// The items in the envelope in the order they're encoded.
- items: std.ArrayListUnmanaged(Item),
+ items: std.ArrayList(Item),
/// Parse an envelope from a reader.
///
@@ -37,7 +37,7 @@ pub const Envelope = struct {
/// parsing in our use case is not a hot path.
pub fn parse(
alloc_gpa: Allocator,
- reader: anytype,
+ reader: *std.Io.Reader,
) !Envelope {
// We use an arena allocator to read from reader. We pair this
// with `alloc_if_needed` when parsing json to allow the json
@@ -62,23 +62,24 @@ pub const Envelope = struct {
fn parseHeader(
alloc: Allocator,
- reader: anytype,
+ reader: *std.Io.Reader,
) !std.json.ObjectMap {
- var buf: std.ArrayListUnmanaged(u8) = .{};
- reader.streamUntilDelimiter(
- buf.writer(alloc),
+ var buf: std.Io.Writer.Allocating = .init(alloc);
+ _ = try reader.streamDelimiterLimit(
+ &buf.writer,
'\n',
- 1024 * 1024, // 1MB, arbitrary choice
- ) catch |err| switch (err) {
- // Envelope can be header-only.
+ .limited(1024 * 1024), // 1MB, arbitrary choice
+ );
+ _ = reader.discardDelimiterInclusive('\n') catch |err| switch (err) {
+ // It's okay if there isn't a trailing newline
error.EndOfStream => {},
- else => |v| return v,
+ else => return err,
};
const value = try std.json.parseFromSliceLeaky(
std.json.Value,
alloc,
- buf.items,
+ buf.written(),
.{ .allocate = .alloc_if_needed },
);
@@ -90,9 +91,9 @@ pub const Envelope = struct {
fn parseItems(
alloc: Allocator,
- reader: anytype,
- ) !std.ArrayListUnmanaged(Item) {
- var items: std.ArrayListUnmanaged(Item) = .{};
+ reader: *std.Io.Reader,
+ ) !std.ArrayList(Item) {
+ var items: std.ArrayList(Item) = .{};
errdefer items.deinit(alloc);
while (try parseOneItem(alloc, reader)) |item| {
try items.append(alloc, item);
@@ -103,22 +104,27 @@ pub const Envelope = struct {
fn parseOneItem(
alloc: Allocator,
- reader: anytype,
+ reader: *std.Io.Reader,
) !?Item {
// Get the next item which must start with a header.
- var buf: std.ArrayListUnmanaged(u8) = .{};
- reader.streamUntilDelimiter(
- buf.writer(alloc),
+ var buf: std.Io.Writer.Allocating = .init(alloc);
+ _ = reader.streamDelimiterLimit(
+ &buf.writer,
'\n',
- 1024 * 1024, // 1MB, arbitrary choice
+ .limited(1024 * 1024), // 1MB, arbitrary choice
) catch |err| switch (err) {
- error.EndOfStream => return null,
- else => |v| return v,
+ error.StreamTooLong => return null,
+ else => return err,
+ };
+ _ = reader.discardDelimiterInclusive('\n') catch |err| switch (err) {
+ // It's okay if there isn't a trailing newline
+ error.EndOfStream => {},
+ else => return err,
};
// Parse the header JSON
const headers: std.json.ObjectMap = headers: {
- const line = std.mem.trim(u8, buf.items, " \t");
+ const line = std.mem.trim(u8, buf.written(), " \t");
if (line.len == 0) return null;
const value = try std.json.parseFromSliceLeaky(
@@ -156,18 +162,16 @@ pub const Envelope = struct {
// Get the payload
const payload: []const u8 = if (len_) |len| payload: {
// The payload length is specified so read the exact length.
- var payload = std.ArrayList(u8).init(alloc);
+ var payload: std.Io.Writer.Allocating = .init(alloc);
defer payload.deinit();
- for (0..len) |_| {
- const byte = reader.readByte() catch |err| switch (err) {
- error.EndOfStream => return error.EnvelopeItemPayloadTooShort,
- else => return err,
- };
- try payload.append(byte);
- }
+
+ reader.streamExact(&payload.writer, len) catch |err| switch (err) {
+ error.EndOfStream => return error.EnvelopeItemPayloadTooShort,
+ else => return err,
+ };
// The next byte must be a newline.
- if (reader.readByte()) |byte| {
+ if (reader.takeByte()) |byte| {
if (byte != '\n') return error.EnvelopeItemPayloadNoNewline;
} else |err| switch (err) {
error.EndOfStream => {},
@@ -177,16 +181,20 @@ pub const Envelope = struct {
break :payload try payload.toOwnedSlice();
} else payload: {
// The payload is the next line ending in `\n`. It is required.
- var payload = std.ArrayList(u8).init(alloc);
- defer payload.deinit();
- reader.streamUntilDelimiter(
- payload.writer(),
+ var payload: std.Io.Writer.Allocating = .init(alloc);
+ _ = reader.streamDelimiterLimit(
+ &payload.writer,
'\n',
- 1024 * 1024 * 50, // 50MB, arbitrary choice
+ .limited(1024 * 1024), // 50MB, arbitrary choice
) catch |err| switch (err) {
- error.EndOfStream => return error.EnvelopeItemPayloadTooShort,
+ error.StreamTooLong => return error.EnvelopeItemPayloadTooShort,
else => |v| return v,
};
+ _ = reader.discardDelimiterInclusive('\n') catch |err| switch (err) {
+ // It's okay if there isn't a trailing newline
+ error.EndOfStream => {},
+ else => return err,
+ };
break :payload try payload.toOwnedSlice();
};
@@ -212,15 +220,13 @@ pub const Envelope = struct {
/// therefore may allocate.
pub fn serialize(
self: *Envelope,
- writer: anytype,
+ writer: *std.Io.Writer,
) !void {
// Header line first
- try std.json.stringify(
+ try writer.print("{f}\n", .{std.json.fmt(
std.json.Value{ .object = self.headers },
json_opts,
- writer,
- );
- try writer.writeByte('\n');
+ )});
// Write each item
const alloc = self.allocator();
@@ -230,13 +236,13 @@ pub const Envelope = struct {
const encoded = try item.encode(alloc);
assert(item.* == .encoded);
- try std.json.stringify(
- std.json.Value{ .object = encoded.headers },
- json_opts,
- writer,
- );
- try writer.writeByte('\n');
- try writer.writeAll(encoded.payload);
+ try writer.print("{f}\n{s}", .{
+ std.json.fmt(
+ std.json.Value{ .object = encoded.headers },
+ json_opts,
+ ),
+ encoded.payload,
+ });
}
}
};
@@ -425,7 +431,7 @@ pub const Attachment = struct {
pub const ObjectMapUnmanaged = std.StringArrayHashMapUnmanaged(std.json.Value);
/// The options we must use for serialization.
-const json_opts: std.json.StringifyOptions = .{
+const json_opts: std.json.Stringify.Options = .{
// This is the default but I want to be explicit because its
// VERY important for the correctness of the envelope. This is
// the only whitespace type in std.json that doesn't emit newlines.
@@ -437,10 +443,10 @@ test "Envelope parse" {
const testing = std.testing;
const alloc = testing.allocator;
- var fbs = std.io.fixedBufferStream(
+ var reader: std.Io.Reader = .fixed(
\\{}
);
- var v = try Envelope.parse(alloc, fbs.reader());
+ var v = try Envelope.parse(alloc, &reader);
defer v.deinit();
}
@@ -448,12 +454,12 @@ test "Envelope parse session" {
const testing = std.testing;
const alloc = testing.allocator;
- var fbs = std.io.fixedBufferStream(
+ var reader: std.Io.Reader = .fixed(
\\{}
\\{"type":"session","length":218}
\\{"init":true,"sid":"c148cc2f-5f9f-4231-575c-2e85504d6434","status":"abnormal","errors":0,"started":"2024-08-29T02:38:57.607016Z","duration":0.000343,"attrs":{"release":"0.1.0-HEAD+d37b7d09","environment":"production"}}
);
- var v = try Envelope.parse(alloc, fbs.reader());
+ var v = try Envelope.parse(alloc, &reader);
defer v.deinit();
try testing.expectEqual(@as(usize, 1), v.items.items.len);
@@ -464,14 +470,14 @@ test "Envelope parse multiple" {
const testing = std.testing;
const alloc = testing.allocator;
- var fbs = std.io.fixedBufferStream(
+ var reader: std.Io.Reader = .fixed(
\\{}
\\{"type":"session","length":218}
\\{"init":true,"sid":"c148cc2f-5f9f-4231-575c-2e85504d6434","status":"abnormal","errors":0,"started":"2024-08-29T02:38:57.607016Z","duration":0.000343,"attrs":{"release":"0.1.0-HEAD+d37b7d09","environment":"production"}}
\\{"type":"attachment","length":4,"filename":"test.txt"}
\\ABCD
);
- var v = try Envelope.parse(alloc, fbs.reader());
+ var v = try Envelope.parse(alloc, &reader);
defer v.deinit();
try testing.expectEqual(@as(usize, 2), v.items.items.len);
@@ -483,14 +489,14 @@ test "Envelope parse multiple no length" {
const testing = std.testing;
const alloc = testing.allocator;
- var fbs = std.io.fixedBufferStream(
+ var reader: std.Io.Reader = .fixed(
\\{}
\\{"type":"session"}
\\{}
\\{"type":"attachment","length":4,"filename":"test.txt"}
\\ABCD
);
- var v = try Envelope.parse(alloc, fbs.reader());
+ var v = try Envelope.parse(alloc, &reader);
defer v.deinit();
try testing.expectEqual(@as(usize, 2), v.items.items.len);
@@ -502,13 +508,13 @@ test "Envelope parse end in new line" {
const testing = std.testing;
const alloc = testing.allocator;
- var fbs = std.io.fixedBufferStream(
+ var reader: std.Io.Reader = .fixed(
\\{}
\\{"type":"session","length":218}
\\{"init":true,"sid":"c148cc2f-5f9f-4231-575c-2e85504d6434","status":"abnormal","errors":0,"started":"2024-08-29T02:38:57.607016Z","duration":0.000343,"attrs":{"release":"0.1.0-HEAD+d37b7d09","environment":"production"}}
\\
);
- var v = try Envelope.parse(alloc, fbs.reader());
+ var v = try Envelope.parse(alloc, &reader);
defer v.deinit();
try testing.expectEqual(@as(usize, 1), v.items.items.len);
@@ -519,12 +525,12 @@ test "Envelope parse attachment" {
const testing = std.testing;
const alloc = testing.allocator;
- var fbs = std.io.fixedBufferStream(
+ var reader: std.Io.Reader = .fixed(
\\{}
\\{"type":"attachment","length":4,"filename":"test.txt"}
\\ABCD
);
- var v = try Envelope.parse(alloc, fbs.reader());
+ var v = try Envelope.parse(alloc, &reader);
defer v.deinit();
try testing.expectEqual(@as(usize, 1), v.items.items.len);
@@ -537,14 +543,14 @@ test "Envelope parse attachment" {
// Serialization test
{
- var output = std.ArrayList(u8).init(alloc);
+ var output: std.Io.Writer.Allocating = .init(alloc);
defer output.deinit();
- try v.serialize(output.writer());
+ try v.serialize(&output.writer);
try testing.expectEqualStrings(
\\{}
\\{"type":"attachment","length":4,"filename":"test.txt"}
\\ABCD
- , std.mem.trim(u8, output.items, "\n"));
+ , std.mem.trim(u8, output.written(), "\n"));
}
}
@@ -552,76 +558,40 @@ test "Envelope serialize empty" {
const testing = std.testing;
const alloc = testing.allocator;
- var fbs = std.io.fixedBufferStream(
+ var reader: std.Io.Reader = .fixed(
\\{}
);
- var v = try Envelope.parse(alloc, fbs.reader());
+ var v = try Envelope.parse(alloc, &reader);
defer v.deinit();
- var output = std.ArrayList(u8).init(alloc);
+ var output: std.Io.Writer.Allocating = .init(alloc);
defer output.deinit();
- try v.serialize(output.writer());
+ try v.serialize(&output.writer);
try testing.expectEqualStrings(
\\{}
- , std.mem.trim(u8, output.items, "\n"));
+ , std.mem.trim(u8, output.written(), "\n"));
}
test "Envelope serialize session" {
const testing = std.testing;
const alloc = testing.allocator;
- var fbs = std.io.fixedBufferStream(
+ var reader: std.Io.Reader = .fixed(
\\{}
\\{"type":"session","length":218}
\\{"init":true,"sid":"c148cc2f-5f9f-4231-575c-2e85504d6434","status":"abnormal","errors":0,"started":"2024-08-29T02:38:57.607016Z","duration":0.000343,"attrs":{"release":"0.1.0-HEAD+d37b7d09","environment":"production"}}
);
- var v = try Envelope.parse(alloc, fbs.reader());
+ var v = try Envelope.parse(alloc, &reader);
defer v.deinit();
- var output = std.ArrayList(u8).init(alloc);
+ var output: std.Io.Writer.Allocating = .init(alloc);
defer output.deinit();
- try v.serialize(output.writer());
+ try v.serialize(&output.writer);
try testing.expectEqualStrings(
\\{}
\\{"type":"session","length":218}
\\{"init":true,"sid":"c148cc2f-5f9f-4231-575c-2e85504d6434","status":"abnormal","errors":0,"started":"2024-08-29T02:38:57.607016Z","duration":0.000343,"attrs":{"release":"0.1.0-HEAD+d37b7d09","environment":"production"}}
- , std.mem.trim(u8, output.items, "\n"));
+ , std.mem.trim(u8, output.written(), "\n"));
}
-
-// // Uncomment this test if you want to extract a minidump file from an
-// // existing envelope. This is useful for getting new test contents.
-// test "Envelope extract mdmp" {
-// const testing = std.testing;
-// const alloc = testing.allocator;
-//
-// var fbs = std.io.fixedBufferStream(@embedFile("in.crash"));
-// var v = try Envelope.parse(alloc, fbs.reader());
-// defer v.deinit();
-//
-// try testing.expect(v.items.items.len > 0);
-// for (v.items.items, 0..) |*item, i| {
-// if (item.encoded.type != .attachment) {
-// log.warn("ignoring item type={} i={}", .{ item.encoded.type, i });
-// continue;
-// }
-//
-// try item.decode(v.allocator());
-// const attach = item.attachment;
-// const attach_type = attach.type orelse {
-// log.warn("attachment missing type i={}", .{i});
-// continue;
-// };
-// if (!std.mem.eql(u8, attach_type, "event.minidump")) {
-// log.warn("ignoring attachment type={s} i={}", .{ attach_type, i });
-// continue;
-// }
-//
-// log.warn("found minidump i={}", .{i});
-// var f = try std.fs.cwd().createFile("out.mdmp", .{});
-// defer f.close();
-// try f.writer().writeAll(attach.payload);
-// return;
-// }
-// }
diff --git a/src/datastruct/lru.zig b/src/datastruct/lru.zig
index 7bf42e82d..1c6df69ce 100644
--- a/src/datastruct/lru.zig
+++ b/src/datastruct/lru.zig
@@ -33,8 +33,13 @@ pub fn HashMap(
) type {
return struct {
const Self = @This();
- const Map = std.HashMapUnmanaged(K, *Queue.Node, Context, max_load_percentage);
- const Queue = std.DoublyLinkedList(KV);
+ const Queue = std.DoublyLinkedList;
+ const Map = std.HashMapUnmanaged(
+ K,
+ *Entry,
+ Context,
+ max_load_percentage,
+ );
/// Map to maintain our entries.
map: Map,
@@ -46,6 +51,15 @@ pub fn HashMap(
/// misses will begin evicting entries.
capacity: Map.Size,
+ const Entry = struct {
+ data: KV,
+ node: Queue.Node,
+
+ fn fromNode(node: *Queue.Node) *Entry {
+ return @fieldParentPtr("node", node);
+ }
+ };
+
pub const KV = struct {
key: K,
value: V,
@@ -82,7 +96,7 @@ pub fn HashMap(
var it = self.queue.first;
while (it) |node| {
it = node.next;
- alloc.destroy(node);
+ alloc.destroy(Entry.fromNode(node));
}
self.map.deinit(alloc);
@@ -108,8 +122,8 @@ pub fn HashMap(
const map_gop = try self.map.getOrPutContext(alloc, key, ctx);
if (map_gop.found_existing) {
// Move to end to mark as most recently used
- self.queue.remove(map_gop.value_ptr.*);
- self.queue.append(map_gop.value_ptr.*);
+ self.queue.remove(&map_gop.value_ptr.*.node);
+ self.queue.append(&map_gop.value_ptr.*.node);
return GetOrPutResult{
.found_existing = true,
@@ -122,37 +136,34 @@ pub fn HashMap(
// We're evicting if our map insertion increased our capacity.
const evict = self.map.count() > self.capacity;
- // Get our node. If we're not evicting then we allocate a new
- // node. If we are evicting then we avoid allocation by just
- // reusing the node we would've evicted.
- var node = if (!evict) try alloc.create(Queue.Node) else node: {
+ // Get our entry. If we're not evicting then we allocate a new
+ // entry. If we are evicting then we avoid allocation by just
+ // reusing the entry we would've evicted.
+ const entry: *Entry = if (!evict) try alloc.create(Entry) else entry: {
// Our first node is the least recently used.
- const least_used = self.queue.first.?;
-
- // Move our least recently used to the end to make
- // it the most recently used.
- self.queue.remove(least_used);
+ const least_used_node = self.queue.popFirst().?;
+ const least_used_entry: *Entry = .fromNode(least_used_node);
// Remove the least used from the map
- _ = self.map.remove(least_used.data.key);
+ _ = self.map.remove(least_used_entry.data.key);
- break :node least_used;
+ break :entry least_used_entry;
};
- errdefer if (!evict) alloc.destroy(node);
+ errdefer if (!evict) alloc.destroy(entry);
- // Store our node in the map.
- map_gop.value_ptr.* = node;
+ // Store our entry in the map.
+ map_gop.value_ptr.* = entry;
- // Mark the node as most recently used
- self.queue.append(node);
+ // Mark the entry as most recently used
+ self.queue.append(&entry.node);
// Set our key
- node.data.key = key;
+ entry.data.key = key;
- return GetOrPutResult{
+ return .{
.found_existing = map_gop.found_existing,
- .value_ptr = &node.data.value,
- .evicted = if (!evict) null else node.data,
+ .value_ptr = &entry.data.value,
+ .evicted = if (!evict) null else entry.data,
};
}
@@ -193,11 +204,12 @@ pub fn HashMap(
var i: Map.Size = 0;
while (i < delta) : (i += 1) {
- const node = self.queue.first.?;
- evicted[i] = node.data.value;
+ const node = self.queue.popFirst().?;
+ const entry: *Entry = .fromNode(node);
+ evicted[i] = entry.data.value;
self.queue.remove(node);
- _ = self.map.remove(node.data.key);
- alloc.destroy(node);
+ _ = self.map.remove(entry.data.key);
+ alloc.destroy(entry);
}
self.capacity = capacity;
diff --git a/src/datastruct/split_tree.zig b/src/datastruct/split_tree.zig
index 28b45ceed..eb371187c 100644
--- a/src/datastruct/split_tree.zig
+++ b/src/datastruct/split_tree.zig
@@ -1023,45 +1023,33 @@ pub fn SplitTree(comptime V: type) type {
}
/// Format the tree in a human-readable format. By default this will
- /// output a diagram followed by a textual representation. This can
- /// be controlled via the formatting string:
- ///
- /// - `diagram` - Output a diagram of the split tree only.
- /// - `text` - Output a textual representation of the split tree only.
- /// - Empty - Output both a diagram and a textual representation.
- ///
+ /// output a diagram followed by a textual representation.
pub fn format(
self: *const Self,
- comptime fmt: []const u8,
- options: std.fmt.FormatOptions,
- writer: anytype,
+ writer: *std.Io.Writer,
) !void {
- _ = options;
-
if (self.nodes.len == 0) {
try writer.writeAll("empty");
return;
}
-
- if (std.mem.eql(u8, fmt, "diagram")) {
- self.formatDiagram(writer) catch
- try writer.writeAll("failed to draw split tree diagram");
- } else if (std.mem.eql(u8, fmt, "text")) {
- try self.formatText(writer, .root, 0);
- } else if (fmt.len == 0) {
- self.formatDiagram(writer) catch {};
- try self.formatText(writer, .root, 0);
- } else {
- return error.InvalidFormat;
- }
+ self.formatDiagram(writer) catch {};
+ try self.formatText(writer);
}
- fn formatText(
- self: *const Self,
- writer: anytype,
+ pub fn formatText(self: Self, writer: *std.Io.Writer) std.Io.Writer.Error!void {
+ if (self.nodes.len == 0) {
+ try writer.writeAll("empty");
+ return;
+ }
+ try self.formatTextInner(writer, .root, 0);
+ }
+
+ fn formatTextInner(
+ self: Self,
+ writer: *std.Io.Writer,
current: Node.Handle,
depth: usize,
- ) !void {
+ ) std.Io.Writer.Error!void {
for (0..depth) |_| try writer.writeAll(" ");
if (self.zoomed) |zoomed| if (zoomed == current) {
@@ -1075,20 +1063,25 @@ pub fn SplitTree(comptime V: type) type {
try writer.print("leaf: {d}\n", .{current}),
.split => |s| {
- try writer.print("split (layout: {s}, ratio: {d:.2})\n", .{
- @tagName(s.layout),
+ try writer.print("split (layout: {t}, ratio: {d:.2})\n", .{
+ s.layout,
s.ratio,
});
- try self.formatText(writer, s.left, depth + 1);
- try self.formatText(writer, s.right, depth + 1);
+ try self.formatTextInner(writer, s.left, depth + 1);
+ try self.formatTextInner(writer, s.right, depth + 1);
},
}
}
- fn formatDiagram(
- self: *const Self,
- writer: anytype,
- ) !void {
+ pub fn formatDiagram(
+ self: Self,
+ writer: *std.Io.Writer,
+ ) std.Io.Writer.Error!void {
+ if (self.nodes.len == 0) {
+ try writer.writeAll("empty");
+ return;
+ }
+
// Use our arena's GPA to allocate some intermediate memory.
// Requiring allocation for formatting is nasty but this is really
// only used for debugging and testing and shouldn't hit OOM
@@ -1099,7 +1092,7 @@ pub fn SplitTree(comptime V: type) type {
// Get our spatial representation.
const sp = spatial: {
- const sp = try self.spatial(alloc);
+ const sp = self.spatial(alloc) catch return error.WriteFailed;
// Scale our spatial representation to have minimum width/height 1.
var min_w: f16 = 1;
@@ -1111,7 +1104,7 @@ pub fn SplitTree(comptime V: type) type {
const ratio_w: f16 = 1 / min_w;
const ratio_h: f16 = 1 / min_h;
- const slots = try alloc.dupe(Spatial.Slot, sp.slots);
+ const slots = alloc.dupe(Spatial.Slot, sp.slots) catch return error.WriteFailed;
for (slots) |*slot| {
slot.x *= ratio_w;
slot.y *= ratio_h;
@@ -1168,9 +1161,9 @@ pub fn SplitTree(comptime V: type) type {
width *= cell_width;
height *= cell_height;
- const rows = try alloc.alloc([]u8, height);
+ const rows = alloc.alloc([]u8, height) catch return error.WriteFailed;
for (0..rows.len) |y| {
- rows[y] = try alloc.alloc(u8, width + 1);
+ rows[y] = alloc.alloc(u8, width + 1) catch return error.WriteFailed;
@memset(rows[y], ' ');
rows[y][width] = '\n';
}
@@ -1223,7 +1216,7 @@ pub fn SplitTree(comptime V: type) type {
const label: []const u8 = if (@hasDecl(View, "splitTreeLabel"))
node.leaf.splitTreeLabel()
else
- try std.fmt.bufPrint(&buf, "{d}", .{handle});
+ std.fmt.bufPrint(&buf, "{d}", .{handle}) catch return error.WriteFailed;
// Draw the handle in the center
const x_mid = width / 2 + x;
@@ -1231,7 +1224,7 @@ pub fn SplitTree(comptime V: type) type {
const label_width = label.len;
const label_start = x_mid - label_width / 2;
const row = grid[y_mid][label_start..];
- _ = try std.fmt.bufPrint(row, "{s}", .{label});
+ _ = std.fmt.bufPrint(row, "{s}", .{label}) catch return error.WriteFailed;
}
// Output every row
@@ -1339,7 +1332,7 @@ test "SplitTree: empty tree" {
var t: TestTree = .empty;
defer t.deinit();
- const str = try std.fmt.allocPrint(alloc, "{}", .{t});
+ const str = try std.fmt.allocPrint(alloc, "{f}", .{t});
defer alloc.free(str);
try testing.expectEqualStrings(str,
\\empty
@@ -1353,7 +1346,7 @@ test "SplitTree: single node" {
var t: TestTree = try .init(alloc, &v);
defer t.deinit();
- const str = try std.fmt.allocPrint(alloc, "{diagram}", .{t});
+ const str = try std.fmt.allocPrint(alloc, "{f}", .{std.fmt.alt(t, .formatDiagram)});
defer alloc.free(str);
try testing.expectEqualStrings(str,
\\+---+
@@ -1383,7 +1376,7 @@ test "SplitTree: split horizontal" {
defer t3.deinit();
{
- const str = try std.fmt.allocPrint(alloc, "{}", .{t3});
+ const str = try std.fmt.allocPrint(alloc, "{f}", .{t3});
defer alloc.free(str);
try testing.expectEqualStrings(str,
\\+---++---+
@@ -1415,7 +1408,7 @@ test "SplitTree: split horizontal" {
defer t4.deinit();
{
- const str = try std.fmt.allocPrint(alloc, "{}", .{t4});
+ const str = try std.fmt.allocPrint(alloc, "{f}", .{t4});
defer alloc.free(str);
try testing.expectEqualStrings(str,
\\+--------++---++---+
@@ -1449,7 +1442,7 @@ test "SplitTree: split horizontal" {
defer t5.deinit();
{
- const str = try std.fmt.allocPrint(alloc, "{}", .{t5});
+ const str = try std.fmt.allocPrint(alloc, "{f}", .{t5});
defer alloc.free(str);
try testing.expectEqualStrings(
\\+------------------++--------++---++---+
@@ -1547,7 +1540,7 @@ test "SplitTree: split vertical" {
);
defer t3.deinit();
- const str = try std.fmt.allocPrint(alloc, "{diagram}", .{t3});
+ const str = try std.fmt.allocPrint(alloc, "{f}", .{std.fmt.alt(t3, .formatDiagram)});
defer alloc.free(str);
try testing.expectEqualStrings(str,
\\+---+
@@ -1583,7 +1576,7 @@ test "SplitTree: split horizontal with zero ratio" {
const split = splitAB;
{
- const str = try std.fmt.allocPrint(alloc, "{diagram}", .{split});
+ const str = try std.fmt.allocPrint(alloc, "{f}", .{std.fmt.alt(split, .formatDiagram)});
defer alloc.free(str);
try testing.expectEqualStrings(str,
\\+---+
@@ -1617,7 +1610,7 @@ test "SplitTree: split vertical with zero ratio" {
const split = splitAB;
{
- const str = try std.fmt.allocPrint(alloc, "{diagram}", .{split});
+ const str = try std.fmt.allocPrint(alloc, "{f}", .{std.fmt.alt(split, .formatDiagram)});
defer alloc.free(str);
try testing.expectEqualStrings(str,
\\+---+
@@ -1651,7 +1644,7 @@ test "SplitTree: split horizontal with full width" {
const split = splitAB;
{
- const str = try std.fmt.allocPrint(alloc, "{diagram}", .{split});
+ const str = try std.fmt.allocPrint(alloc, "{f}", .{std.fmt.alt(split, .formatDiagram)});
defer alloc.free(str);
try testing.expectEqualStrings(str,
\\+---+
@@ -1685,7 +1678,7 @@ test "SplitTree: split vertical with full width" {
const split = splitAB;
{
- const str = try std.fmt.allocPrint(alloc, "{diagram}", .{split});
+ const str = try std.fmt.allocPrint(alloc, "{f}", .{std.fmt.alt(split, .formatDiagram)});
defer alloc.free(str);
try testing.expectEqualStrings(str,
\\+---+
@@ -1727,7 +1720,7 @@ test "SplitTree: remove leaf" {
);
defer t4.deinit();
- const str = try std.fmt.allocPrint(alloc, "{diagram}", .{t4});
+ const str = try std.fmt.allocPrint(alloc, "{f}", .{std.fmt.alt(t4, .formatDiagram)});
defer alloc.free(str);
try testing.expectEqualStrings(str,
\\+---+
@@ -1772,7 +1765,7 @@ test "SplitTree: split twice, remove intermediary" {
defer split2.deinit();
{
- const str = try std.fmt.allocPrint(alloc, "{diagram}", .{split2});
+ const str = try std.fmt.allocPrint(alloc, "{f}", .{std.fmt.alt(split2, .formatDiagram)});
defer alloc.free(str);
try testing.expectEqualStrings(str,
\\+---++---+
@@ -1798,7 +1791,7 @@ test "SplitTree: split twice, remove intermediary" {
defer split3.deinit();
{
- const str = try std.fmt.allocPrint(alloc, "{diagram}", .{split3});
+ const str = try std.fmt.allocPrint(alloc, "{f}", .{std.fmt.alt(split3, .formatDiagram)});
defer alloc.free(str);
try testing.expectEqualStrings(str,
\\+---+
@@ -1883,7 +1876,7 @@ test "SplitTree: spatial goto" {
const split = splitBD;
{
- const str = try std.fmt.allocPrint(alloc, "{diagram}", .{split});
+ const str = try std.fmt.allocPrint(alloc, "{f}", .{std.fmt.alt(split, .formatDiagram)});
defer alloc.free(str);
try testing.expectEqualStrings(str,
\\+---++---+
@@ -1943,7 +1936,7 @@ test "SplitTree: spatial goto" {
defer equal.deinit();
{
- const str = try std.fmt.allocPrint(alloc, "{diagram}", .{equal});
+ const str = try std.fmt.allocPrint(alloc, "{f}", .{std.fmt.alt(equal, .formatDiagram)});
defer alloc.free(str);
try testing.expectEqualStrings(str,
\\+---++---+
@@ -1979,7 +1972,7 @@ test "SplitTree: resize" {
defer split.deinit();
{
- const str = try std.fmt.allocPrint(alloc, "{diagram}", .{split});
+ const str = try std.fmt.allocPrint(alloc, "{f}", .{std.fmt.alt(split, .formatDiagram)});
defer alloc.free(str);
try testing.expectEqualStrings(str,
\\+---++---+
@@ -2005,7 +1998,7 @@ test "SplitTree: resize" {
0.25,
);
defer resized.deinit();
- const str = try std.fmt.allocPrint(alloc, "{diagram}", .{resized});
+ const str = try std.fmt.allocPrint(alloc, "{f}", .{std.fmt.alt(resized, .formatDiagram)});
defer alloc.free(str);
try testing.expectEqualStrings(str,
\\+-------------++---+
@@ -2026,7 +2019,7 @@ test "SplitTree: clone empty tree" {
defer t2.deinit();
{
- const str = try std.fmt.allocPrint(alloc, "{}", .{t2});
+ const str = try std.fmt.allocPrint(alloc, "{f}", .{t2});
defer alloc.free(str);
try testing.expectEqualStrings(str,
\\empty
@@ -2064,7 +2057,7 @@ test "SplitTree: zoom" {
});
{
- const str = try std.fmt.allocPrint(alloc, "{text}", .{split});
+ const str = try std.fmt.allocPrint(alloc, "{f}", .{std.fmt.alt(split, .formatText)});
defer alloc.free(str);
try testing.expectEqualStrings(str,
\\split (layout: horizontal, ratio: 0.50)
@@ -2079,7 +2072,7 @@ test "SplitTree: zoom" {
defer clone.deinit();
{
- const str = try std.fmt.allocPrint(alloc, "{text}", .{clone});
+ const str = try std.fmt.allocPrint(alloc, "{f}", .{std.fmt.alt(clone, .formatText)});
defer alloc.free(str);
try testing.expectEqualStrings(str,
\\split (layout: horizontal, ratio: 0.50)
@@ -2122,7 +2115,7 @@ test "SplitTree: split resets zoom" {
defer split.deinit();
{
- const str = try std.fmt.allocPrint(alloc, "{text}", .{split});
+ const str = try std.fmt.allocPrint(alloc, "{f}", .{std.fmt.alt(split, .formatText)});
defer alloc.free(str);
try testing.expectEqualStrings(str,
\\split (layout: horizontal, ratio: 0.50)
@@ -2178,7 +2171,7 @@ test "SplitTree: remove and zoom" {
defer removed.deinit();
try testing.expect(removed.zoomed == null);
- const str = try std.fmt.allocPrint(alloc, "{text}", .{removed});
+ const str = try std.fmt.allocPrint(alloc, "{f}", .{std.fmt.alt(removed, .formatText)});
defer alloc.free(str);
try testing.expectEqualStrings(str,
\\leaf: B
@@ -2201,7 +2194,7 @@ test "SplitTree: remove and zoom" {
);
defer removed.deinit();
- const str = try std.fmt.allocPrint(alloc, "{text}", .{removed});
+ const str = try std.fmt.allocPrint(alloc, "{f}", .{std.fmt.alt(removed, .formatText)});
defer alloc.free(str);
try testing.expectEqualStrings(str,
\\(zoomed) leaf: A
diff --git a/src/extra/bash.zig b/src/extra/bash.zig
index 536cadbc4..ee9a7895c 100644
--- a/src/extra/bash.zig
+++ b/src/extra/bash.zig
@@ -19,18 +19,18 @@ pub const completions = comptimeGenerateBashCompletions();
fn comptimeGenerateBashCompletions() []const u8 {
comptime {
@setEvalBranchQuota(50000);
- var counter = std.io.countingWriter(std.io.null_writer);
- try writeBashCompletions(&counter.writer());
+ var counter: std.Io.Writer.Discarding = .init(&.{});
+ try writeBashCompletions(&counter.writer);
- var buf: [counter.bytes_written]u8 = undefined;
- var stream = std.io.fixedBufferStream(&buf);
- try writeBashCompletions(stream.writer());
+ var buf: [counter.count]u8 = undefined;
+ var writer: std.Io.Writer = .fixed(&buf);
+ try writeBashCompletions(&writer);
const final = buf;
- return final[0..stream.getWritten().len];
+ return final[0..writer.end];
}
}
-fn writeBashCompletions(writer: anytype) !void {
+fn writeBashCompletions(writer: *std.Io.Writer) !void {
const pad1 = " ";
const pad2 = pad1 ++ pad1;
const pad3 = pad2 ++ pad1;
diff --git a/src/extra/fish.zig b/src/extra/fish.zig
index 5a4b38e32..7ffc23093 100644
--- a/src/extra/fish.zig
+++ b/src/extra/fish.zig
@@ -11,18 +11,18 @@ pub const completions = comptimeGenerateCompletions();
fn comptimeGenerateCompletions() []const u8 {
comptime {
@setEvalBranchQuota(50000);
- var counter = std.io.countingWriter(std.io.null_writer);
- try writeCompletions(&counter.writer());
+ var counter: std.Io.Writer.Discarding = .init(&.{});
+ try writeCompletions(&counter.writer);
- var buf: [counter.bytes_written]u8 = undefined;
- var stream = std.io.fixedBufferStream(&buf);
- try writeCompletions(stream.writer());
+ var buf: [counter.count]u8 = undefined;
+ var writer: std.Io.Writer = .fixed(&buf);
+ try writeCompletions(&writer);
const final = buf;
- return final[0..stream.getWritten().len];
+ return final[0..writer.end];
}
}
-fn writeCompletions(writer: anytype) !void {
+fn writeCompletions(writer: *std.Io.Writer) !void {
{
try writer.writeAll("set -l commands \"");
var count: usize = 0;
diff --git a/src/extra/vim.zig b/src/extra/vim.zig
index 4443fd168..2c0192d03 100644
--- a/src/extra/vim.zig
+++ b/src/extra/vim.zig
@@ -59,19 +59,20 @@ pub const compiler =
/// Generates the syntax file at comptime.
fn comptimeGenSyntax() []const u8 {
comptime {
- var counting_writer = std.io.countingWriter(std.io.null_writer);
- try writeSyntax(&counting_writer.writer());
+ @setEvalBranchQuota(50000);
+ var counter: std.Io.Writer.Discarding = .init(&.{});
+ try writeSyntax(&counter.writer);
- var buf: [counting_writer.bytes_written]u8 = undefined;
- var stream = std.io.fixedBufferStream(&buf);
- try writeSyntax(stream.writer());
+ var buf: [counter.count]u8 = undefined;
+ var writer: std.Io.Writer = .fixed(&buf);
+ try writeSyntax(&writer);
const final = buf;
- return final[0..stream.getWritten().len];
+ return final[0..writer.end];
}
}
/// Writes the syntax file to the given writer.
-fn writeSyntax(writer: anytype) !void {
+fn writeSyntax(writer: *std.Io.Writer) !void {
try writer.writeAll(
\\" Vim syntax file
\\" Language: Ghostty config file
diff --git a/src/extra/zsh.zig b/src/extra/zsh.zig
index 6bddcd285..2fad4234a 100644
--- a/src/extra/zsh.zig
+++ b/src/extra/zsh.zig
@@ -12,18 +12,18 @@ const equals_required = "=-:::";
fn comptimeGenerateZshCompletions() []const u8 {
comptime {
@setEvalBranchQuota(50000);
- var counter = std.io.countingWriter(std.io.null_writer);
- try writeZshCompletions(&counter.writer());
+ var counter: std.Io.Writer.Discarding = .init(&.{});
+ try writeZshCompletions(&counter.writer);
- var buf: [counter.bytes_written]u8 = undefined;
- var stream = std.io.fixedBufferStream(&buf);
- try writeZshCompletions(stream.writer());
+ var buf: [counter.count]u8 = undefined;
+ var writer: std.Io.Writer = .fixed(&buf);
+ try writeZshCompletions(&writer);
const final = buf;
- return final[0..stream.getWritten().len];
+ return final[0..writer.end];
}
}
-fn writeZshCompletions(writer: anytype) !void {
+fn writeZshCompletions(writer: *std.Io.Writer) !void {
try writer.writeAll(
\\#compdef ghostty
\\
diff --git a/src/font/Atlas.zig b/src/font/Atlas.zig
index 68ccaddcc..e2d9a5de2 100644
--- a/src/font/Atlas.zig
+++ b/src/font/Atlas.zig
@@ -355,7 +355,7 @@ pub fn clear(self: *Atlas) void {
/// swapped because PPM expects RGB. This would be
/// easy enough to fix so next time someone needs
/// to debug a color atlas they should fix it.
-pub fn dump(self: Atlas, writer: anytype) !void {
+pub fn dump(self: Atlas, writer: *std.Io.Writer) !void {
try writer.print(
\\P{c}
\\{d} {d}
diff --git a/src/font/Collection.zig b/src/font/Collection.zig
index e91fe03ae..5ec076608 100644
--- a/src/font/Collection.zig
+++ b/src/font/Collection.zig
@@ -223,12 +223,13 @@ fn getFaceFromEntry(
// Calculate the scale factor for this
// entry now that we have a loaded face.
- entry.scale_factor = .{
- .scale = self.scaleFactor(
+ if (entry.scale_factor == .adjustment) {
+ const factor = self.scaleFactor(
face.getMetrics(),
entry.scale_factor.adjustment,
- ),
- };
+ );
+ entry.scale_factor = .{ .scale = factor };
+ }
// If our scale factor is something other
// than 1.0 then we need to resize the face.
diff --git a/src/font/Metrics.zig b/src/font/Metrics.zig
index a0bc047c4..668b6f15f 100644
--- a/src/font/Metrics.zig
+++ b/src/font/Metrics.zig
@@ -471,23 +471,23 @@ pub const Modifier = union(enum) {
test "formatConfig percent" {
const configpkg = @import("../config.zig");
const testing = std.testing;
- var buf = std.ArrayList(u8).init(testing.allocator);
+ var buf: std.Io.Writer.Allocating = .init(testing.allocator);
defer buf.deinit();
const p = try parseCLI("24%");
- try p.formatEntry(configpkg.entryFormatter("a", buf.writer()));
- try std.testing.expectEqualSlices(u8, "a = 24%\n", buf.items);
+ try p.formatEntry(configpkg.entryFormatter("a", &buf.writer));
+ try std.testing.expectEqualSlices(u8, "a = 24%\n", buf.written());
}
test "formatConfig absolute" {
const configpkg = @import("../config.zig");
const testing = std.testing;
- var buf = std.ArrayList(u8).init(testing.allocator);
+ var buf: std.Io.Writer.Allocating = .init(testing.allocator);
defer buf.deinit();
const p = try parseCLI("-30");
- try p.formatEntry(configpkg.entryFormatter("a", buf.writer()));
- try std.testing.expectEqualSlices(u8, "a = -30\n", buf.items);
+ try p.formatEntry(configpkg.entryFormatter("a", &buf.writer));
+ try std.testing.expectEqualSlices(u8, "a = -30\n", buf.written());
}
};
diff --git a/src/font/SharedGridSet.zig b/src/font/SharedGridSet.zig
index 813a8d6d0..4512e23cc 100644
--- a/src/font/SharedGridSet.zig
+++ b/src/font/SharedGridSet.zig
@@ -596,10 +596,10 @@ pub const Key = struct {
// from DerivedConfig below.
var config = try DerivedConfig.init(alloc, config_src);
- var descriptors = std.ArrayList(discovery.Descriptor).init(alloc);
- defer descriptors.deinit();
+ var descriptors: std.ArrayList(discovery.Descriptor) = .empty;
+ defer descriptors.deinit(alloc);
for (config.@"font-family".list.items) |family| {
- try descriptors.append(.{
+ try descriptors.append(alloc, .{
.family = family,
.style = config.@"font-style".nameValue(),
.size = font_size.points,
@@ -617,7 +617,7 @@ pub const Key = struct {
// italic.
for (config.@"font-family-bold".list.items) |family| {
const style = config.@"font-style-bold".nameValue();
- try descriptors.append(.{
+ try descriptors.append(alloc, .{
.family = family,
.style = style,
.size = font_size.points,
@@ -627,7 +627,7 @@ pub const Key = struct {
}
for (config.@"font-family-italic".list.items) |family| {
const style = config.@"font-style-italic".nameValue();
- try descriptors.append(.{
+ try descriptors.append(alloc, .{
.family = family,
.style = style,
.size = font_size.points,
@@ -637,7 +637,7 @@ pub const Key = struct {
}
for (config.@"font-family-bold-italic".list.items) |family| {
const style = config.@"font-style-bold-italic".nameValue();
- try descriptors.append(.{
+ try descriptors.append(alloc, .{
.family = family,
.style = style,
.size = font_size.points,
@@ -681,7 +681,7 @@ pub const Key = struct {
return .{
.arena = arena,
- .descriptors = try descriptors.toOwnedSlice(),
+ .descriptors = try descriptors.toOwnedSlice(alloc),
.style_offsets = .{
regular_offset,
bold_offset,
diff --git a/src/font/opentype/sfnt.zig b/src/font/opentype/sfnt.zig
index 82c118bce..d97d9e2d5 100644
--- a/src/font/opentype/sfnt.zig
+++ b/src/font/opentype/sfnt.zig
@@ -106,7 +106,7 @@ fn FixedPoint(comptime T: type, int_bits: u64, frac_bits: u64) type {
self: Self,
comptime fmt: []const u8,
options: std.fmt.FormatOptions,
- writer: anytype,
+ writer: *std.Io.Writer,
) !void {
_ = fmt;
_ = options;
@@ -176,7 +176,7 @@ pub const SFNT = struct {
self: OffsetSubtable,
comptime fmt: []const u8,
options: std.fmt.FormatOptions,
- writer: anytype,
+ writer: *std.Io.Writer,
) !void {
_ = fmt;
_ = options;
@@ -210,7 +210,7 @@ pub const SFNT = struct {
self: TableRecord,
comptime fmt: []const u8,
options: std.fmt.FormatOptions,
- writer: anytype,
+ writer: *std.Io.Writer,
) !void {
_ = fmt;
_ = options;
diff --git a/src/font/shaper/feature.zig b/src/font/shaper/feature.zig
index 5fce7d6eb..40770376b 100644
--- a/src/font/shaper/feature.zig
+++ b/src/font/shaper/feature.zig
@@ -201,7 +201,7 @@ pub const Feature = struct {
self: Feature,
comptime layout: []const u8,
opts: std.fmt.FormatOptions,
- writer: anytype,
+ writer: *std.Io.Writer,
) !void {
_ = layout;
_ = opts;
@@ -262,7 +262,7 @@ pub const FeatureList = struct {
self: FeatureList,
comptime layout: []const u8,
opts: std.fmt.FormatOptions,
- writer: anytype,
+ writer: *std.Io.Writer,
) !void {
for (self.features.items, 0..) |feature, i| {
try feature.format(layout, opts, writer);
diff --git a/src/font/shaper/run.zig b/src/font/shaper/run.zig
index 7bd019fd7..da3c51cee 100644
--- a/src/font/shaper/run.zig
+++ b/src/font/shaper/run.zig
@@ -356,8 +356,8 @@ pub const RunIterator = struct {
// If this is a grapheme, we need to find a font that supports
// all of the codepoints in the grapheme.
const cps = self.opts.row.grapheme(cell) orelse return primary;
- var candidates = try std.ArrayList(font.Collection.Index).initCapacity(alloc, cps.len + 1);
- defer candidates.deinit();
+ var candidates: std.ArrayList(font.Collection.Index) = try .initCapacity(alloc, cps.len + 1);
+ defer candidates.deinit(alloc);
candidates.appendAssumeCapacity(primary);
for (cps) |cp| {
diff --git a/src/global.zig b/src/global.zig
index e68ec7f74..8034fabe0 100644
--- a/src/global.zig
+++ b/src/global.zig
@@ -140,7 +140,7 @@ pub const GlobalState = struct {
std.log.info("dependency fontconfig={d}", .{fontconfig.version()});
}
std.log.info("renderer={}", .{renderer.Renderer});
- std.log.info("libxev default backend={s}", .{@tagName(xev.backend)});
+ std.log.info("libxev default backend={t}", .{xev.backend});
// As early as possible, initialize our resource limits.
self.rlimits = .init();
@@ -206,7 +206,7 @@ pub const GlobalState = struct {
var sa: p.Sigaction = .{
.handler = .{ .handler = p.SIG.IGN },
- .mask = p.empty_sigset,
+ .mask = p.sigemptyset(),
.flags = 0,
};
diff --git a/src/helpgen.zig b/src/helpgen.zig
index 57296fe86..fe30db10c 100644
--- a/src/helpgen.zig
+++ b/src/helpgen.zig
@@ -11,19 +11,22 @@ pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
const alloc = gpa.allocator();
- const stdout = std.io.getStdOut().writer();
- try stdout.writeAll(
+ var buf: [4096]u8 = undefined;
+ var stdout = std.fs.File.stdout().writer(&buf);
+ const writer = &stdout.interface;
+ try writer.writeAll(
\\// THIS FILE IS AUTO GENERATED
\\
\\
);
- try genConfig(alloc, stdout);
- try genActions(alloc, stdout);
- try genKeybindActions(alloc, stdout);
+ try genConfig(alloc, writer);
+ try genActions(alloc, writer);
+ try genKeybindActions(alloc, writer);
+ try stdout.end();
}
-fn genConfig(alloc: std.mem.Allocator, writer: anytype) !void {
+fn genConfig(alloc: std.mem.Allocator, writer: *std.Io.Writer) !void {
var ast = try std.zig.Ast.parse(alloc, @embedFile("config/Config.zig"), .zig);
defer ast.deinit(alloc);
@@ -44,7 +47,7 @@ fn genConfig(alloc: std.mem.Allocator, writer: anytype) !void {
fn genConfigField(
alloc: std.mem.Allocator,
- writer: anytype,
+ writer: *std.Io.Writer,
ast: std.zig.Ast,
comptime field: []const u8,
) !void {
@@ -69,7 +72,7 @@ fn genConfigField(
}
}
-fn genActions(alloc: std.mem.Allocator, writer: anytype) !void {
+fn genActions(alloc: std.mem.Allocator, writer: *std.Io.Writer) !void {
try writer.writeAll(
\\
\\/// Actions help
@@ -115,7 +118,7 @@ fn genActions(alloc: std.mem.Allocator, writer: anytype) !void {
try writer.writeAll("};\n");
}
-fn genKeybindActions(alloc: std.mem.Allocator, writer: anytype) !void {
+fn genKeybindActions(alloc: std.mem.Allocator, writer: *std.Io.Writer) !void {
var ast = try std.zig.Ast.parse(alloc, @embedFile("input/Binding.zig"), .zig);
defer ast.deinit(alloc);
@@ -149,24 +152,24 @@ fn extractDocComments(
} else unreachable;
// Go through and build up the lines.
- var lines = std.ArrayList([]const u8).init(alloc);
- defer lines.deinit();
+ var lines: std.ArrayList([]const u8) = .empty;
+ defer lines.deinit(alloc);
for (start_idx..index + 1) |i| {
const token = tokens[i];
if (token != .doc_comment) break;
- try lines.append(ast.tokenSlice(@intCast(i))[3..]);
+ try lines.append(alloc, ast.tokenSlice(@intCast(i))[3..]);
}
// Convert the lines to a multiline string.
- var buffer = std.ArrayList(u8).init(alloc);
- const writer = buffer.writer();
+ var buffer: std.Io.Writer.Allocating = .init(alloc);
+ defer buffer.deinit();
const prefix = findCommonPrefix(lines);
for (lines.items) |line| {
- try writer.writeAll(" \\\\");
- try writer.writeAll(line[@min(prefix, line.len)..]);
- try writer.writeAll("\n");
+ try buffer.writer.writeAll(" \\\\");
+ try buffer.writer.writeAll(line[@min(prefix, line.len)..]);
+ try buffer.writer.writeAll("\n");
}
- try writer.writeAll(";\n");
+ try buffer.writer.writeAll(";\n");
return buffer.toOwnedSlice();
}
diff --git a/src/input/Binding.zig b/src/input/Binding.zig
index 642044067..c44fb0b09 100644
--- a/src/input/Binding.zig
+++ b/src/input/Binding.zig
@@ -7,6 +7,7 @@ const Allocator = std.mem.Allocator;
const assert = std.debug.assert;
const build_config = @import("../build_config.zig");
const uucode = @import("uucode");
+const EntryFormatter = @import("../config/formatter.zig").EntryFormatter;
const key = @import("key.zig");
const KeyEvent = key.KeyEvent;
@@ -1184,13 +1185,8 @@ pub const Action = union(enum) {
/// action back into the format used by parse.
pub fn format(
self: Action,
- comptime layout: []const u8,
- opts: std.fmt.FormatOptions,
- writer: anytype,
+ writer: *std.Io.Writer,
) !void {
- _ = layout;
- _ = opts;
-
switch (self) {
inline else => |value| {
// All actions start with the tag.
@@ -1206,16 +1202,16 @@ pub const Action = union(enum) {
}
fn formatValue(
- writer: anytype,
+ writer: *std.Io.Writer,
value: anytype,
) !void {
const Value = @TypeOf(value);
const value_info = @typeInfo(Value);
switch (Value) {
void => {},
- []const u8 => try std.zig.stringEscape(value, "", .{}, writer),
+ []const u8 => try std.zig.stringEscape(value, writer),
else => switch (value_info) {
- .@"enum" => try writer.print("{s}", .{@tagName(value)}),
+ .@"enum" => try writer.print("{t}", .{value}),
.float => try writer.print("{d}", .{value}),
.int => try writer.print("{d}", .{value}),
.@"struct" => |info| if (!info.is_tuple) {
@@ -1648,13 +1644,8 @@ pub const Trigger = struct {
/// Format implementation for fmt package.
pub fn format(
self: Trigger,
- comptime layout: []const u8,
- opts: std.fmt.FormatOptions,
- writer: anytype,
+ writer: *std.Io.Writer,
) !void {
- _ = layout;
- _ = opts;
-
// Modifiers first
if (self.mods.super) try writer.writeAll("super+");
if (self.mods.ctrl) try writer.writeAll("ctrl+");
@@ -1663,7 +1654,7 @@ pub const Trigger = struct {
// Key
switch (self.key) {
- .physical => |k| try writer.print("{s}", .{@tagName(k)}),
+ .physical => |k| try writer.print("{t}", .{k}),
.unicode => |c| try writer.print("{u}", .{c}),
}
}
@@ -1721,13 +1712,8 @@ pub const Set = struct {
/// action back into the format used by parse.
pub fn format(
self: Value,
- comptime layout: []const u8,
- opts: std.fmt.FormatOptions,
- writer: anytype,
+ writer: *std.Io.Writer,
) !void {
- _ = layout;
- _ = opts;
-
switch (self) {
.leader => |set| {
// the leader key was already printed.
@@ -1758,26 +1744,34 @@ pub const Set = struct {
/// that is shared between calls to nested levels of the set.
/// For example, 'a>b>c=x' and 'a>b>d=y' will re-use the 'a>b' written
/// to the buffer before flushing it to the formatter with 'c=x' and 'd=y'.
- pub fn formatEntries(self: Value, buffer_stream: anytype, formatter: anytype) !void {
+ pub fn formatEntries(
+ self: Value,
+ buffer: *std.Io.Writer,
+ formatter: EntryFormatter,
+ ) !void {
switch (self) {
.leader => |set| {
// We'll rewind to this position after each sub-entry,
// sharing the prefix between siblings.
- const pos = try buffer_stream.getPos();
+ const pos = buffer.end;
var iter = set.bindings.iterator();
while (iter.next()) |binding| {
- buffer_stream.seekTo(pos) catch unreachable; // can't fail
- std.fmt.format(buffer_stream.writer(), ">{s}", .{binding.key_ptr.*}) catch return error.OutOfMemory;
- try binding.value_ptr.*.formatEntries(buffer_stream, formatter);
+ // I'm not exactly if this is safe for any arbitrary
+ // writer since the Writer interface does not have any
+ // rewind functions, but for our use case of a
+ // fixed-size buffer writer this should work just fine.
+ buffer.end = pos;
+ buffer.print(">{f}", .{binding.key_ptr.*}) catch return error.OutOfMemory;
+ try binding.value_ptr.*.formatEntries(buffer, formatter);
}
},
.leaf => |leaf| {
// When we get to the leaf, the buffer_stream contains
// the full sequence of keys needed to reach this action.
- std.fmt.format(buffer_stream.writer(), "={s}", .{leaf.action}) catch return error.OutOfMemory;
- try formatter.formatEntry([]const u8, buffer_stream.getWritten());
+ buffer.print("={f}", .{leaf.action}) catch return error.OutOfMemory;
+ try formatter.formatEntry([]const u8, buffer.buffer[0..buffer.end]);
},
}
}
@@ -3234,11 +3228,8 @@ test "action: format" {
const a: Action = .{ .text = "👻" };
- var buf: std.ArrayListUnmanaged(u8) = .empty;
- defer buf.deinit(alloc);
-
- const writer = buf.writer(alloc);
- try a.format("", .{}, writer);
-
- try testing.expectEqualStrings("text:\\xf0\\x9f\\x91\\xbb", buf.items);
+ var buf: std.Io.Writer.Allocating = .init(alloc);
+ defer buf.deinit();
+ try a.format(&buf.writer);
+ try testing.expectEqualStrings("text:\\xf0\\x9f\\x91\\xbb", buf.written());
}
diff --git a/src/input/command.zig b/src/input/command.zig
index bf5061c12..ba55820fc 100644
--- a/src/input/command.zig
+++ b/src/input/command.zig
@@ -50,7 +50,7 @@ pub const Command = struct {
return .{
.action_key = @tagName(self.action),
- .action = std.fmt.comptimePrint("{s}", .{self.action}),
+ .action = std.fmt.comptimePrint("{t}", .{self.action}),
.title = self.title,
.description = self.description,
};
@@ -94,6 +94,7 @@ pub const defaults: []const Command = defaults: {
/// Defaults in C-compatible form.
pub const defaultsC: []const Command.C = defaults: {
+ @setEvalBranchQuota(100_000);
var result: [defaults.len]Command.C = undefined;
for (defaults, 0..) |cmd, i| result[i] = cmd.comptimeCval();
const final = result;
diff --git a/src/input/function_keys.zig b/src/input/function_keys.zig
index 33a5b89c0..8c89b39bd 100644
--- a/src/input/function_keys.zig
+++ b/src/input/function_keys.zig
@@ -278,6 +278,7 @@ fn pcStyle(comptime fmt: []const u8) []Entry {
// The comptime {} wrapper is superfluous but it prevents us from
// accidentally running this function at runtime.
comptime {
+ @setEvalBranchQuota(500_000);
var entries: [modifiers.len]Entry = undefined;
for (modifiers, 2.., 0..) |mods, code, i| {
entries[i] = .{
diff --git a/src/input/helpgen_actions.zig b/src/input/helpgen_actions.zig
index 1382bbe95..4210f1f91 100644
--- a/src/input/helpgen_actions.zig
+++ b/src/input/helpgen_actions.zig
@@ -13,7 +13,7 @@ pub const Format = enum {
/// Markdown formatted output
markdown,
- fn formatFieldName(self: Format, writer: anytype, field_name: []const u8) !void {
+ fn formatFieldName(self: Format, writer: *std.Io.Writer, field_name: []const u8) !void {
switch (self) {
.plaintext => {
try writer.writeAll(field_name);
@@ -27,16 +27,16 @@ pub const Format = enum {
}
}
- fn formatDocLine(self: Format, writer: anytype, line: []const u8) !void {
+ fn formatDocLine(self: Format, writer: *std.Io.Writer, line: []const u8) !void {
switch (self) {
.plaintext => {
- try writer.appendSlice(" ");
- try writer.appendSlice(line);
- try writer.appendSlice("\n");
+ try writer.writeAll(" ");
+ try writer.writeAll(line);
+ try writer.writeAll("\n");
},
.markdown => {
- try writer.appendSlice(line);
- try writer.appendSlice("\n");
+ try writer.writeAll(line);
+ try writer.writeAll("\n");
},
}
}
@@ -61,7 +61,7 @@ pub const Format = enum {
/// Generate keybind actions documentation with the specified format
pub fn generate(
- writer: anytype,
+ writer: *std.Io.Writer,
format: Format,
show_docs: bool,
page_allocator: std.mem.Allocator,
@@ -70,8 +70,8 @@ pub fn generate(
try writer.writeAll(header);
}
- var buffer = std.ArrayList(u8).init(page_allocator);
- defer buffer.deinit();
+ var stream: std.Io.Writer.Allocating = .init(page_allocator);
+ defer stream.deinit();
const fields = @typeInfo(KeybindAction).@"union".fields;
inline for (fields) |field| {
@@ -79,10 +79,9 @@ pub fn generate(
// Write previously stored doc comment below all related actions
if (show_docs and @hasDecl(help_strings.KeybindAction, field.name)) {
- try writer.writeAll(buffer.items);
+ try writer.writeAll(stream.written());
try writer.writeAll("\n");
-
- buffer.clearRetainingCapacity();
+ stream.clearRetainingCapacity();
}
if (show_docs) {
@@ -101,13 +100,13 @@ pub fn generate(
while (iter.next()) |s| {
// If it is the last line and empty, then skip it.
if (iter.peek() == null and s.len == 0) continue;
- try format.formatDocLine(&buffer, s);
+ try format.formatDocLine(&stream.writer, s);
}
}
}
// Write any remaining buffered documentation
- if (buffer.items.len > 0) {
- try writer.writeAll(buffer.items);
+ if (stream.written().len > 0) {
+ try writer.writeAll(stream.written());
}
}
diff --git a/src/inspector/Inspector.zig b/src/inspector/Inspector.zig
index 27abb8657..49b05bd7f 100644
--- a/src/inspector/Inspector.zig
+++ b/src/inspector/Inspector.zig
@@ -149,7 +149,7 @@ pub fn setup() void {
font_config.FontDataOwnedByAtlas = false;
_ = cimgui.c.ImFontAtlas_AddFontFromMemoryTTF(
io.Fonts,
- @constCast(@ptrCast(font.embedded.regular)),
+ @ptrCast(@constCast(font.embedded.regular)),
font.embedded.regular.len,
font_size,
font_config,
@@ -600,6 +600,7 @@ fn renderModesWindow(self: *Inspector) void {
const t = self.surface.renderer_state.terminal;
inline for (@typeInfo(terminal.Mode).@"enum".fields) |field| {
+ @setEvalBranchQuota(6000);
const tag: terminal.modes.ModeTag = @bitCast(@as(terminal.modes.ModeTag.Backing, field.value));
cimgui.c.igTableNextRow(cimgui.c.ImGuiTableRowFlags_None, 0);
diff --git a/src/inspector/termio.zig b/src/inspector/termio.zig
index 49ab00ecd..03a3b0375 100644
--- a/src/inspector/termio.zig
+++ b/src/inspector/termio.zig
@@ -43,9 +43,9 @@ pub const VTEvent = struct {
) !VTEvent {
var md = Metadata.init(alloc);
errdefer md.deinit();
- var buf = std.ArrayList(u8).init(alloc);
+ var buf: std.Io.Writer.Allocating = .init(alloc);
defer buf.deinit();
- try encodeAction(alloc, buf.writer(), &md, action);
+ try encodeAction(alloc, &buf.writer, &md, action);
const str = try buf.toOwnedSliceSentinel(0);
errdefer alloc.free(str);
@@ -115,7 +115,7 @@ pub const VTEvent = struct {
/// Encode a parser action as a string that we show in the logs.
fn encodeAction(
alloc: Allocator,
- writer: anytype,
+ writer: *std.Io.Writer,
md: *Metadata,
action: terminal.Parser.Action,
) !void {
@@ -125,16 +125,16 @@ pub const VTEvent = struct {
.csi_dispatch => |v| try encodeCSI(writer, v),
.esc_dispatch => |v| try encodeEsc(writer, v),
.osc_dispatch => |v| try encodeOSC(alloc, writer, md, v),
- else => try writer.print("{}", .{action}),
+ else => try writer.print("{f}", .{action}),
}
}
- fn encodePrint(writer: anytype, action: terminal.Parser.Action) !void {
+ fn encodePrint(writer: *std.Io.Writer, action: terminal.Parser.Action) !void {
const ch = action.print;
try writer.print("'{u}' (U+{X})", .{ ch, ch });
}
- fn encodeExecute(writer: anytype, action: terminal.Parser.Action) !void {
+ fn encodeExecute(writer: *std.Io.Writer, action: terminal.Parser.Action) !void {
const ch = action.execute;
switch (ch) {
0x00 => try writer.writeAll("NUL"),
@@ -158,7 +158,7 @@ pub const VTEvent = struct {
try writer.print(" (0x{X})", .{ch});
}
- fn encodeCSI(writer: anytype, csi: terminal.Parser.Action.CSI) !void {
+ fn encodeCSI(writer: *std.Io.Writer, csi: terminal.Parser.Action.CSI) !void {
for (csi.intermediates) |v| try writer.print("{c} ", .{v});
for (csi.params, 0..) |v, i| {
if (i != 0) try writer.writeByte(';');
@@ -168,14 +168,14 @@ pub const VTEvent = struct {
try writer.writeByte(csi.final);
}
- fn encodeEsc(writer: anytype, esc: terminal.Parser.Action.ESC) !void {
+ fn encodeEsc(writer: *std.Io.Writer, esc: terminal.Parser.Action.ESC) !void {
for (esc.intermediates) |v| try writer.print("{c} ", .{v});
try writer.writeByte(esc.final);
}
fn encodeOSC(
alloc: Allocator,
- writer: anytype,
+ writer: *std.Io.Writer,
md: *Metadata,
osc: terminal.osc.Command,
) !void {
@@ -265,10 +265,10 @@ pub const VTEvent = struct {
const s = if (field.type == void)
try alloc.dupeZ(u8, tag_name)
else
- try std.fmt.allocPrintZ(alloc, "{s}={}", .{
+ try std.fmt.allocPrintSentinel(alloc, "{s}={}", .{
tag_name,
@field(value, field.name),
- });
+ }, 0);
try md.put(key, s);
}
@@ -283,7 +283,7 @@ pub const VTEvent = struct {
else => switch (Value) {
u8, u16 => try md.put(
key,
- try std.fmt.allocPrintZ(alloc, "{}", .{value}),
+ try std.fmt.allocPrintSentinel(alloc, "{}", .{value}, 0),
),
[]const u8,
diff --git a/src/main_build_data.zig b/src/main_build_data.zig
index 13e604389..9fffdd0d6 100644
--- a/src/main_build_data.zig
+++ b/src/main_build_data.zig
@@ -33,7 +33,9 @@ pub fn main() !void {
const action = action_ orelse return error.NoAction;
// Our output always goes to stdout.
- const writer = std.io.getStdOut().writer();
+ var buffer: [1024]u8 = undefined;
+ var stdout_writer = std.fs.File.stdout().writer(&buffer);
+ const writer = &stdout_writer.interface;
switch (action) {
.bash => try writer.writeAll(@import("extra/bash.zig").completions),
.fish => try writer.writeAll(@import("extra/fish.zig").completions),
diff --git a/src/main_ghostty.zig b/src/main_ghostty.zig
index 9c121b950..decfc609c 100644
--- a/src/main_ghostty.zig
+++ b/src/main_ghostty.zig
@@ -35,7 +35,9 @@ pub fn main() !MainReturn {
// a global is because the C API needs to be able to access this state;
// no other Zig code should EVER access the global state.
state.init() catch |err| {
- const stderr = std.io.getStdErr().writer();
+ var buffer: [1024]u8 = undefined;
+ var stderr_writer = std.fs.File.stderr().writer(&buffer);
+ const stderr = &stderr_writer.interface;
defer posix.exit(1);
const ErrSet = @TypeOf(err) || error{Unknown};
switch (@as(ErrSet, @errorCast(err))) {
@@ -54,6 +56,7 @@ pub fn main() !MainReturn {
else => try stderr.print("invalid CLI invocation err={}\n", .{err}),
}
+ try stderr.flush();
};
defer state.deinit();
const alloc = state.alloc;
@@ -154,8 +157,12 @@ fn logFn(
.stderr => {
// Always try default to send to stderr
- const stderr = std.io.getStdErr().writer();
- nosuspend stderr.print(level_txt ++ prefix ++ format ++ "\n", args) catch return;
+ var buffer: [1024]u8 = undefined;
+ var stderr = std.fs.File.stderr().writer(&buffer);
+ const writer = &stderr.interface;
+ nosuspend writer.print(level_txt ++ prefix ++ format ++ "\n", args) catch return;
+ // TODO: Do we want to use flushless stderr in the future?
+ writer.flush() catch {};
},
}
}
diff --git a/src/os/cgroup.zig b/src/os/cgroup.zig
index 4f13921c5..97c796f8b 100644
--- a/src/os/cgroup.zig
+++ b/src/os/cgroup.zig
@@ -19,8 +19,9 @@ pub fn current(alloc: Allocator, pid: std.os.linux.pid_t) !?[]const u8 {
defer file.close();
// Read it all into memory -- we don't expect this file to ever be that large.
- var buf_reader = std.io.bufferedReader(file.reader());
- const contents = try buf_reader.reader().readAllAlloc(
+ var reader_buf: [4096]u8 = undefined;
+ var reader = file.reader(&reader_buf);
+ const contents = try reader.interface.readAlloc(
alloc,
1 * 1024 * 1024, // 1MB
);
@@ -52,7 +53,11 @@ pub fn create(
);
const file = try std.fs.cwd().openFile(pid_path, .{ .mode = .write_only });
defer file.close();
- try file.writer().print("{}", .{pid});
+
+ var file_buf: [64]u8 = undefined;
+ var writer = file.writer(&file_buf);
+ try writer.interface.print("{}", .{pid});
+ try writer.interface.flush();
}
}
@@ -182,8 +187,9 @@ pub fn controllers(alloc: Allocator, cgroup: []const u8) ![]const u8 {
// Read it all into memory -- we don't expect this file to ever
// be that large.
- var buf_reader = std.io.bufferedReader(file.reader());
- const contents = try buf_reader.reader().readAllAlloc(
+ var reader_buf: [4096]u8 = undefined;
+ var reader = file.reader(&reader_buf);
+ const contents = try reader.interface.readAlloc(
alloc,
1 * 1024 * 1024, // 1MB
);
@@ -213,7 +219,10 @@ pub fn configureControllers(
defer file.close();
// Write
- try file.writer().writeAll(v);
+ var writer_buf: [4096]u8 = undefined;
+ var writer = file.writer(&writer_buf);
+ try writer.interface.writeAll(v);
+ try writer.interface.flush();
}
pub const Limit = union(enum) {
@@ -242,5 +251,8 @@ pub fn configureLimit(cgroup: []const u8, limit: Limit) !void {
defer file.close();
// Write our limit in bytes
- try file.writer().print("{}", .{size});
+ var writer_buf: [4096]u8 = undefined;
+ var writer = file.writer(&writer_buf);
+ try writer.interface.print("{}", .{size});
+ try writer.interface.flush();
}
diff --git a/src/os/shell.zig b/src/os/shell.zig
index 3e57031dd..a6f23e843 100644
--- a/src/os/shell.zig
+++ b/src/os/shell.zig
@@ -1,110 +1,121 @@
const std = @import("std");
const testing = std.testing;
+const Writer = std.Io.Writer;
/// Writer that escapes characters that shells treat specially to reduce the
/// risk of injection attacks or other such weirdness. Specifically excludes
/// linefeeds so that they can be used to delineate lists of file paths.
///
-/// T should be a Zig type that follows the `std.io.Writer` interface.
-pub fn ShellEscapeWriter(comptime T: type) type {
- return struct {
- child_writer: T,
+/// T should be a Zig type that follows the `std.Io.Writer` interface.
+pub const ShellEscapeWriter = struct {
+ writer: Writer,
+ child: *Writer,
- fn write(self: *ShellEscapeWriter(T), data: []const u8) error{Error}!usize {
- var count: usize = 0;
- for (data) |byte| {
- const buf = switch (byte) {
- '\\',
- '"',
- '\'',
- '$',
- '`',
- '*',
- '?',
- ' ',
- '|',
- '(',
- ')',
- => &[_]u8{ '\\', byte },
- else => &[_]u8{byte},
- };
- self.child_writer.writeAll(buf) catch return error.Error;
- count += 1;
- }
- return count;
+ pub fn init(child: *Writer) ShellEscapeWriter {
+ return .{
+ .writer = .{
+ // TODO: Actually use a buffer here
+ .buffer = &.{},
+ .vtable = &.{ .drain = ShellEscapeWriter.drain },
+ },
+ .child = child,
+ };
+ }
+
+ fn drain(w: *Writer, data: []const []const u8, splat: usize) Writer.Error!usize {
+ const self: *ShellEscapeWriter = @fieldParentPtr("writer", w);
+
+ // TODO: This is a very naive implementation and does not really make
+ // full use of the post-Writergate API. However, since we know that
+ // this is going into an Allocating writer anyways, we can be a bit
+ // less strict here.
+
+ var count: usize = 0;
+ for (data[0 .. data.len - 1]) |chunk| try self.writeEscaped(chunk, &count);
+
+ for (0..splat) |_| try self.writeEscaped(data[data.len], &count);
+ return count;
+ }
+
+ fn writeEscaped(
+ self: *ShellEscapeWriter,
+ s: []const u8,
+ count: *usize,
+ ) Writer.Error!void {
+ for (s) |byte| {
+ const buf = switch (byte) {
+ '\\',
+ '"',
+ '\'',
+ '$',
+ '`',
+ '*',
+ '?',
+ ' ',
+ '|',
+ '(',
+ ')',
+ => &[_]u8{ '\\', byte },
+ else => &[_]u8{byte},
+ };
+ try self.child.writeAll(buf);
+ count.* += 1;
}
-
- const Writer = std.io.Writer(*ShellEscapeWriter(T), error{Error}, write);
-
- pub fn init(child_writer: T) ShellEscapeWriter(T) {
- return .{ .child_writer = child_writer };
- }
-
- pub fn writer(self: *ShellEscapeWriter(T)) Writer {
- return .{ .context = self };
- }
- };
-}
+ }
+};
test "shell escape 1" {
var buf: [128]u8 = undefined;
- var fmt = std.io.fixedBufferStream(&buf);
- var shell: ShellEscapeWriter(@TypeOf(fmt).Writer) = .{ .child_writer = fmt.writer() };
- const writer = shell.writer();
- try writer.writeAll("abc");
- try testing.expectEqualStrings("abc", fmt.getWritten());
+ var writer: std.Io.Writer = .fixed(&buf);
+ var shell: ShellEscapeWriter = .{ .child_writer = &writer };
+ try shell.writer.writeAll("abc");
+ try testing.expectEqualStrings("abc", writer.buffered());
}
test "shell escape 2" {
var buf: [128]u8 = undefined;
- var fmt = std.io.fixedBufferStream(&buf);
- var shell: ShellEscapeWriter(@TypeOf(fmt).Writer) = .{ .child_writer = fmt.writer() };
- const writer = shell.writer();
- try writer.writeAll("a c");
- try testing.expectEqualStrings("a\\ c", fmt.getWritten());
+ var writer: std.Io.Writer = .fixed(&buf);
+ var shell: ShellEscapeWriter = .{ .child_writer = &writer };
+ try shell.writer.writeAll("a c");
+ try testing.expectEqualStrings("a\\ c", writer.buffered());
}
test "shell escape 3" {
var buf: [128]u8 = undefined;
- var fmt = std.io.fixedBufferStream(&buf);
- var shell: ShellEscapeWriter(@TypeOf(fmt).Writer) = .{ .child_writer = fmt.writer() };
- const writer = shell.writer();
- try writer.writeAll("a?c");
- try testing.expectEqualStrings("a\\?c", fmt.getWritten());
+ var writer: std.Io.Writer = .fixed(&buf);
+ var shell: ShellEscapeWriter = .{ .child_writer = &writer };
+ try shell.writer.writeAll("a?c");
+ try testing.expectEqualStrings("a\\?c", writer.buffered());
}
test "shell escape 4" {
var buf: [128]u8 = undefined;
- var fmt = std.io.fixedBufferStream(&buf);
- var shell: ShellEscapeWriter(@TypeOf(fmt).Writer) = .{ .child_writer = fmt.writer() };
- const writer = shell.writer();
- try writer.writeAll("a\\c");
- try testing.expectEqualStrings("a\\\\c", fmt.getWritten());
+ var writer: std.Io.Writer = .fixed(&buf);
+ var shell: ShellEscapeWriter = .{ .child_writer = &writer };
+ try shell.writer.writeAll("a\\c");
+ try testing.expectEqualStrings("a\\\\c", writer.buffered());
}
test "shell escape 5" {
var buf: [128]u8 = undefined;
- var fmt = std.io.fixedBufferStream(&buf);
- var shell: ShellEscapeWriter(@TypeOf(fmt).Writer) = .{ .child_writer = fmt.writer() };
- const writer = shell.writer();
- try writer.writeAll("a|c");
- try testing.expectEqualStrings("a\\|c", fmt.getWritten());
+ var writer: std.Io.Writer = .fixed(&buf);
+ var shell: ShellEscapeWriter = .{ .child_writer = &writer };
+ try shell.writer.writeAll("a|c");
+ try testing.expectEqualStrings("a\\|c", writer.buffered());
}
test "shell escape 6" {
var buf: [128]u8 = undefined;
- var fmt = std.io.fixedBufferStream(&buf);
- var shell: ShellEscapeWriter(@TypeOf(fmt).Writer) = .{ .child_writer = fmt.writer() };
- const writer = shell.writer();
- try writer.writeAll("a\"c");
- try testing.expectEqualStrings("a\\\"c", fmt.getWritten());
+ var writer: std.Io.Writer = .fixed(&buf);
+ var shell: ShellEscapeWriter = .{ .child_writer = &writer };
+ try shell.writer.writeAll("a\"c");
+ try testing.expectEqualStrings("a\\\"c", writer.buffered());
}
test "shell escape 7" {
var buf: [128]u8 = undefined;
- var fmt = std.io.fixedBufferStream(&buf);
- var shell: ShellEscapeWriter(@TypeOf(fmt).Writer) = .{ .child_writer = fmt.writer() };
- const writer = shell.writer();
- try writer.writeAll("a(1)");
- try testing.expectEqualStrings("a\\(1\\)", fmt.getWritten());
+ var writer: std.Io.Writer = .fixed(&buf);
+ var shell: ShellEscapeWriter = .{ .child_writer = &writer };
+ try shell.writer.writeAll("a(1)");
+ try testing.expectEqualStrings("a\\(1\\)", writer.buffered());
}
diff --git a/src/pty.zig b/src/pty.zig
index 02906b778..1ab88d40f 100644
--- a/src/pty.zig
+++ b/src/pty.zig
@@ -216,7 +216,7 @@ const PosixPty = struct {
// Reset our signals
var sa: posix.Sigaction = .{
.handler = .{ .handler = posix.SIG.DFL },
- .mask = posix.empty_sigset,
+ .mask = posix.sigemptyset(),
.flags = 0,
};
posix.sigaction(posix.SIG.ABRT, &sa, null);
diff --git a/src/renderer/link.zig b/src/renderer/link.zig
index 410fb8632..9f489ed48 100644
--- a/src/renderer/link.zig
+++ b/src/renderer/link.zig
@@ -34,19 +34,19 @@ pub const Set = struct {
alloc: Allocator,
config: []const inputpkg.Link,
) !Set {
- var links = std.ArrayList(Link).init(alloc);
- defer links.deinit();
+ var links: std.ArrayList(Link) = .empty;
+ defer links.deinit(alloc);
for (config) |link| {
var regex = try link.oniRegex();
errdefer regex.deinit();
- try links.append(.{
+ try links.append(alloc, .{
.regex = regex,
.highlight = link.highlight,
});
}
- return .{ .links = try links.toOwnedSlice() };
+ return .{ .links = try links.toOwnedSlice(alloc) };
}
pub fn deinit(self: *Set, alloc: Allocator) void {
@@ -77,8 +77,8 @@ pub const Set = struct {
// as selections which contain the start and end points of
// the match. There is no way to map these back to the link
// configuration right now because we don't need to.
- var matches = std.ArrayList(terminal.Selection).init(alloc);
- defer matches.deinit();
+ var matches: std.ArrayList(terminal.Selection) = .empty;
+ defer matches.deinit(alloc);
// If our mouse is over an OSC8 link, then we can skip the regex
// matches below since OSC8 takes priority.
@@ -101,7 +101,7 @@ pub const Set = struct {
);
}
- return .{ .matches = try matches.toOwnedSlice() };
+ return .{ .matches = try matches.toOwnedSlice(alloc) };
}
fn matchSetFromOSC8(
@@ -112,8 +112,6 @@ pub const Set = struct {
mouse_pin: terminal.Pin,
mouse_mods: inputpkg.Mods,
) !void {
- _ = alloc;
-
// If the right mods aren't pressed, then we can't match.
if (!mouse_mods.equal(inputpkg.ctrlOrSuper(.{}))) return;
@@ -135,6 +133,7 @@ pub const Set = struct {
if (link.id == .implicit) {
const uri = link.uri.offset.ptr(page.memory)[0..link.uri.len];
return try self.matchSetFromOSC8Implicit(
+ alloc,
matches,
mouse_pin,
uri,
@@ -154,7 +153,7 @@ pub const Set = struct {
// building our matching selection.
if (!row.hyperlink) {
if (current) |sel| {
- try matches.append(sel);
+ try matches.append(alloc, sel);
current = null;
}
@@ -191,7 +190,7 @@ pub const Set = struct {
// No match, if we have a current selection then complete it.
if (current) |sel| {
- try matches.append(sel);
+ try matches.append(alloc, sel);
current = null;
}
}
@@ -203,6 +202,7 @@ pub const Set = struct {
/// around the mouse pin.
fn matchSetFromOSC8Implicit(
self: *const Set,
+ alloc: Allocator,
matches: *std.ArrayList(terminal.Selection),
mouse_pin: terminal.Pin,
uri: []const u8,
@@ -264,7 +264,7 @@ pub const Set = struct {
sel.endPtr().* = cell_pin;
}
- try matches.append(sel);
+ try matches.append(alloc, sel);
}
/// Fills matches with the matches from regex link matches.
@@ -334,7 +334,7 @@ pub const Set = struct {
=> if (!sel.contains(screen, mouse_pin)) continue,
}
- try matches.append(sel);
+ try matches.append(alloc, sel);
}
}
}
diff --git a/src/renderer/shadertoy.zig b/src/renderer/shadertoy.zig
index 576237587..d31c36dee 100644
--- a/src/renderer/shadertoy.zig
+++ b/src/renderer/shadertoy.zig
@@ -38,8 +38,8 @@ pub fn loadFromFiles(
paths: configpkg.RepeatablePath,
target: Target,
) ![]const [:0]const u8 {
- var list = std.ArrayList([:0]const u8).init(alloc_gpa);
- defer list.deinit();
+ var list: std.ArrayList([:0]const u8) = .empty;
+ defer list.deinit(alloc_gpa);
errdefer for (list.items) |shader| alloc_gpa.free(shader);
for (paths.value.items) |item| {
@@ -56,10 +56,10 @@ pub fn loadFromFiles(
return err;
};
log.info("loaded custom shader path={s}", .{path});
- try list.append(shader);
+ try list.append(alloc_gpa, shader);
}
- return try list.toOwnedSlice();
+ return try list.toOwnedSlice(alloc_gpa);
}
/// Load a single shader from a file and convert it to the target language
@@ -73,34 +73,35 @@ pub fn loadFromFile(
defer arena.deinit();
const alloc = arena.allocator();
- // Load the shader file
- const cwd = std.fs.cwd();
- const file = try cwd.openFile(path, .{});
- defer file.close();
-
// Read it all into memory -- we don't expect shaders to be large.
- var buf_reader = std.io.bufferedReader(file.reader());
- const src = try buf_reader.reader().readAllAlloc(
- alloc,
- 4 * 1024 * 1024, // 4MB
- );
+ const src = src: {
+ // Load the shader file
+ const cwd = std.fs.cwd();
+ const file = try cwd.openFile(path, .{});
+ defer file.close();
+
+ var buf: [4096]u8 = undefined;
+ var reader = file.reader(&buf);
+ break :src try reader.interface.readAlloc(
+ alloc,
+ 4 * 1024 * 1024, // 4MB
+ );
+ };
// Convert to full GLSL
const glsl: [:0]const u8 = glsl: {
- var list = std.ArrayList(u8).init(alloc);
- try glslFromShader(list.writer(), src);
- try list.append(0);
- break :glsl list.items[0 .. list.items.len - 1 :0];
+ var stream: std.Io.Writer.Allocating = .init(alloc);
+ try glslFromShader(&stream.writer, src);
+ try stream.writer.writeByte(0);
+ break :glsl stream.written()[0 .. stream.written().len - 1 :0];
};
// Convert to SPIR-V
const spirv: []const u8 = spirv: {
- // SpirV pointer must be aligned to 4 bytes since we expect
- // a slice of words.
- var list = std.ArrayListAligned(u8, @alignOf(u32)).init(alloc);
+ var stream: std.Io.Writer.Allocating = .init(alloc);
var errlog: SpirvLog = .{ .alloc = alloc };
defer errlog.deinit();
- spirvFromGlsl(list.writer(), &errlog, glsl) catch |err| {
+ spirvFromGlsl(&stream.writer, &errlog, glsl) catch |err| {
if (errlog.info.len > 0 or errlog.debug.len > 0) {
log.warn("spirv error path={s} info={s} debug={s}", .{
path,
@@ -111,6 +112,11 @@ pub fn loadFromFile(
return err;
};
+
+ // SpirV pointer must be aligned to 4 bytes since we expect
+ // a slice of words.
+ var list: std.ArrayListAligned(u8, .of(u32)) = .empty;
+ try list.appendSlice(alloc, stream.written());
break :spirv list.items;
};
@@ -129,7 +135,7 @@ pub fn loadFromFile(
/// mainImage function and don't define any of the uniforms. This function
/// will convert the ShaderToy shader into a valid GLSL shader that can be
/// compiled and linked.
-pub fn glslFromShader(writer: anytype, src: []const u8) !void {
+pub fn glslFromShader(writer: *std.Io.Writer, src: []const u8) !void {
const prefix = @embedFile("shaders/shadertoy_prefix.glsl");
try writer.writeAll(prefix);
try writer.writeAll("\n\n");
@@ -138,7 +144,7 @@ pub fn glslFromShader(writer: anytype, src: []const u8) !void {
/// Convert a GLSL shader into SPIR-V assembly.
pub fn spirvFromGlsl(
- writer: anytype,
+ writer: *std.Io.Writer,
errlog: ?*SpirvLog,
src: [:0]const u8,
) !void {
@@ -331,10 +337,10 @@ fn spvCross(
/// Convert ShaderToy shader to null-terminated glsl for testing.
fn testGlslZ(alloc: Allocator, src: []const u8) ![:0]const u8 {
- var list = std.ArrayList(u8).init(alloc);
- defer list.deinit();
- try glslFromShader(list.writer(), src);
- return try list.toOwnedSliceSentinel(0);
+ var buf: std.Io.Writer.Allocating = .init(alloc);
+ defer buf.deinit();
+ try glslFromShader(&buf.writer, src);
+ return try buf.toOwnedSliceSentinel(0);
}
test "spirv" {
@@ -345,9 +351,8 @@ test "spirv" {
defer alloc.free(src);
var buf: [4096 * 4]u8 = undefined;
- var buf_stream = std.io.fixedBufferStream(&buf);
- const writer = buf_stream.writer();
- try spirvFromGlsl(writer, null, src);
+ var writer: std.Io.Writer = .fixed(&buf);
+ try spirvFromGlsl(&writer, null, src);
}
test "spirv invalid" {
@@ -358,12 +363,11 @@ test "spirv invalid" {
defer alloc.free(src);
var buf: [4096 * 4]u8 = undefined;
- var buf_stream = std.io.fixedBufferStream(&buf);
- const writer = buf_stream.writer();
+ var writer: std.Io.Writer = .fixed(&buf);
var errlog: SpirvLog = .{ .alloc = alloc };
defer errlog.deinit();
- try testing.expectError(error.GlslangFailed, spirvFromGlsl(writer, &errlog, src));
+ try testing.expectError(error.GlslangFailed, spirvFromGlsl(&writer, &errlog, src));
try testing.expect(errlog.info.len > 0);
}
@@ -374,9 +378,14 @@ test "shadertoy to msl" {
const src = try testGlslZ(alloc, test_crt);
defer alloc.free(src);
- var spvlist = std.ArrayListAligned(u8, @alignOf(u32)).init(alloc);
- defer spvlist.deinit();
- try spirvFromGlsl(spvlist.writer(), null, src);
+ var buf: std.Io.Writer.Allocating = .init(alloc);
+ defer buf.deinit();
+ try spirvFromGlsl(&buf.writer, null, src);
+
+ // TODO: Replace this with an aligned version of Writer.Allocating
+ var spvlist: std.ArrayListAligned(u8, .of(u32)) = .empty;
+ defer spvlist.deinit(alloc);
+ try spvlist.appendSlice(alloc, buf.written());
const msl = try mslFromSpv(alloc, spvlist.items);
defer alloc.free(msl);
@@ -389,9 +398,14 @@ test "shadertoy to glsl" {
const src = try testGlslZ(alloc, test_crt);
defer alloc.free(src);
- var spvlist = std.ArrayListAligned(u8, @alignOf(u32)).init(alloc);
- defer spvlist.deinit();
- try spirvFromGlsl(spvlist.writer(), null, src);
+ var buf: std.Io.Writer.Allocating = .init(alloc);
+ defer buf.deinit();
+ try spirvFromGlsl(&buf.writer, null, src);
+
+ // TODO: Replace this with an aligned version of Writer.Allocating
+ var spvlist: std.ArrayListAligned(u8, .of(u32)) = .empty;
+ defer spvlist.deinit(alloc);
+ try spvlist.appendSlice(alloc, buf.written());
const glsl = try glslFromSpv(alloc, spvlist.items);
defer alloc.free(glsl);
diff --git a/src/synthetic/cli.zig b/src/synthetic/cli.zig
index 36832587c..b32469aab 100644
--- a/src/synthetic/cli.zig
+++ b/src/synthetic/cli.zig
@@ -90,12 +90,17 @@ fn mainActionImpl(
const rand = prng.random();
// Our output always goes to stdout.
- const writer = std.io.getStdOut().writer();
+ var buffer: [2048]u8 = undefined;
+ var stdout_writer = std.fs.File.stdout().writer(&buffer);
+ const writer = &stdout_writer.interface;
// Create our implementation
const impl = try Impl.create(alloc, opts);
defer impl.destroy(alloc);
try impl.run(writer, rand);
+
+ // Always flush
+ try writer.flush();
}
test {
diff --git a/src/synthetic/cli/Ascii.zig b/src/synthetic/cli/Ascii.zig
index 25e5bb00b..339bdee2e 100644
--- a/src/synthetic/cli/Ascii.zig
+++ b/src/synthetic/cli/Ascii.zig
@@ -23,7 +23,7 @@ pub fn destroy(self: *Ascii, alloc: Allocator) void {
alloc.destroy(self);
}
-pub fn run(self: *Ascii, writer: anytype, rand: std.Random) !void {
+pub fn run(self: *Ascii, writer: *std.Io.Writer, rand: std.Random) !void {
_ = self;
var gen: synthetic.Bytes = .{
@@ -35,10 +35,10 @@ pub fn run(self: *Ascii, writer: anytype, rand: std.Random) !void {
while (true) {
const data = try gen.next(&buf);
writer.writeAll(data) catch |err| {
- const Error = error{ NoSpaceLeft, BrokenPipe } || @TypeOf(err);
+ const Error = error{ WriteFailed, BrokenPipe } || @TypeOf(err);
switch (@as(Error, err)) {
error.BrokenPipe => return, // stdout closed
- error.NoSpaceLeft => return, // fixed buffer full
+ error.WriteFailed => return, // fixed buffer full
else => return err,
}
};
@@ -56,8 +56,6 @@ test Ascii {
const rand = prng.random();
var buf: [1024]u8 = undefined;
- var fbs = std.io.fixedBufferStream(&buf);
- const writer = fbs.writer();
-
- try impl.run(writer, rand);
+ var writer: std.Io.Writer = .fixed(&buf);
+ try impl.run(&writer, rand);
}
diff --git a/src/synthetic/cli/Osc.zig b/src/synthetic/cli/Osc.zig
index 4792cda6b..23d19e4ae 100644
--- a/src/synthetic/cli/Osc.zig
+++ b/src/synthetic/cli/Osc.zig
@@ -29,7 +29,7 @@ pub fn destroy(self: *Osc, alloc: Allocator) void {
alloc.destroy(self);
}
-pub fn run(self: *Osc, writer: anytype, rand: std.Random) !void {
+pub fn run(self: *Osc, writer: *std.Io.Writer, rand: std.Random) !void {
var gen: synthetic.Osc = .{
.rand = rand,
.p_valid = self.opts.@"p-valid",
@@ -39,10 +39,10 @@ pub fn run(self: *Osc, writer: anytype, rand: std.Random) !void {
while (true) {
const data = try gen.next(&buf);
writer.writeAll(data) catch |err| {
- const Error = error{ NoSpaceLeft, BrokenPipe } || @TypeOf(err);
+ const Error = error{ WriteFailed, BrokenPipe } || @TypeOf(err);
switch (@as(Error, err)) {
error.BrokenPipe => return, // stdout closed
- error.NoSpaceLeft => return, // fixed buffer full
+ error.WriteFailed => return, // fixed buffer full
else => return err,
}
};
@@ -60,8 +60,6 @@ test Osc {
const rand = prng.random();
var buf: [1024]u8 = undefined;
- var fbs = std.io.fixedBufferStream(&buf);
- const writer = fbs.writer();
-
- try impl.run(writer, rand);
+ var writer: std.Io.Writer = .fixed(&buf);
+ try impl.run(&writer, rand);
}
diff --git a/src/synthetic/cli/Utf8.zig b/src/synthetic/cli/Utf8.zig
index 28a11f891..3c2fddef7 100644
--- a/src/synthetic/cli/Utf8.zig
+++ b/src/synthetic/cli/Utf8.zig
@@ -23,7 +23,7 @@ pub fn destroy(self: *Utf8, alloc: Allocator) void {
alloc.destroy(self);
}
-pub fn run(self: *Utf8, writer: anytype, rand: std.Random) !void {
+pub fn run(self: *Utf8, writer: *std.Io.Writer, rand: std.Random) !void {
_ = self;
var gen: synthetic.Utf8 = .{
@@ -34,10 +34,10 @@ pub fn run(self: *Utf8, writer: anytype, rand: std.Random) !void {
while (true) {
const data = try gen.next(&buf);
writer.writeAll(data) catch |err| {
- const Error = error{ NoSpaceLeft, BrokenPipe } || @TypeOf(err);
+ const Error = error{ WriteFailed, BrokenPipe } || @TypeOf(err);
switch (@as(Error, err)) {
error.BrokenPipe => return, // stdout closed
- error.NoSpaceLeft => return, // fixed buffer full
+ error.WriteFailed => return, // fixed buffer full
else => return err,
}
};
@@ -55,8 +55,6 @@ test Utf8 {
const rand = prng.random();
var buf: [1024]u8 = undefined;
- var fbs = std.io.fixedBufferStream(&buf);
- const writer = fbs.writer();
-
- try impl.run(writer, rand);
+ var writer: std.Io.Writer = .fixed(&buf);
+ try impl.run(&writer, rand);
}
diff --git a/src/terminal/PageList.zig b/src/terminal/PageList.zig
index 8aeb6f6dc..9bf116598 100644
--- a/src/terminal/PageList.zig
+++ b/src/terminal/PageList.zig
@@ -56,7 +56,7 @@ const std_size = Page.layout(std_capacity).total_size;
/// allocator because we need memory that is zero-initialized and page-aligned.
const PagePool = std.heap.MemoryPoolAligned(
[std_size]u8,
- std.heap.page_size_min,
+ .fromByteUnits(std.heap.page_size_min),
);
/// List of pins, known as "tracked" pins. These are pins that are kept
@@ -388,11 +388,18 @@ pub fn reset(self: *PageList) void {
const page_arena = &self.pool.pages.arena;
var it = page_arena.state.buffer_list.first;
while (it) |node| : (it = node.next) {
- // The fully allocated buffer
- const alloc_buf = @as([*]u8, @ptrCast(node))[0..node.data];
+ // WARN: Since HeapAllocator's BufNode is not public API,
+ // we have to hardcode its layout here. We do a comptime assert
+ // on Zig version to verify we check it on every bump.
+ const BufNode = struct {
+ data: usize,
+ node: std.SinglyLinkedList.Node,
+ };
+ const buf_node: *BufNode = @fieldParentPtr("node", node);
+ // The fully allocated buffer
+ const alloc_buf = @as([*]u8, @ptrCast(buf_node))[0..buf_node.data];
// The buffer minus our header
- const BufNode = @TypeOf(page_arena.state.buffer_list).Node;
const data_buf = alloc_buf[@sizeOf(BufNode)..];
@memset(data_buf, 0);
}
@@ -2075,7 +2082,7 @@ inline fn createPageExt(
else
try page_alloc.alignedAlloc(
u8,
- std.heap.page_size_min,
+ .fromByteUnits(std.heap.page_size_min),
layout.total_size,
);
errdefer if (pooled)
@@ -2676,7 +2683,7 @@ pub const EncodeUtf8Options = struct {
/// predates this and is a thin wrapper around it so the tests all live there.
pub fn encodeUtf8(
self: *const PageList,
- writer: anytype,
+ writer: *std.Io.Writer,
opts: EncodeUtf8Options,
) anyerror!void {
// We don't currently use self at all. There is an argument that this
@@ -2716,7 +2723,7 @@ pub fn encodeUtf8(
/// 1 | etc.| | 4
/// +-----+ :
/// +--------+
-pub fn diagram(self: *const PageList, writer: anytype) !void {
+pub fn diagram(self: *const PageList, writer: *std.Io.Writer) !void {
const active_pin = self.getTopLeft(.active);
var active = false;
diff --git a/src/terminal/Parser.zig b/src/terminal/Parser.zig
index 05cbe7957..ca2fd3718 100644
--- a/src/terminal/Parser.zig
+++ b/src/terminal/Parser.zig
@@ -97,13 +97,9 @@ pub const Action = union(enum) {
// Implement formatter for logging
pub fn format(
self: CSI,
- comptime layout: []const u8,
- opts: std.fmt.FormatOptions,
- writer: anytype,
+ writer: *std.Io.Writer,
) !void {
- _ = layout;
- _ = opts;
- try std.fmt.format(writer, "ESC [ {s} {any} {c}", .{
+ try writer.print("ESC [ {s} {any} {c}", .{
self.intermediates,
self.params,
self.final,
@@ -118,13 +114,9 @@ pub const Action = union(enum) {
// Implement formatter for logging
pub fn format(
self: ESC,
- comptime layout: []const u8,
- opts: std.fmt.FormatOptions,
- writer: anytype,
+ writer: *std.Io.Writer,
) !void {
- _ = layout;
- _ = opts;
- try std.fmt.format(writer, "ESC {s} {c}", .{
+ try writer.print("ESC {s} {c}", .{
self.intermediates,
self.final,
});
@@ -142,11 +134,8 @@ pub const Action = union(enum) {
// print out custom formats for some of our primitives.
pub fn format(
self: Action,
- comptime layout: []const u8,
- opts: std.fmt.FormatOptions,
- writer: anytype,
+ writer: *std.Io.Writer,
) !void {
- _ = layout;
const T = Action;
const info = @typeInfo(T).@"union";
@@ -162,21 +151,20 @@ pub const Action = union(enum) {
const value = @field(self, u_field.name);
switch (@TypeOf(value)) {
// Unicode
- u21 => try std.fmt.format(writer, "'{u}' (U+{X})", .{ value, value }),
+ u21 => try writer.print("'{u}' (U+{X})", .{ value, value }),
// Byte
- u8 => try std.fmt.format(writer, "0x{x}", .{value}),
+ u8 => try writer.print("0x{x}", .{value}),
// Note: we don't do ASCII (u8) because there are a lot
// of invisible characters we don't want to handle right
// now.
// All others do the default behavior
- else => try std.fmt.formatType(
- @field(self, u_field.name),
+ else => try writer.printValue(
"any",
- opts,
- writer,
+ .{},
+ @field(self, u_field.name),
3,
),
}
@@ -391,7 +379,7 @@ inline fn doAction(self: *Parser, action: TransitionAction, c: u8) ?Action {
// We only allow colon or mixed separators for the 'm' command.
if (c != 'm' and self.params_sep.count() > 0) {
log.warn(
- "CSI colon or mixed separators only allowed for 'm' command, got: {}",
+ "CSI colon or mixed separators only allowed for 'm' command, got: {f}",
.{result},
);
break :csi_dispatch null;
diff --git a/src/terminal/Screen.zig b/src/terminal/Screen.zig
index 0c60dcec8..a98407af7 100644
--- a/src/terminal/Screen.zig
+++ b/src/terminal/Screen.zig
@@ -2168,17 +2168,21 @@ pub const SelectionString = struct {
/// Returns the raw text associated with a selection. This will unwrap
/// soft-wrapped edges. The returned slice is owned by the caller and allocated
/// using alloc, not the allocator associated with the screen (unless they match).
-pub fn selectionString(self: *Screen, alloc: Allocator, opts: SelectionString) ![:0]const u8 {
+pub fn selectionString(
+ self: *Screen,
+ alloc: Allocator,
+ opts: SelectionString,
+) ![:0]const u8 {
// Use an ArrayList so that we can grow the array as we go. We
// build an initial capacity of just our rows in our selection times
// columns. It can be more or less based on graphemes, newlines, etc.
- var strbuilder = std.ArrayList(u8).init(alloc);
- defer strbuilder.deinit();
+ var strbuilder: std.ArrayList(u8) = .empty;
+ defer strbuilder.deinit(alloc);
// If we're building a stringmap, create our builder for the pins.
const MapBuilder = std.ArrayList(Pin);
- var mapbuilder: ?MapBuilder = if (opts.map != null) MapBuilder.init(alloc) else null;
- defer if (mapbuilder) |*b| b.deinit();
+ var mapbuilder: ?MapBuilder = if (opts.map != null) .empty else null;
+ defer if (mapbuilder) |*b| b.deinit(alloc);
const sel_ordered = opts.sel.ordered(self, .forward);
const sel_start: Pin = start: {
@@ -2235,9 +2239,9 @@ pub fn selectionString(self: *Screen, alloc: Allocator, opts: SelectionString) !
const raw: u21 = if (cell.hasText()) cell.content.codepoint else 0;
const char = if (raw > 0) raw else ' ';
const encode_len = try std.unicode.utf8Encode(char, &buf);
- try strbuilder.appendSlice(buf[0..encode_len]);
+ try strbuilder.appendSlice(alloc, buf[0..encode_len]);
if (mapbuilder) |*b| {
- for (0..encode_len) |_| try b.append(.{
+ for (0..encode_len) |_| try b.append(alloc, .{
.node = chunk.node,
.y = @intCast(y),
.x = @intCast(x),
@@ -2248,9 +2252,9 @@ pub fn selectionString(self: *Screen, alloc: Allocator, opts: SelectionString) !
const cps = chunk.node.data.lookupGrapheme(cell).?;
for (cps) |cp| {
const encode_len = try std.unicode.utf8Encode(cp, &buf);
- try strbuilder.appendSlice(buf[0..encode_len]);
+ try strbuilder.appendSlice(alloc, buf[0..encode_len]);
if (mapbuilder) |*b| {
- for (0..encode_len) |_| try b.append(.{
+ for (0..encode_len) |_| try b.append(alloc, .{
.node = chunk.node,
.y = @intCast(y),
.x = @intCast(x),
@@ -2265,8 +2269,8 @@ pub fn selectionString(self: *Screen, alloc: Allocator, opts: SelectionString) !
if (!is_final_row and
(!row.wrap or sel_ordered.rectangle))
{
- try strbuilder.append('\n');
- if (mapbuilder) |*b| try b.append(.{
+ try strbuilder.append(alloc, '\n');
+ if (mapbuilder) |*b| try b.append(alloc, .{
.node = chunk.node,
.y = @intCast(y),
.x = chunk.node.data.size.cols - 1,
@@ -2281,11 +2285,11 @@ pub fn selectionString(self: *Screen, alloc: Allocator, opts: SelectionString) !
// If we have a mapbuilder, we need to setup our string map.
if (mapbuilder) |*b| {
- var strclone = try strbuilder.clone();
- defer strclone.deinit();
- const str = try strclone.toOwnedSliceSentinel(0);
+ var strclone = try strbuilder.clone(alloc);
+ defer strclone.deinit(alloc);
+ const str = try strclone.toOwnedSliceSentinel(alloc, 0);
errdefer alloc.free(str);
- const map = try b.toOwnedSlice();
+ const map = try b.toOwnedSlice(alloc);
errdefer alloc.free(map);
opts.map.?.* = .{ .string = str, .map = map };
}
@@ -2306,7 +2310,7 @@ pub fn selectionString(self: *Screen, alloc: Allocator, opts: SelectionString) !
const i = strbuilder.items.len;
strbuilder.items.len += trimmed.len;
std.mem.copyForwards(u8, strbuilder.items[i..], trimmed);
- try strbuilder.append('\n');
+ try strbuilder.append(alloc, '\n');
}
// Remove all trailing newlines
@@ -2317,7 +2321,7 @@ pub fn selectionString(self: *Screen, alloc: Allocator, opts: SelectionString) !
}
// Get our final string
- const string = try strbuilder.toOwnedSliceSentinel(0);
+ const string = try strbuilder.toOwnedSliceSentinel(alloc, 0);
errdefer alloc.free(string);
return string;
@@ -2902,7 +2906,7 @@ pub fn promptPath(
/// one byte at a time.
pub fn dumpString(
self: *const Screen,
- writer: anytype,
+ writer: *std.Io.Writer,
opts: PageList.EncodeUtf8Options,
) anyerror!void {
try self.pages.encodeUtf8(writer, opts);
@@ -2915,10 +2919,10 @@ pub fn dumpStringAlloc(
alloc: Allocator,
tl: point.Point,
) ![]const u8 {
- var builder = std.ArrayList(u8).init(alloc);
+ var builder: std.Io.Writer.Allocating = .init(alloc);
defer builder.deinit();
- try self.dumpString(builder.writer(), .{
+ try self.dumpString(&builder.writer, .{
.tl = self.pages.getTopLeft(tl),
.br = self.pages.getBottomRight(tl) orelse return error.UnknownPoint,
.unwrap = false,
@@ -2934,10 +2938,10 @@ pub fn dumpStringAllocUnwrapped(
alloc: Allocator,
tl: point.Point,
) ![]const u8 {
- var builder = std.ArrayList(u8).init(alloc);
+ var builder: std.Io.Writer.Allocating = .init(alloc);
defer builder.deinit();
- try self.dumpString(builder.writer(), .{
+ try self.dumpString(&builder.writer, .{
.tl = self.pages.getTopLeft(tl),
.br = self.pages.getBottomRight(tl) orelse return error.UnknownPoint,
.unwrap = true,
@@ -9030,33 +9034,33 @@ test "Screen UTF8 cell map with newlines" {
var cell_map = Page.CellMap.init(alloc);
defer cell_map.deinit();
- var builder = std.ArrayList(u8).init(alloc);
+ var builder: std.Io.Writer.Allocating = .init(alloc);
defer builder.deinit();
- try s.dumpString(builder.writer(), .{
+ try s.dumpString(&builder.writer, .{
.tl = s.pages.getTopLeft(.screen),
.br = s.pages.getBottomRight(.screen),
.cell_map = &cell_map,
});
- try testing.expectEqual(7, builder.items.len);
- try testing.expectEqualStrings("A\n\nB\n\nC", builder.items);
- try testing.expectEqual(builder.items.len, cell_map.items.len);
+ try testing.expectEqual(7, builder.written().len);
+ try testing.expectEqualStrings("A\n\nB\n\nC", builder.written());
+ try testing.expectEqual(builder.written().len, cell_map.map.items.len);
try testing.expectEqual(Page.CellMapEntry{
.x = 0,
.y = 0,
- }, cell_map.items[0]);
+ }, cell_map.map.items[0]);
try testing.expectEqual(Page.CellMapEntry{
.x = 1,
.y = 0,
- }, cell_map.items[1]);
+ }, cell_map.map.items[1]);
try testing.expectEqual(Page.CellMapEntry{
.x = 0,
.y = 1,
- }, cell_map.items[2]);
+ }, cell_map.map.items[2]);
try testing.expectEqual(Page.CellMapEntry{
.x = 0,
.y = 2,
- }, cell_map.items[3]);
+ }, cell_map.map.items[3]);
}
test "Screen UTF8 cell map with blank prefix" {
@@ -9068,32 +9072,32 @@ test "Screen UTF8 cell map with blank prefix" {
s.cursorAbsolute(2, 1);
try s.testWriteString("B");
- var cell_map = Page.CellMap.init(alloc);
+ var cell_map: Page.CellMap = .init(alloc);
defer cell_map.deinit();
- var builder = std.ArrayList(u8).init(alloc);
+ var builder: std.Io.Writer.Allocating = .init(alloc);
defer builder.deinit();
- try s.dumpString(builder.writer(), .{
+ try s.dumpString(&builder.writer, .{
.tl = s.pages.getTopLeft(.screen),
.br = s.pages.getBottomRight(.screen),
.cell_map = &cell_map,
});
- try testing.expectEqualStrings("\n B", builder.items);
- try testing.expectEqual(builder.items.len, cell_map.items.len);
+ try testing.expectEqualStrings("\n B", builder.written());
+ try testing.expectEqual(builder.written().len, cell_map.map.items.len);
try testing.expectEqual(Page.CellMapEntry{
.x = 0,
.y = 0,
- }, cell_map.items[0]);
+ }, cell_map.map.items[0]);
try testing.expectEqual(Page.CellMapEntry{
.x = 0,
.y = 1,
- }, cell_map.items[1]);
+ }, cell_map.map.items[1]);
try testing.expectEqual(Page.CellMapEntry{
.x = 1,
.y = 1,
- }, cell_map.items[2]);
+ }, cell_map.map.items[2]);
try testing.expectEqual(Page.CellMapEntry{
.x = 2,
.y = 1,
- }, cell_map.items[3]);
+ }, cell_map.map.items[3]);
}
diff --git a/src/terminal/Terminal.zig b/src/terminal/Terminal.zig
index 9857d4798..69bcbcb84 100644
--- a/src/terminal/Terminal.zig
+++ b/src/terminal/Terminal.zig
@@ -223,7 +223,7 @@ pub fn init(
.left = 0,
.right = cols - 1,
},
- .pwd = std.ArrayList(u8).init(alloc),
+ .pwd = .empty,
.modes = .{
.values = opts.default_modes,
.default = opts.default_modes,
@@ -235,10 +235,15 @@ pub fn deinit(self: *Terminal, alloc: Allocator) void {
self.tabstops.deinit(alloc);
self.screen.deinit();
self.secondary_screen.deinit();
- self.pwd.deinit();
+ self.pwd.deinit(alloc);
self.* = undefined;
}
+/// The general allocator we should use for this terminal.
+fn gpa(self: *Terminal) Allocator {
+ return self.screen.alloc;
+}
+
/// Print UTF-8 encoded string to the terminal.
pub fn printString(self: *Terminal, str: []const u8) !void {
const view = try std.unicode.Utf8View.init(str);
@@ -2531,7 +2536,7 @@ pub fn resize(
/// Set the pwd for the terminal.
pub fn setPwd(self: *Terminal, pwd: []const u8) !void {
self.pwd.clearRetainingCapacity();
- try self.pwd.appendSlice(pwd);
+ try self.pwd.appendSlice(self.gpa(), pwd);
}
/// Returns the pwd for the terminal, if any. The memory is owned by the
diff --git a/src/terminal/apc.zig b/src/terminal/apc.zig
index a168da4a1..704c3fbe3 100644
--- a/src/terminal/apc.zig
+++ b/src/terminal/apc.zig
@@ -65,7 +65,9 @@ pub const Handler = struct {
.kitty => |*p| kitty: {
if (comptime !build_options.kitty_graphics) unreachable;
- const command = p.complete() catch |err| {
+ // Use the same allocator that was used to create the parser.
+ const alloc = p.arena.child_allocator;
+ const command = p.complete(alloc) catch |err| {
log.warn("kitty graphics protocol error: {}", .{err});
break :kitty null;
};
diff --git a/src/terminal/bitmap_allocator.zig b/src/terminal/bitmap_allocator.zig
index 724c71be5..894172b4c 100644
--- a/src/terminal/bitmap_allocator.zig
+++ b/src/terminal/bitmap_allocator.zig
@@ -34,7 +34,7 @@ pub fn BitmapAllocator(comptime chunk_size: comptime_int) type {
assert(std.math.isPowerOfTwo(chunk_size));
}
- pub const base_align = @alignOf(u64);
+ pub const base_align: std.mem.Alignment = .fromByteUnits(@alignOf(u64));
pub const bitmap_bit_size = @bitSizeOf(u64);
/// The bitmap of available chunks. Each bit represents a chunk. A
@@ -49,7 +49,7 @@ pub fn BitmapAllocator(comptime chunk_size: comptime_int) type {
/// Initialize the allocator map with a given buf and memory layout.
pub fn init(buf: OffsetBuf, l: Layout) Self {
- assert(@intFromPtr(buf.start()) % base_align == 0);
+ assert(base_align.check(@intFromPtr(buf.start())));
// Initialize our bitmaps to all 1s to note that all chunks are free.
const bitmap = buf.member(u64, l.bitmap_start);
@@ -92,7 +92,7 @@ pub fn BitmapAllocator(comptime chunk_size: comptime_int) type {
return error.OutOfMemory;
const chunks = self.chunks.ptr(base);
- const ptr: [*]T = @alignCast(@ptrCast(&chunks[idx * chunk_size]));
+ const ptr: [*]T = @ptrCast(@alignCast(&chunks[idx * chunk_size]));
return ptr[0..n];
}
diff --git a/src/terminal/dcs.zig b/src/terminal/dcs.zig
index e4d0f3de2..971ea13a0 100644
--- a/src/terminal/dcs.zig
+++ b/src/terminal/dcs.zig
@@ -64,7 +64,7 @@ pub const Handler = struct {
.state = .{
.tmux = .{
.max_bytes = self.max_bytes,
- .buffer = try std.ArrayList(u8).initCapacity(
+ .buffer = try .initCapacity(
alloc,
128, // Arbitrary choice to limit initial reallocs
),
@@ -83,7 +83,7 @@ pub const Handler = struct {
// https://github.com/mitchellh/ghostty/issues/517
'q' => .{
.state = .{
- .xtgettcap = try std.ArrayList(u8).initCapacity(
+ .xtgettcap = try .initCapacity(
alloc,
128, // Arbitrary choice
),
@@ -134,11 +134,11 @@ pub const Handler = struct {
} else unreachable,
.xtgettcap => |*list| {
- if (list.items.len >= self.max_bytes) {
+ if (list.written().len >= self.max_bytes) {
return error.OutOfMemory;
}
- try list.append(byte);
+ try list.writer.writeByte(byte);
},
.decrqss => |*buffer| {
@@ -170,11 +170,12 @@ pub const Handler = struct {
break :tmux .{ .tmux = .{ .exit = {} } };
} else unreachable,
- .xtgettcap => |list| xtgettcap: {
- for (list.items, 0..) |b, i| {
- list.items[i] = std.ascii.toUpper(b);
- }
- break :xtgettcap .{ .xtgettcap = .{ .data = list } };
+ .xtgettcap => |*list| xtgettcap: {
+ // Note: purposely do not deinit our state here because
+ // we copy it into the resulting command.
+ const items = list.written();
+ for (items, 0..) |b, i| items[i] = std.ascii.toUpper(b);
+ break :xtgettcap .{ .xtgettcap = .{ .data = list.* } };
},
.decrqss => |buffer| .{ .decrqss = switch (buffer.len) {
@@ -216,8 +217,8 @@ pub const Command = union(enum) {
else
void,
- pub fn deinit(self: Command) void {
- switch (self) {
+ pub fn deinit(self: *Command) void {
+ switch (self.*) {
.xtgettcap => |*v| v.data.deinit(),
.decrqss => {},
.tmux => {},
@@ -225,16 +226,16 @@ pub const Command = union(enum) {
}
pub const XTGETTCAP = struct {
- data: std.ArrayList(u8),
+ data: std.Io.Writer.Allocating,
i: usize = 0,
/// Returns the next terminfo key being requested and null
/// when there are no more keys. The returned value is NOT hex-decoded
/// because we expect to use a comptime lookup table.
pub fn next(self: *XTGETTCAP) ?[]const u8 {
- if (self.i >= self.data.items.len) return null;
-
- var rem = self.data.items[self.i..];
+ const items = self.data.written();
+ if (self.i >= items.len) return null;
+ var rem = items[self.i..];
const idx = std.mem.indexOf(u8, rem, ";") orelse rem.len;
// Note that if we're at the end, idx + 1 is len + 1 so we're over
@@ -271,7 +272,7 @@ const State = union(enum) {
ignore: void,
/// XTGETTCAP
- xtgettcap: std.ArrayList(u8),
+ xtgettcap: std.Io.Writer.Allocating,
/// DECRQSS
decrqss: struct {
diff --git a/src/terminal/hash_map.zig b/src/terminal/hash_map.zig
index 9a16be3b2..23b10950e 100644
--- a/src/terminal/hash_map.zig
+++ b/src/terminal/hash_map.zig
@@ -88,7 +88,7 @@ pub fn OffsetHashMap(
/// Initialize a new HashMap with the given capacity and backing
/// memory. The backing memory must be aligned to base_align.
pub fn init(buf: OffsetBuf, l: Layout) Self {
- assert(@intFromPtr(buf.start()) % base_align == 0);
+ assert(base_align.check(@intFromPtr(buf.start())));
const m = Unmanaged.init(buf, l);
return .{ .metadata = getOffset(
@@ -124,7 +124,11 @@ fn HashMapUnmanaged(
const header_align = @alignOf(Header);
const key_align = if (@sizeOf(K) == 0) 1 else @alignOf(K);
const val_align = if (@sizeOf(V) == 0) 1 else @alignOf(V);
- const base_align = @max(header_align, key_align, val_align);
+ const base_align: mem.Alignment = .fromByteUnits(@max(
+ header_align,
+ key_align,
+ val_align,
+ ));
// This is actually a midway pointer to the single buffer containing
// a `Header` field, the `Metadata`s and `Entry`s.
@@ -287,7 +291,7 @@ fn HashMapUnmanaged(
/// Initialize a hash map with a given capacity and a buffer. The
/// buffer must fit within the size defined by `layoutForCapacity`.
pub fn init(buf: OffsetBuf, layout: Layout) Self {
- assert(@intFromPtr(buf.start()) % base_align == 0);
+ assert(base_align.check(@intFromPtr(buf.start())));
// Get all our main pointers
const metadata_buf = buf.rebase(@sizeOf(Header));
@@ -862,7 +866,11 @@ fn HashMapUnmanaged(
// Our total memory size required is the end of our values
// aligned to the base required alignment.
- const total_size = std.mem.alignForward(usize, vals_end, base_align);
+ const total_size = std.mem.alignForward(
+ usize,
+ vals_end,
+ base_align.toByteUnits(),
+ );
// The offsets we actually store in the map are from the
// metadata pointer so that we can use self.metadata as
@@ -1126,15 +1134,15 @@ test "HashMap put and remove loop in random order" {
defer alloc.free(buf);
var map = Map.init(.init(buf), layout);
- var keys = std.ArrayList(u32).init(alloc);
- defer keys.deinit();
+ var keys: std.ArrayList(u32) = .empty;
+ defer keys.deinit(alloc);
const size = 32;
const iterations = 100;
var i: u32 = 0;
while (i < size) : (i += 1) {
- try keys.append(i);
+ try keys.append(alloc, i);
}
var prng = std.Random.DefaultPrng.init(0);
const random = prng.random();
diff --git a/src/terminal/kitty/color.zig b/src/terminal/kitty/color.zig
index b23e30ad8..099002f39 100644
--- a/src/terminal/kitty/color.zig
+++ b/src/terminal/kitty/color.zig
@@ -42,13 +42,8 @@ pub const Kind = union(enum) {
pub fn format(
self: Kind,
- comptime layout: []const u8,
- opts: std.fmt.FormatOptions,
- writer: anytype,
+ writer: *std.Io.Writer,
) !void {
- _ = layout;
- _ = opts;
-
switch (self) {
.palette => |p| try writer.print("{d}", .{p}),
.special => |s| try writer.print("{s}", .{@tagName(s)}),
@@ -61,11 +56,11 @@ test "OSC: kitty color protocol kind string" {
var buf: [256]u8 = undefined;
{
- const actual = try std.fmt.bufPrint(&buf, "{}", .{Kind{ .special = .foreground }});
+ const actual = try std.fmt.bufPrint(&buf, "{f}", .{Kind{ .special = .foreground }});
try testing.expectEqualStrings("foreground", actual);
}
{
- const actual = try std.fmt.bufPrint(&buf, "{}", .{Kind{ .palette = 42 }});
+ const actual = try std.fmt.bufPrint(&buf, "{f}", .{Kind{ .palette = 42 }});
try testing.expectEqualStrings("42", actual);
}
}
diff --git a/src/terminal/kitty/graphics_command.zig b/src/terminal/kitty/graphics_command.zig
index dcb4850c9..99a7cdaac 100644
--- a/src/terminal/kitty/graphics_command.zig
+++ b/src/terminal/kitty/graphics_command.zig
@@ -59,7 +59,7 @@ pub const Parser = struct {
errdefer arena.deinit();
var result: Parser = .{
.arena = arena,
- .data = std.ArrayList(u8).init(alloc),
+ .data = .empty,
.kv = .{},
.kv_temp_len = 0,
.kv_current = 0,
@@ -77,8 +77,8 @@ pub const Parser = struct {
pub fn deinit(self: *Parser) void {
// We don't free the hash map because its in the arena
+ self.data.deinit(self.arena.child_allocator);
self.arena.deinit();
- self.data.deinit();
}
/// Parse a complete command string.
@@ -86,7 +86,7 @@ pub const Parser = struct {
var parser = init(alloc);
defer parser.deinit();
for (data) |c| try parser.feed(c);
- return try parser.complete();
+ return try parser.complete(alloc);
}
/// Feed a single byte to the parser.
@@ -136,7 +136,7 @@ pub const Parser = struct {
else => {},
},
- .data => try self.data.append(c),
+ .data => try self.data.append(self.arena.child_allocator, c),
}
}
@@ -145,7 +145,7 @@ pub const Parser = struct {
///
/// The allocator given will be used for the long-lived data
/// of the final command.
- pub fn complete(self: *Parser) !Command {
+ pub fn complete(self: *Parser, alloc: Allocator) !Command {
switch (self.state) {
// We can't ever end in the control key state and be valid.
// This means the command looked something like "a=1,b"
@@ -194,14 +194,14 @@ pub const Parser = struct {
return .{
.control = control,
.quiet = quiet,
- .data = try self.decodeData(),
+ .data = try self.decodeData(alloc),
};
}
/// Decodes the payload data from base64 and returns it as a slice.
/// This function will destroy the contents of self.data, it should
/// only be used once we are done collecting payload bytes.
- fn decodeData(self: *Parser) ![]const u8 {
+ fn decodeData(self: *Parser, alloc: Allocator) ![]const u8 {
if (self.data.items.len == 0) {
return "";
}
@@ -225,7 +225,7 @@ pub const Parser = struct {
// Remove the extra bytes.
self.data.items.len = decoded.len;
- return try self.data.toOwnedSlice();
+ return try self.data.toOwnedSlice(alloc);
}
fn accumulateValue(self: *Parser, c: u8, overflow_state: State) !void {
@@ -276,7 +276,7 @@ pub const Response = struct {
placement_id: u32 = 0,
message: []const u8 = "OK",
- pub fn encode(self: Response, writer: anytype) !void {
+ pub fn encode(self: Response, writer: *std.Io.Writer) !void {
// We only encode a result if we have either an id or an image number.
if (self.id == 0 and self.image_number == 0) return;
@@ -969,7 +969,7 @@ test "transmission command" {
const input = "f=24,s=10,v=20";
for (input) |c| try p.feed(c);
- const command = try p.complete();
+ const command = try p.complete(alloc);
defer command.deinit(alloc);
try testing.expect(command.control == .transmit);
@@ -987,7 +987,7 @@ test "transmission ignores 'm' if medium is not direct" {
const input = "a=t,t=t,m=1";
for (input) |c| try p.feed(c);
- const command = try p.complete();
+ const command = try p.complete(alloc);
defer command.deinit(alloc);
try testing.expect(command.control == .transmit);
@@ -1004,7 +1004,7 @@ test "transmission respects 'm' if medium is direct" {
const input = "a=t,t=d,m=1";
for (input) |c| try p.feed(c);
- const command = try p.complete();
+ const command = try p.complete(alloc);
defer command.deinit(alloc);
try testing.expect(command.control == .transmit);
@@ -1021,7 +1021,7 @@ test "query command" {
const input = "i=31,s=1,v=1,a=q,t=d,f=24;QUFBQQ";
for (input) |c| try p.feed(c);
- const command = try p.complete();
+ const command = try p.complete(alloc);
defer command.deinit(alloc);
try testing.expect(command.control == .query);
@@ -1041,7 +1041,7 @@ test "display command" {
const input = "a=p,U=1,i=31,c=80,r=120";
for (input) |c| try p.feed(c);
- const command = try p.complete();
+ const command = try p.complete(alloc);
defer command.deinit(alloc);
try testing.expect(command.control == .display);
@@ -1059,7 +1059,7 @@ test "delete command" {
const input = "a=d,d=p,x=3,y=4";
for (input) |c| try p.feed(c);
- const command = try p.complete();
+ const command = try p.complete(alloc);
defer command.deinit(alloc);
try testing.expect(command.control == .delete);
@@ -1079,7 +1079,7 @@ test "no control data" {
const input = ";QUFBQQ";
for (input) |c| try p.feed(c);
- const command = try p.complete();
+ const command = try p.complete(alloc);
defer command.deinit(alloc);
try testing.expect(command.control == .transmit);
@@ -1094,7 +1094,7 @@ test "ignore unknown keys (long)" {
const input = "f=24,s=10,v=20,hello=world";
for (input) |c| try p.feed(c);
- const command = try p.complete();
+ const command = try p.complete(alloc);
defer command.deinit(alloc);
try testing.expect(command.control == .transmit);
@@ -1112,7 +1112,7 @@ test "ignore very long values" {
const input = "f=24,s=10,v=2000000000000000000000000000000000000000";
for (input) |c| try p.feed(c);
- const command = try p.complete();
+ const command = try p.complete(alloc);
defer command.deinit(alloc);
try testing.expect(command.control == .transmit);
@@ -1130,7 +1130,7 @@ test "ensure very large negative values don't get skipped" {
const input = "a=p,i=1,z=-2000000000";
for (input) |c| try p.feed(c);
- const command = try p.complete();
+ const command = try p.complete(alloc);
defer command.deinit(alloc);
try testing.expect(command.control == .display);
@@ -1147,7 +1147,7 @@ test "ensure proper overflow error for u32" {
const input = "a=p,i=10000000000";
for (input) |c| try p.feed(c);
- try testing.expectError(error.Overflow, p.complete());
+ try testing.expectError(error.Overflow, p.complete(alloc));
}
test "ensure proper overflow error for i32" {
@@ -1158,7 +1158,7 @@ test "ensure proper overflow error for i32" {
const input = "a=p,i=1,z=-9999999999";
for (input) |c| try p.feed(c);
- try testing.expectError(error.Overflow, p.complete());
+ try testing.expectError(error.Overflow, p.complete(alloc));
}
test "all i32 values" {
@@ -1171,7 +1171,7 @@ test "all i32 values" {
defer p.deinit();
const input = "a=p,i=1,z=-1";
for (input) |c| try p.feed(c);
- const command = try p.complete();
+ const command = try p.complete(alloc);
defer command.deinit(alloc);
try testing.expect(command.control == .display);
@@ -1186,7 +1186,7 @@ test "all i32 values" {
defer p.deinit();
const input = "a=p,i=1,H=-1";
for (input) |c| try p.feed(c);
- const command = try p.complete();
+ const command = try p.complete(alloc);
defer command.deinit(alloc);
try testing.expect(command.control == .display);
@@ -1201,7 +1201,7 @@ test "all i32 values" {
defer p.deinit();
const input = "a=p,i=1,V=-1";
for (input) |c| try p.feed(c);
- const command = try p.complete();
+ const command = try p.complete(alloc);
defer command.deinit(alloc);
try testing.expect(command.control == .display);
@@ -1214,41 +1214,41 @@ test "all i32 values" {
test "response: encode nothing without ID or image number" {
const testing = std.testing;
var buf: [1024]u8 = undefined;
- var fbs = std.io.fixedBufferStream(&buf);
+ var writer: std.Io.Writer = .fixed(&buf);
var r: Response = .{};
- try r.encode(fbs.writer());
- try testing.expectEqualStrings("", fbs.getWritten());
+ try r.encode(&writer);
+ try testing.expectEqualStrings("", writer.buffered());
}
test "response: encode with only image id" {
const testing = std.testing;
var buf: [1024]u8 = undefined;
- var fbs = std.io.fixedBufferStream(&buf);
+ var writer: std.Io.Writer = .fixed(&buf);
var r: Response = .{ .id = 4 };
- try r.encode(fbs.writer());
- try testing.expectEqualStrings("\x1b_Gi=4;OK\x1b\\", fbs.getWritten());
+ try r.encode(&writer);
+ try testing.expectEqualStrings("\x1b_Gi=4;OK\x1b\\", writer.buffered());
}
test "response: encode with only image number" {
const testing = std.testing;
var buf: [1024]u8 = undefined;
- var fbs = std.io.fixedBufferStream(&buf);
+ var writer: std.Io.Writer = .fixed(&buf);
var r: Response = .{ .image_number = 4 };
- try r.encode(fbs.writer());
- try testing.expectEqualStrings("\x1b_GI=4;OK\x1b\\", fbs.getWritten());
+ try r.encode(&writer);
+ try testing.expectEqualStrings("\x1b_GI=4;OK\x1b\\", writer.buffered());
}
test "response: encode with image ID and number" {
const testing = std.testing;
var buf: [1024]u8 = undefined;
- var fbs = std.io.fixedBufferStream(&buf);
+ var writer: std.Io.Writer = .fixed(&buf);
var r: Response = .{ .id = 12, .image_number = 4 };
- try r.encode(fbs.writer());
- try testing.expectEqualStrings("\x1b_Gi=12,I=4;OK\x1b\\", fbs.getWritten());
+ try r.encode(&writer);
+ try testing.expectEqualStrings("\x1b_Gi=12,I=4;OK\x1b\\", writer.buffered());
}
test "delete range command 1" {
@@ -1259,7 +1259,7 @@ test "delete range command 1" {
const input = "a=d,d=r,x=3,y=4";
for (input) |c| try p.feed(c);
- const command = try p.complete();
+ const command = try p.complete(alloc);
defer command.deinit(alloc);
try testing.expect(command.control == .delete);
@@ -1279,7 +1279,7 @@ test "delete range command 2" {
const input = "a=d,d=R,x=5,y=11";
for (input) |c| try p.feed(c);
- const command = try p.complete();
+ const command = try p.complete(alloc);
defer command.deinit(alloc);
try testing.expect(command.control == .delete);
@@ -1299,7 +1299,7 @@ test "delete range command 3" {
const input = "a=d,d=R,x=5,y=4";
for (input) |c| try p.feed(c);
- try testing.expectError(error.InvalidFormat, p.complete());
+ try testing.expectError(error.InvalidFormat, p.complete(alloc));
}
test "delete range command 4" {
@@ -1310,7 +1310,7 @@ test "delete range command 4" {
const input = "a=d,d=R,x=5";
for (input) |c| try p.feed(c);
- try testing.expectError(error.InvalidFormat, p.complete());
+ try testing.expectError(error.InvalidFormat, p.complete(alloc));
}
test "delete range command 5" {
@@ -1321,5 +1321,5 @@ test "delete range command 5" {
const input = "a=d,d=R,y=5";
for (input) |c| try p.feed(c);
- try testing.expectError(error.InvalidFormat, p.complete());
+ try testing.expectError(error.InvalidFormat, p.complete(alloc));
}
diff --git a/src/terminal/kitty/graphics_image.zig b/src/terminal/kitty/graphics_image.zig
index f32b70be2..268f71601 100644
--- a/src/terminal/kitty/graphics_image.zig
+++ b/src/terminal/kitty/graphics_image.zig
@@ -259,15 +259,16 @@ pub const LoadingImage = struct {
};
}
- var buf_reader = std.io.bufferedReader(file.reader());
- const reader = buf_reader.reader();
+ var buf: [4096]u8 = undefined;
+ var buf_reader = file.reader(&buf);
+ const reader = &buf_reader.interface;
// Read the file
- var managed = std.ArrayList(u8).init(alloc);
- errdefer managed.deinit();
+ var managed: std.ArrayList(u8) = .empty;
+ errdefer managed.deinit(alloc);
const size: usize = if (t.size > 0) @min(t.size, max_size) else max_size;
- reader.readAllArrayList(&managed, size) catch |err| {
- log.warn("failed to read temporary file: {}", .{err});
+ reader.appendRemaining(alloc, &managed, .limited(size)) catch {
+ log.warn("failed to read temporary file: {?}", .{buf_reader.err});
return error.InvalidData;
};
@@ -402,14 +403,15 @@ pub const LoadingImage = struct {
fn decompressZlib(self: *LoadingImage, alloc: Allocator) !void {
// Open our zlib stream
- var fbs = std.io.fixedBufferStream(self.data.items);
- var stream = std.compress.zlib.decompressor(fbs.reader());
+ var buf: [std.compress.flate.max_window_len]u8 = undefined;
+ var reader: std.Io.Reader = .fixed(self.data.items);
+ var stream: std.compress.flate.Decompress = .init(&reader, .zlib, &buf);
// Write it to an array list
- var list = std.ArrayList(u8).init(alloc);
- errdefer list.deinit();
- stream.reader().readAllArrayList(&list, max_size) catch |err| {
- log.warn("failed to read decompressed data: {}", .{err});
+ var list: std.ArrayList(u8) = .empty;
+ errdefer list.deinit(alloc);
+ stream.reader.appendRemaining(alloc, &list, .limited(max_size)) catch {
+ log.warn("failed to read decompressed data: {?}", .{stream.err});
return error.DecompressionFailed;
};
diff --git a/src/terminal/kitty/graphics_storage.zig b/src/terminal/kitty/graphics_storage.zig
index 0c3022e4a..8aef0ece5 100644
--- a/src/terminal/kitty/graphics_storage.zig
+++ b/src/terminal/kitty/graphics_storage.zig
@@ -526,8 +526,8 @@ pub const ImageStorage = struct {
used: bool,
};
- var candidates = std.ArrayList(Candidate).init(alloc);
- defer candidates.deinit();
+ var candidates: std.ArrayList(Candidate) = .empty;
+ defer candidates.deinit(alloc);
var it = self.images.iterator();
while (it.next()) |kv| {
@@ -548,7 +548,7 @@ pub const ImageStorage = struct {
break :used false;
};
- try candidates.append(.{
+ try candidates.append(alloc, .{
.id = img.id,
.time = img.transmit_time,
.used = used,
diff --git a/src/terminal/osc.zig b/src/terminal/osc.zig
index 800257c3d..897a5ef0f 100644
--- a/src/terminal/osc.zig
+++ b/src/terminal/osc.zig
@@ -274,7 +274,7 @@ pub const Terminator = enum {
self: Terminator,
comptime _: []const u8,
_: std.fmt.FormatOptions,
- writer: anytype,
+ writer: *std.Io.Writer,
) !void {
try writer.writeAll(self.string());
}
@@ -475,7 +475,7 @@ pub const Parser = struct {
// Some commands have their own memory management we need to clear.
switch (self.command) {
- .kitty_color_protocol => |*v| v.list.deinit(),
+ .kitty_color_protocol => |*v| v.list.deinit(self.alloc.?),
.color_operation => |*v| v.requests.deinit(self.alloc.?),
else => {},
}
@@ -821,15 +821,15 @@ pub const Parser = struct {
.@"21" => switch (c) {
';' => kitty: {
- const alloc = self.alloc orelse {
+ if (self.alloc == null) {
log.info("OSC 21 requires an allocator, but none was provided", .{});
self.state = .invalid;
break :kitty;
- };
+ }
self.command = .{
.kitty_color_protocol = .{
- .list = std.ArrayList(kitty_color.OSC.Request).init(alloc),
+ .list = .empty,
},
};
@@ -1553,18 +1553,22 @@ pub const Parser = struct {
return;
}
+ // Asserted when the command is set to kitty_color_protocol
+ // that we have an allocator.
+ const alloc = self.alloc.?;
+
if (kind == .key_only or value.len == 0) {
- v.list.append(.{ .reset = key }) catch |err| {
+ v.list.append(alloc, .{ .reset = key }) catch |err| {
log.warn("unable to append kitty color protocol option: {}", .{err});
return;
};
} else if (mem.eql(u8, "?", value)) {
- v.list.append(.{ .query = key }) catch |err| {
+ v.list.append(alloc, .{ .query = key }) catch |err| {
log.warn("unable to append kitty color protocol option: {}", .{err});
return;
};
} else {
- v.list.append(.{
+ v.list.append(alloc, .{
.set = .{
.key = key,
.color = RGB.parse(value) catch |err| switch (err) {
diff --git a/src/terminal/page.zig b/src/terminal/page.zig
index b2fe993d2..331168a27 100644
--- a/src/terminal/page.zig
+++ b/src/terminal/page.zig
@@ -86,7 +86,7 @@ pub const Page = struct {
assert(std.heap.page_size_min % @max(
@alignOf(Row),
@alignOf(Cell),
- style.Set.base_align,
+ style.Set.base_align.toByteUnits(),
) == 0);
}
@@ -1528,7 +1528,21 @@ pub const Page = struct {
};
/// See cell_map
- pub const CellMap = std.ArrayList(CellMapEntry);
+ pub const CellMap = struct {
+ alloc: Allocator,
+ map: std.ArrayList(CellMapEntry),
+
+ pub fn init(alloc: Allocator) CellMap {
+ return .{
+ .alloc = alloc,
+ .map = .empty,
+ };
+ }
+
+ pub fn deinit(self: *CellMap) void {
+ self.map.deinit(self.alloc);
+ }
+ };
/// The x/y coordinate of a single cell in the cell map.
pub const CellMapEntry = struct {
@@ -1547,7 +1561,7 @@ pub const Page = struct {
/// it makes it easier to test input contents.
pub fn encodeUtf8(
self: *const Page,
- writer: anytype,
+ writer: *std.Io.Writer,
opts: EncodeUtf8Options,
) anyerror!EncodeUtf8Options.TrailingUtf8State {
var blank_rows: usize = opts.preceding.rows;
@@ -1583,7 +1597,7 @@ pub const Page = struct {
// This is tested in Screen.zig, i.e. one test is
// "cell map with newlines"
if (opts.cell_map) |cell_map| {
- try cell_map.append(.{
+ try cell_map.map.append(cell_map.alloc, .{
.x = last_x,
.y = @intCast(y - blank_rows + i - 1),
});
@@ -1618,9 +1632,9 @@ pub const Page = struct {
continue;
}
if (blank_cells > 0) {
- try writer.writeByteNTimes(' ', blank_cells);
+ try writer.splatByteAll(' ', blank_cells);
if (opts.cell_map) |cell_map| {
- for (0..blank_cells) |i| try cell_map.append(.{
+ for (0..blank_cells) |i| try cell_map.map.append(cell_map.alloc, .{
.x = @intCast(x - blank_cells + i),
.y = y,
});
@@ -1634,7 +1648,7 @@ pub const Page = struct {
try writer.print("{u}", .{cell.content.codepoint});
if (opts.cell_map) |cell_map| {
last_x = x + 1;
- try cell_map.append(.{
+ try cell_map.map.append(cell_map.alloc, .{
.x = x,
.y = y,
});
@@ -1645,7 +1659,7 @@ pub const Page = struct {
try writer.print("{u}", .{cell.content.codepoint});
if (opts.cell_map) |cell_map| {
last_x = x + 1;
- try cell_map.append(.{
+ try cell_map.map.append(cell_map.alloc, .{
.x = x,
.y = y,
});
@@ -1653,7 +1667,7 @@ pub const Page = struct {
for (self.lookupGrapheme(cell).?) |cp| {
try writer.print("{u}", .{cp});
- if (opts.cell_map) |cell_map| try cell_map.append(.{
+ if (opts.cell_map) |cell_map| try cell_map.map.append(cell_map.alloc, .{
.x = x,
.y = y,
});
@@ -1743,25 +1757,25 @@ pub const Page = struct {
const dirty_end: usize = dirty_start + (dirty_usize_length * @sizeOf(usize));
const styles_layout: style.Set.Layout = .init(cap.styles);
- const styles_start = alignForward(usize, dirty_end, style.Set.base_align);
+ const styles_start = alignForward(usize, dirty_end, style.Set.base_align.toByteUnits());
const styles_end = styles_start + styles_layout.total_size;
const grapheme_alloc_layout = GraphemeAlloc.layout(cap.grapheme_bytes);
- const grapheme_alloc_start = alignForward(usize, styles_end, GraphemeAlloc.base_align);
+ const grapheme_alloc_start = alignForward(usize, styles_end, GraphemeAlloc.base_align.toByteUnits());
const grapheme_alloc_end = grapheme_alloc_start + grapheme_alloc_layout.total_size;
const grapheme_count = @divFloor(cap.grapheme_bytes, grapheme_chunk);
const grapheme_map_layout = GraphemeMap.layout(@intCast(grapheme_count));
- const grapheme_map_start = alignForward(usize, grapheme_alloc_end, GraphemeMap.base_align);
+ const grapheme_map_start = alignForward(usize, grapheme_alloc_end, GraphemeMap.base_align.toByteUnits());
const grapheme_map_end = grapheme_map_start + grapheme_map_layout.total_size;
const string_layout = StringAlloc.layout(cap.string_bytes);
- const string_start = alignForward(usize, grapheme_map_end, StringAlloc.base_align);
+ const string_start = alignForward(usize, grapheme_map_end, StringAlloc.base_align.toByteUnits());
const string_end = string_start + string_layout.total_size;
const hyperlink_count = @divFloor(cap.hyperlink_bytes, @sizeOf(hyperlink.Set.Item));
const hyperlink_set_layout: hyperlink.Set.Layout = .init(@intCast(hyperlink_count));
- const hyperlink_set_start = alignForward(usize, string_end, hyperlink.Set.base_align);
+ const hyperlink_set_start = alignForward(usize, string_end, hyperlink.Set.base_align.toByteUnits());
const hyperlink_set_end = hyperlink_set_start + hyperlink_set_layout.total_size;
const hyperlink_map_count: u32 = count: {
@@ -1773,7 +1787,7 @@ pub const Page = struct {
break :count std.math.ceilPowerOfTwoAssert(u32, mult);
};
const hyperlink_map_layout = hyperlink.Map.layout(hyperlink_map_count);
- const hyperlink_map_start = alignForward(usize, hyperlink_set_end, hyperlink.Map.base_align);
+ const hyperlink_map_start = alignForward(usize, hyperlink_set_end, hyperlink.Map.base_align.toByteUnits());
const hyperlink_map_end = hyperlink_map_start + hyperlink_map_layout.total_size;
const total_size = alignForward(usize, hyperlink_map_end, std.heap.page_size_min);
@@ -1867,12 +1881,12 @@ pub const Capacity = struct {
// for rows & cells (which will allow us to calculate the number of
// rows we can fit at a certain column width) we need to layout the
// "meta" members of the page (i.e. everything else) from the end.
- const hyperlink_map_start = alignBackward(usize, layout.total_size - layout.hyperlink_map_layout.total_size, hyperlink.Map.base_align);
- const hyperlink_set_start = alignBackward(usize, hyperlink_map_start - layout.hyperlink_set_layout.total_size, hyperlink.Set.base_align);
- const string_alloc_start = alignBackward(usize, hyperlink_set_start - layout.string_alloc_layout.total_size, StringAlloc.base_align);
- const grapheme_map_start = alignBackward(usize, string_alloc_start - layout.grapheme_map_layout.total_size, GraphemeMap.base_align);
- const grapheme_alloc_start = alignBackward(usize, grapheme_map_start - layout.grapheme_alloc_layout.total_size, GraphemeAlloc.base_align);
- const styles_start = alignBackward(usize, grapheme_alloc_start - layout.styles_layout.total_size, style.Set.base_align);
+ const hyperlink_map_start = alignBackward(usize, layout.total_size - layout.hyperlink_map_layout.total_size, hyperlink.Map.base_align.toByteUnits());
+ const hyperlink_set_start = alignBackward(usize, hyperlink_map_start - layout.hyperlink_set_layout.total_size, hyperlink.Set.base_align.toByteUnits());
+ const string_alloc_start = alignBackward(usize, hyperlink_set_start - layout.string_alloc_layout.total_size, StringAlloc.base_align.toByteUnits());
+ const grapheme_map_start = alignBackward(usize, string_alloc_start - layout.grapheme_map_layout.total_size, GraphemeMap.base_align.toByteUnits());
+ const grapheme_alloc_start = alignBackward(usize, grapheme_map_start - layout.grapheme_alloc_layout.total_size, GraphemeAlloc.base_align.toByteUnits());
+ const styles_start = alignBackward(usize, grapheme_alloc_start - layout.styles_layout.total_size, style.Set.base_align.toByteUnits());
// The size per row is:
// - The row metadata itself
diff --git a/src/terminal/ref_counted_set.zig b/src/terminal/ref_counted_set.zig
index 153e331a6..e07de4e97 100644
--- a/src/terminal/ref_counted_set.zig
+++ b/src/terminal/ref_counted_set.zig
@@ -59,12 +59,12 @@ pub fn RefCountedSet(
return struct {
const Self = @This();
- pub const base_align = @max(
+ pub const base_align: std.mem.Alignment = .fromByteUnits(@max(
@alignOf(Context),
@alignOf(Layout),
@alignOf(Item),
@alignOf(Id),
- );
+ ));
/// Set item
pub const Item = struct {
diff --git a/src/terminal/search.zig b/src/terminal/search.zig
index b3c6494a3..d9f6c5663 100644
--- a/src/terminal/search.zig
+++ b/src/terminal/search.zig
@@ -55,7 +55,7 @@ pub const PageListSearch = struct {
needle: []const u8,
) Allocator.Error!PageListSearch {
var window = try SlidingWindow.init(alloc, needle);
- errdefer window.deinit(alloc);
+ errdefer window.deinit();
return .{
.list = list,
@@ -63,16 +63,13 @@ pub const PageListSearch = struct {
};
}
- pub fn deinit(self: *PageListSearch, alloc: Allocator) void {
- self.window.deinit(alloc);
+ pub fn deinit(self: *PageListSearch) void {
+ self.window.deinit();
}
/// Find the next match for the needle in the pagelist. This returns
/// null when there are no more matches.
- pub fn next(
- self: *PageListSearch,
- alloc: Allocator,
- ) Allocator.Error!?Selection {
+ pub fn next(self: *PageListSearch) Allocator.Error!?Selection {
// Try to search for the needle in the window. If we find a match
// then we can return that and we're done.
if (self.window.next()) |sel| return sel;
@@ -89,7 +86,7 @@ pub const PageListSearch = struct {
// until we find a match or we reach the end of the pagelist.
// This append then next pattern limits memory usage of the window.
while (node_) |node| : (node_ = node.next) {
- try self.window.append(alloc, node);
+ try self.window.append(node);
if (self.window.next()) |sel| return sel;
}
@@ -115,6 +112,14 @@ pub const PageListSearch = struct {
/// and repeat the process. This will always maintain the minimum
/// required memory to search for the needle.
const SlidingWindow = struct {
+ /// The allocator to use for all the data within this window. We
+ /// store this rather than passing it around because its already
+ /// part of multiple elements (eg. Meta's CellMap) and we want to
+ /// ensure we always use a consistent allocator. Additionally, only
+ /// a small amount of sliding windows are expected to be in use
+ /// at any one time so the memory overhead isn't that large.
+ alloc: Allocator,
+
/// The data buffer is a circular buffer of u8 that contains the
/// encoded page text that we can use to search for the needle.
data: DataBuf,
@@ -163,6 +168,7 @@ const SlidingWindow = struct {
errdefer alloc.free(overlap_buf);
return .{
+ .alloc = alloc,
.data = data,
.meta = meta,
.needle = needle,
@@ -170,13 +176,13 @@ const SlidingWindow = struct {
};
}
- pub fn deinit(self: *SlidingWindow, alloc: Allocator) void {
- alloc.free(self.overlap_buf);
- self.data.deinit(alloc);
+ pub fn deinit(self: *SlidingWindow) void {
+ self.alloc.free(self.overlap_buf);
+ self.data.deinit(self.alloc);
var meta_it = self.meta.iterator(.forward);
while (meta_it.next()) |meta| meta.deinit();
- self.meta.deinit(alloc);
+ self.meta.deinit(self.alloc);
}
/// Clear all data but retain allocated capacity.
@@ -206,7 +212,10 @@ const SlidingWindow = struct {
// Search the first slice for the needle.
if (std.mem.indexOf(u8, slices[0], self.needle)) |idx| {
- return self.selection(idx, self.needle.len);
+ return self.selection(
+ idx,
+ self.needle.len,
+ );
}
// Search the overlap buffer for the needle.
@@ -244,7 +253,10 @@ const SlidingWindow = struct {
// Search the last slice for the needle.
if (std.mem.indexOf(u8, slices[1], self.needle)) |idx| {
- return self.selection(slices[0].len + idx, self.needle.len);
+ return self.selection(
+ slices[0].len + idx,
+ self.needle.len,
+ );
}
// No match. We keep `needle.len - 1` bytes available to
@@ -254,15 +266,15 @@ const SlidingWindow = struct {
var saved: usize = 0;
while (meta_it.next()) |meta| {
const needed = self.needle.len - 1 - saved;
- if (meta.cell_map.items.len >= needed) {
+ if (meta.cell_map.map.items.len >= needed) {
// We save up to this meta. We set our data offset
// to exactly where it needs to be to continue
// searching.
- self.data_offset = meta.cell_map.items.len - needed;
+ self.data_offset = meta.cell_map.map.items.len - needed;
break;
}
- saved += meta.cell_map.items.len;
+ saved += meta.cell_map.map.items.len;
} else {
// If we exited the while loop naturally then we
// never got the amount we needed and so there is
@@ -284,7 +296,7 @@ const SlidingWindow = struct {
var prune_data_len: usize = 0;
for (0..prune_count) |_| {
const meta = meta_it.next().?;
- prune_data_len += meta.cell_map.items.len;
+ prune_data_len += meta.cell_map.map.items.len;
meta.deinit();
}
self.meta.deleteOldest(prune_count);
@@ -384,16 +396,16 @@ const SlidingWindow = struct {
// meta_i is the index we expect to find the match in the
// cell map within this meta if it contains it.
const meta_i = idx - offset.*;
- if (meta_i >= meta.cell_map.items.len) {
+ if (meta_i >= meta.cell_map.map.items.len) {
// This meta doesn't contain the match. This means we
// can also prune this set of data because we only look
// forward.
- offset.* += meta.cell_map.items.len;
+ offset.* += meta.cell_map.map.items.len;
continue;
}
// We found the meta that contains the start of the match.
- const map = meta.cell_map.items[meta_i];
+ const map = meta.cell_map.map.items[meta_i];
return .{
.node = meta.node,
.y = map.y,
@@ -411,13 +423,15 @@ const SlidingWindow = struct {
/// via a search (via next()).
pub fn append(
self: *SlidingWindow,
- alloc: Allocator,
node: *PageList.List.Node,
) Allocator.Error!void {
// Initialize our metadata for the node.
var meta: Meta = .{
.node = node,
- .cell_map = .init(alloc),
+ .cell_map = .{
+ .alloc = self.alloc,
+ .map = .empty,
+ },
};
errdefer meta.deinit();
@@ -425,27 +439,27 @@ const SlidingWindow = struct {
// temporary memory, and then copy it into our circular buffer.
// In the future, we should benchmark and see if we can encode
// directly into the circular buffer.
- var encoded: std.ArrayListUnmanaged(u8) = .{};
- defer encoded.deinit(alloc);
+ var encoded: std.Io.Writer.Allocating = .init(self.alloc);
+ defer encoded.deinit();
// Encode the page into the buffer.
const page: *const Page = &meta.node.data;
_ = page.encodeUtf8(
- encoded.writer(alloc),
+ &encoded.writer,
.{ .cell_map = &meta.cell_map },
) catch {
// writer uses anyerror but the only realistic error on
// an ArrayList is out of memory.
return error.OutOfMemory;
};
- assert(meta.cell_map.items.len == encoded.items.len);
+ assert(meta.cell_map.map.items.len == encoded.written().len);
// Ensure our buffers are big enough to store what we need.
- try self.data.ensureUnusedCapacity(alloc, encoded.items.len);
- try self.meta.ensureUnusedCapacity(alloc, 1);
+ try self.data.ensureUnusedCapacity(self.alloc, encoded.written().len);
+ try self.meta.ensureUnusedCapacity(self.alloc, 1);
// Append our new node to the circular buffer.
- try self.data.appendSlice(encoded.items);
+ try self.data.appendSlice(encoded.written());
try self.meta.append(meta);
self.assertIntegrity();
@@ -462,7 +476,7 @@ const SlidingWindow = struct {
// Integrity check: verify our data matches our metadata exactly.
var meta_it = self.meta.iterator(.forward);
var data_len: usize = 0;
- while (meta_it.next()) |m| data_len += m.cell_map.items.len;
+ while (meta_it.next()) |m| data_len += m.cell_map.map.items.len;
assert(data_len == self.data.len());
// Integrity check: verify our data offset is within bounds.
@@ -480,11 +494,11 @@ test "PageListSearch single page" {
try testing.expect(s.pages.pages.first == s.pages.pages.last);
var search = try PageListSearch.init(alloc, &s.pages, "boo!");
- defer search.deinit(alloc);
+ defer search.deinit();
// We should be able to find two matches.
{
- const sel = (try search.next(alloc)).?;
+ const sel = (try search.next()).?;
try testing.expectEqual(point.Point{ .active = .{
.x = 7,
.y = 0,
@@ -495,7 +509,7 @@ test "PageListSearch single page" {
} }, s.pages.pointFromPin(.active, sel.end()).?);
}
{
- const sel = (try search.next(alloc)).?;
+ const sel = (try search.next()).?;
try testing.expectEqual(point.Point{ .active = .{
.x = 19,
.y = 0,
@@ -505,8 +519,8 @@ test "PageListSearch single page" {
.y = 0,
} }, s.pages.pointFromPin(.active, sel.end()).?);
}
- try testing.expect((try search.next(alloc)) == null);
- try testing.expect((try search.next(alloc)) == null);
+ try testing.expect((try search.next()) == null);
+ try testing.expect((try search.next()) == null);
}
test "SlidingWindow empty on init" {
@@ -514,7 +528,7 @@ test "SlidingWindow empty on init" {
const alloc = testing.allocator;
var w = try SlidingWindow.init(alloc, "boo!");
- defer w.deinit(alloc);
+ defer w.deinit();
try testing.expectEqual(0, w.data.len());
try testing.expectEqual(0, w.meta.len());
}
@@ -524,7 +538,7 @@ test "SlidingWindow single append" {
const alloc = testing.allocator;
var w = try SlidingWindow.init(alloc, "boo!");
- defer w.deinit(alloc);
+ defer w.deinit();
var s = try Screen.init(alloc, 80, 24, 0);
defer s.deinit();
@@ -533,7 +547,7 @@ test "SlidingWindow single append" {
// We want to test single-page cases.
try testing.expect(s.pages.pages.first == s.pages.pages.last);
const node: *PageList.List.Node = s.pages.pages.first.?;
- try w.append(alloc, node);
+ try w.append(node);
// We should be able to find two matches.
{
@@ -567,7 +581,7 @@ test "SlidingWindow single append no match" {
const alloc = testing.allocator;
var w = try SlidingWindow.init(alloc, "nope!");
- defer w.deinit(alloc);
+ defer w.deinit();
var s = try Screen.init(alloc, 80, 24, 0);
defer s.deinit();
@@ -576,7 +590,7 @@ test "SlidingWindow single append no match" {
// We want to test single-page cases.
try testing.expect(s.pages.pages.first == s.pages.pages.last);
const node: *PageList.List.Node = s.pages.pages.first.?;
- try w.append(alloc, node);
+ try w.append(node);
// No matches
try testing.expect(w.next() == null);
@@ -591,7 +605,7 @@ test "SlidingWindow two pages" {
const alloc = testing.allocator;
var w = try SlidingWindow.init(alloc, "boo!");
- defer w.deinit(alloc);
+ defer w.deinit();
var s = try Screen.init(alloc, 80, 24, 1000);
defer s.deinit();
@@ -609,8 +623,8 @@ test "SlidingWindow two pages" {
// Add both pages
const node: *PageList.List.Node = s.pages.pages.first.?;
- try w.append(alloc, node);
- try w.append(alloc, node.next.?);
+ try w.append(node);
+ try w.append(node.next.?);
// Search should find two matches
{
@@ -644,7 +658,7 @@ test "SlidingWindow two pages match across boundary" {
const alloc = testing.allocator;
var w = try SlidingWindow.init(alloc, "hello, world");
- defer w.deinit(alloc);
+ defer w.deinit();
var s = try Screen.init(alloc, 80, 24, 1000);
defer s.deinit();
@@ -661,8 +675,8 @@ test "SlidingWindow two pages match across boundary" {
// Add both pages
const node: *PageList.List.Node = s.pages.pages.first.?;
- try w.append(alloc, node);
- try w.append(alloc, node.next.?);
+ try w.append(node);
+ try w.append(node.next.?);
// Search should find a match
{
@@ -688,7 +702,7 @@ test "SlidingWindow two pages no match prunes first page" {
const alloc = testing.allocator;
var w = try SlidingWindow.init(alloc, "nope!");
- defer w.deinit(alloc);
+ defer w.deinit();
var s = try Screen.init(alloc, 80, 24, 1000);
defer s.deinit();
@@ -706,8 +720,8 @@ test "SlidingWindow two pages no match prunes first page" {
// Add both pages
const node: *PageList.List.Node = s.pages.pages.first.?;
- try w.append(alloc, node);
- try w.append(alloc, node.next.?);
+ try w.append(node);
+ try w.append(node.next.?);
// Search should find nothing
try testing.expect(w.next() == null);
@@ -737,18 +751,18 @@ test "SlidingWindow two pages no match keeps both pages" {
try s.testWriteString("hello. boo!");
// Imaginary needle for search. Doesn't match!
- var needle_list = std.ArrayList(u8).init(alloc);
- defer needle_list.deinit();
- try needle_list.appendNTimes('x', first_page_rows * s.pages.cols);
+ var needle_list: std.ArrayList(u8) = .empty;
+ defer needle_list.deinit(alloc);
+ try needle_list.appendNTimes(alloc, 'x', first_page_rows * s.pages.cols);
const needle: []const u8 = needle_list.items;
var w = try SlidingWindow.init(alloc, needle);
- defer w.deinit(alloc);
+ defer w.deinit();
// Add both pages
const node: *PageList.List.Node = s.pages.pages.first.?;
- try w.append(alloc, node);
- try w.append(alloc, node.next.?);
+ try w.append(node);
+ try w.append(node.next.?);
// Search should find nothing
try testing.expect(w.next() == null);
@@ -763,7 +777,7 @@ test "SlidingWindow single append across circular buffer boundary" {
const alloc = testing.allocator;
var w = try SlidingWindow.init(alloc, "abc");
- defer w.deinit(alloc);
+ defer w.deinit();
var s = try Screen.init(alloc, 80, 24, 0);
defer s.deinit();
@@ -776,8 +790,8 @@ test "SlidingWindow single append across circular buffer boundary" {
// our implementation changes our test will fail.
try testing.expect(s.pages.pages.first == s.pages.pages.last);
const node: *PageList.List.Node = s.pages.pages.first.?;
- try w.append(alloc, node);
- try w.append(alloc, node);
+ try w.append(node);
+ try w.append(node);
{
// No wrap around yet
const slices = w.data.getPtrSlice(0, w.data.len());
@@ -793,7 +807,7 @@ test "SlidingWindow single append across circular buffer boundary" {
w.needle = "boo";
// Add new page, now wraps
- try w.append(alloc, node);
+ try w.append(node);
{
const slices = w.data.getPtrSlice(0, w.data.len());
try testing.expect(slices[0].len > 0);
@@ -818,7 +832,7 @@ test "SlidingWindow single append match on boundary" {
const alloc = testing.allocator;
var w = try SlidingWindow.init(alloc, "abcd");
- defer w.deinit(alloc);
+ defer w.deinit();
var s = try Screen.init(alloc, 80, 24, 0);
defer s.deinit();
@@ -831,8 +845,8 @@ test "SlidingWindow single append match on boundary" {
// our implementation changes our test will fail.
try testing.expect(s.pages.pages.first == s.pages.pages.last);
const node: *PageList.List.Node = s.pages.pages.first.?;
- try w.append(alloc, node);
- try w.append(alloc, node);
+ try w.append(node);
+ try w.append(node);
{
// No wrap around yet
const slices = w.data.getPtrSlice(0, w.data.len());
@@ -848,7 +862,7 @@ test "SlidingWindow single append match on boundary" {
w.needle = "boo!";
// Add new page, now wraps
- try w.append(alloc, node);
+ try w.append(node);
{
const slices = w.data.getPtrSlice(0, w.data.len());
try testing.expect(slices[0].len > 0);
diff --git a/src/terminal/stream.zig b/src/terminal/stream.zig
index db43aae47..c85e72f0f 100644
--- a/src/terminal/stream.zig
+++ b/src/terminal/stream.zig
@@ -288,13 +288,13 @@ pub fn Stream(comptime Handler: type) type {
for (actions) |action_opt| {
const action = action_opt orelse continue;
- if (comptime debug) log.info("action: {}", .{action});
+ if (comptime debug) log.info("action: {f}", .{action});
// If this handler handles everything manually then we do nothing
// if it can be processed.
if (@hasDecl(T, "handleManually")) {
const processed = self.handler.handleManually(action) catch |err| err: {
- log.warn("error handling action manually err={} action={}", .{
+ log.warn("error handling action manually err={} action={f}", .{
err,
action,
});
@@ -341,7 +341,7 @@ pub fn Stream(comptime Handler: type) type {
pub inline fn execute(self: *Self, c: u8) !void {
const c0: ansi.C0 = @enumFromInt(c);
- if (comptime debug) log.info("execute: {}", .{c0});
+ if (comptime debug) log.info("execute: {f}", .{c0});
switch (c0) {
// We ignore SOH/STX: https://github.com/microsoft/terminal/issues/10786
.NUL, .SOH, .STX => {},
@@ -399,12 +399,12 @@ pub fn Stream(comptime Handler: type) type {
0 => 1,
1 => input.params[0],
else => {
- log.warn("invalid cursor up command: {}", .{input});
+ log.warn("invalid cursor up command: {f}", .{input});
return;
},
},
false,
- ) else log.warn("unimplemented CSI callback: {}", .{input}),
+ ) else log.warn("unimplemented CSI callback: {f}", .{input}),
else => log.warn(
"ignoring unimplemented CSI A with intermediates: {s}",
@@ -419,12 +419,12 @@ pub fn Stream(comptime Handler: type) type {
0 => 1,
1 => input.params[0],
else => {
- log.warn("invalid cursor down command: {}", .{input});
+ log.warn("invalid cursor down command: {f}", .{input});
return;
},
},
false,
- ) else log.warn("unimplemented CSI callback: {}", .{input}),
+ ) else log.warn("unimplemented CSI callback: {f}", .{input}),
else => log.warn(
"ignoring unimplemented CSI B with intermediates: {s}",
@@ -439,11 +439,11 @@ pub fn Stream(comptime Handler: type) type {
0 => 1,
1 => input.params[0],
else => {
- log.warn("invalid cursor right command: {}", .{input});
+ log.warn("invalid cursor right command: {f}", .{input});
return;
},
},
- ) else log.warn("unimplemented CSI callback: {}", .{input}),
+ ) else log.warn("unimplemented CSI callback: {f}", .{input}),
else => log.warn(
"ignoring unimplemented CSI C with intermediates: {s}",
@@ -458,11 +458,11 @@ pub fn Stream(comptime Handler: type) type {
0 => 1,
1 => input.params[0],
else => {
- log.warn("invalid cursor left command: {}", .{input});
+ log.warn("invalid cursor left command: {f}", .{input});
return;
},
},
- ) else log.warn("unimplemented CSI callback: {}", .{input}),
+ ) else log.warn("unimplemented CSI callback: {f}", .{input}),
else => log.warn(
"ignoring unimplemented CSI D with intermediates: {s}",
@@ -477,12 +477,12 @@ pub fn Stream(comptime Handler: type) type {
0 => 1,
1 => input.params[0],
else => {
- log.warn("invalid cursor up command: {}", .{input});
+ log.warn("invalid cursor up command: {f}", .{input});
return;
},
},
true,
- ) else log.warn("unimplemented CSI callback: {}", .{input}),
+ ) else log.warn("unimplemented CSI callback: {f}", .{input}),
else => log.warn(
"ignoring unimplemented CSI E with intermediates: {s}",
@@ -497,12 +497,12 @@ pub fn Stream(comptime Handler: type) type {
0 => 1,
1 => input.params[0],
else => {
- log.warn("invalid cursor down command: {}", .{input});
+ log.warn("invalid cursor down command: {f}", .{input});
return;
},
},
true,
- ) else log.warn("unimplemented CSI callback: {}", .{input}),
+ ) else log.warn("unimplemented CSI callback: {f}", .{input}),
else => log.warn(
"ignoring unimplemented CSI F with intermediates: {s}",
@@ -516,8 +516,8 @@ pub fn Stream(comptime Handler: type) type {
0 => if (@hasDecl(T, "setCursorCol")) switch (input.params.len) {
0 => try self.handler.setCursorCol(1),
1 => try self.handler.setCursorCol(input.params[0]),
- else => log.warn("invalid HPA command: {}", .{input}),
- } else log.warn("unimplemented CSI callback: {}", .{input}),
+ else => log.warn("invalid HPA command: {f}", .{input}),
+ } else log.warn("unimplemented CSI callback: {f}", .{input}),
else => log.warn(
"ignoring unimplemented CSI G with intermediates: {s}",
@@ -532,8 +532,8 @@ pub fn Stream(comptime Handler: type) type {
0 => try self.handler.setCursorPos(1, 1),
1 => try self.handler.setCursorPos(input.params[0], 1),
2 => try self.handler.setCursorPos(input.params[0], input.params[1]),
- else => log.warn("invalid CUP command: {}", .{input}),
- } else log.warn("unimplemented CSI callback: {}", .{input}),
+ else => log.warn("invalid CUP command: {f}", .{input}),
+ } else log.warn("unimplemented CSI callback: {f}", .{input}),
else => log.warn(
"ignoring unimplemented CSI H with intermediates: {s}",
@@ -548,11 +548,11 @@ pub fn Stream(comptime Handler: type) type {
0 => 1,
1 => input.params[0],
else => {
- log.warn("invalid horizontal tab command: {}", .{input});
+ log.warn("invalid horizontal tab command: {f}", .{input});
return;
},
},
- ) else log.warn("unimplemented CSI callback: {}", .{input}),
+ ) else log.warn("unimplemented CSI callback: {f}", .{input}),
else => log.warn(
"ignoring unimplemented CSI I with intermediates: {s}",
@@ -569,7 +569,7 @@ pub fn Stream(comptime Handler: type) type {
};
const protected = protected_ orelse {
- log.warn("invalid erase display command: {}", .{input});
+ log.warn("invalid erase display command: {f}", .{input});
return;
};
@@ -580,12 +580,12 @@ pub fn Stream(comptime Handler: type) type {
};
const mode = mode_ orelse {
- log.warn("invalid erase display command: {}", .{input});
+ log.warn("invalid erase display command: {f}", .{input});
return;
};
try self.handler.eraseDisplay(mode, protected);
- } else log.warn("unimplemented CSI callback: {}", .{input}),
+ } else log.warn("unimplemented CSI callback: {f}", .{input}),
// Erase Line
'K' => if (@hasDecl(T, "eraseLine")) {
@@ -596,7 +596,7 @@ pub fn Stream(comptime Handler: type) type {
};
const protected = protected_ orelse {
- log.warn("invalid erase line command: {}", .{input});
+ log.warn("invalid erase line command: {f}", .{input});
return;
};
@@ -607,12 +607,12 @@ pub fn Stream(comptime Handler: type) type {
};
const mode = mode_ orelse {
- log.warn("invalid erase line command: {}", .{input});
+ log.warn("invalid erase line command: {f}", .{input});
return;
};
try self.handler.eraseLine(mode, protected);
- } else log.warn("unimplemented CSI callback: {}", .{input}),
+ } else log.warn("unimplemented CSI callback: {f}", .{input}),
// IL - Insert Lines
// TODO: test
@@ -620,8 +620,8 @@ pub fn Stream(comptime Handler: type) type {
0 => if (@hasDecl(T, "insertLines")) switch (input.params.len) {
0 => try self.handler.insertLines(1),
1 => try self.handler.insertLines(input.params[0]),
- else => log.warn("invalid IL command: {}", .{input}),
- } else log.warn("unimplemented CSI callback: {}", .{input}),
+ else => log.warn("invalid IL command: {f}", .{input}),
+ } else log.warn("unimplemented CSI callback: {f}", .{input}),
else => log.warn(
"ignoring unimplemented CSI L with intermediates: {s}",
@@ -635,8 +635,8 @@ pub fn Stream(comptime Handler: type) type {
0 => if (@hasDecl(T, "deleteLines")) switch (input.params.len) {
0 => try self.handler.deleteLines(1),
1 => try self.handler.deleteLines(input.params[0]),
- else => log.warn("invalid DL command: {}", .{input}),
- } else log.warn("unimplemented CSI callback: {}", .{input}),
+ else => log.warn("invalid DL command: {f}", .{input}),
+ } else log.warn("unimplemented CSI callback: {f}", .{input}),
else => log.warn(
"ignoring unimplemented CSI M with intermediates: {s}",
@@ -651,11 +651,11 @@ pub fn Stream(comptime Handler: type) type {
0 => 1,
1 => input.params[0],
else => {
- log.warn("invalid delete characters command: {}", .{input});
+ log.warn("invalid delete characters command: {f}", .{input});
return;
},
},
- ) else log.warn("unimplemented CSI callback: {}", .{input}),
+ ) else log.warn("unimplemented CSI callback: {f}", .{input}),
else => log.warn(
"ignoring unimplemented CSI P with intermediates: {s}",
@@ -671,11 +671,11 @@ pub fn Stream(comptime Handler: type) type {
0 => 1,
1 => input.params[0],
else => {
- log.warn("invalid scroll up command: {}", .{input});
+ log.warn("invalid scroll up command: {f}", .{input});
return;
},
},
- ) else log.warn("unimplemented CSI callback: {}", .{input}),
+ ) else log.warn("unimplemented CSI callback: {f}", .{input}),
else => log.warn(
"ignoring unimplemented CSI S with intermediates: {s}",
@@ -690,11 +690,11 @@ pub fn Stream(comptime Handler: type) type {
0 => 1,
1 => input.params[0],
else => {
- log.warn("invalid scroll down command: {}", .{input});
+ log.warn("invalid scroll down command: {f}", .{input});
return;
},
},
- ) else log.warn("unimplemented CSI callback: {}", .{input}),
+ ) else log.warn("unimplemented CSI callback: {f}", .{input}),
else => log.warn(
"ignoring unimplemented CSI T with intermediates: {s}",
@@ -711,7 +711,7 @@ pub fn Stream(comptime Handler: type) type {
if (@hasDecl(T, "tabSet"))
try self.handler.tabSet()
else
- log.warn("unimplemented tab set callback: {}", .{input});
+ log.warn("unimplemented tab set callback: {f}", .{input});
return;
}
@@ -725,12 +725,12 @@ pub fn Stream(comptime Handler: type) type {
2 => if (@hasDecl(T, "tabClear"))
try self.handler.tabClear(.current)
else
- log.warn("unimplemented tab clear callback: {}", .{input}),
+ log.warn("unimplemented tab clear callback: {f}", .{input}),
5 => if (@hasDecl(T, "tabClear"))
try self.handler.tabClear(.all)
else
- log.warn("unimplemented tab clear callback: {}", .{input}),
+ log.warn("unimplemented tab clear callback: {f}", .{input}),
else => {},
},
@@ -738,7 +738,7 @@ pub fn Stream(comptime Handler: type) type {
else => {},
}
- log.warn("invalid cursor tabulation control: {}", .{input});
+ log.warn("invalid cursor tabulation control: {f}", .{input});
return;
},
@@ -746,8 +746,8 @@ pub fn Stream(comptime Handler: type) type {
if (@hasDecl(T, "tabReset"))
try self.handler.tabReset()
else
- log.warn("unimplemented tab reset callback: {}", .{input});
- } else log.warn("invalid cursor tabulation control: {}", .{input}),
+ log.warn("unimplemented tab reset callback: {f}", .{input});
+ } else log.warn("invalid cursor tabulation control: {f}", .{input}),
else => log.warn(
"ignoring unimplemented CSI W with intermediates: {s}",
@@ -762,11 +762,11 @@ pub fn Stream(comptime Handler: type) type {
0 => 1,
1 => input.params[0],
else => {
- log.warn("invalid erase characters command: {}", .{input});
+ log.warn("invalid erase characters command: {f}", .{input});
return;
},
},
- ) else log.warn("unimplemented CSI callback: {}", .{input}),
+ ) else log.warn("unimplemented CSI callback: {f}", .{input}),
else => log.warn(
"ignoring unimplemented CSI X with intermediates: {s}",
@@ -781,11 +781,11 @@ pub fn Stream(comptime Handler: type) type {
0 => 1,
1 => input.params[0],
else => {
- log.warn("invalid horizontal tab back command: {}", .{input});
+ log.warn("invalid horizontal tab back command: {f}", .{input});
return;
},
},
- ) else log.warn("unimplemented CSI callback: {}", .{input}),
+ ) else log.warn("unimplemented CSI callback: {f}", .{input}),
else => log.warn(
"ignoring unimplemented CSI Z with intermediates: {s}",
@@ -800,11 +800,11 @@ pub fn Stream(comptime Handler: type) type {
0 => 1,
1 => input.params[0],
else => {
- log.warn("invalid HPR command: {}", .{input});
+ log.warn("invalid HPR command: {f}", .{input});
return;
},
},
- ) else log.warn("unimplemented CSI callback: {}", .{input}),
+ ) else log.warn("unimplemented CSI callback: {f}", .{input}),
else => log.warn(
"ignoring unimplemented CSI a with intermediates: {s}",
@@ -819,11 +819,11 @@ pub fn Stream(comptime Handler: type) type {
0 => 1,
1 => input.params[0],
else => {
- log.warn("invalid print repeat command: {}", .{input});
+ log.warn("invalid print repeat command: {f}", .{input});
return;
},
},
- ) else log.warn("unimplemented CSI callback: {}", .{input}),
+ ) else log.warn("unimplemented CSI callback: {f}", .{input}),
else => log.warn(
"ignoring unimplemented CSI b with intermediates: {s}",
@@ -842,12 +842,12 @@ pub fn Stream(comptime Handler: type) type {
},
else => @as(?ansi.DeviceAttributeReq, null),
} orelse {
- log.warn("invalid device attributes command: {}", .{input});
+ log.warn("invalid device attributes command: {f}", .{input});
return;
};
try self.handler.deviceAttributes(req, input.params);
- } else log.warn("unimplemented CSI callback: {}", .{input}),
+ } else log.warn("unimplemented CSI callback: {f}", .{input}),
// VPA - Cursor Vertical Position Absolute
'd' => switch (input.intermediates.len) {
@@ -856,11 +856,11 @@ pub fn Stream(comptime Handler: type) type {
0 => 1,
1 => input.params[0],
else => {
- log.warn("invalid VPA command: {}", .{input});
+ log.warn("invalid VPA command: {f}", .{input});
return;
},
},
- ) else log.warn("unimplemented CSI callback: {}", .{input}),
+ ) else log.warn("unimplemented CSI callback: {f}", .{input}),
else => log.warn(
"ignoring unimplemented CSI d with intermediates: {s}",
@@ -875,11 +875,11 @@ pub fn Stream(comptime Handler: type) type {
0 => 1,
1 => input.params[0],
else => {
- log.warn("invalid VPR command: {}", .{input});
+ log.warn("invalid VPR command: {f}", .{input});
return;
},
},
- ) else log.warn("unimplemented CSI callback: {}", .{input}),
+ ) else log.warn("unimplemented CSI callback: {f}", .{input}),
else => log.warn(
"ignoring unimplemented CSI e with intermediates: {s}",
@@ -894,11 +894,11 @@ pub fn Stream(comptime Handler: type) type {
switch (input.params.len) {
1 => @enumFromInt(input.params[0]),
else => {
- log.warn("invalid tab clear command: {}", .{input});
+ log.warn("invalid tab clear command: {f}", .{input});
return;
},
},
- ) else log.warn("unimplemented CSI callback: {}", .{input}),
+ ) else log.warn("unimplemented CSI callback: {f}", .{input}),
else => log.warn(
"ignoring unimplemented CSI g with intermediates: {s}",
@@ -913,7 +913,7 @@ pub fn Stream(comptime Handler: type) type {
if (input.intermediates.len == 1 and
input.intermediates[0] == '?') break :ansi false;
- log.warn("invalid set mode command: {}", .{input});
+ log.warn("invalid set mode command: {f}", .{input});
break :mode;
};
@@ -924,7 +924,7 @@ pub fn Stream(comptime Handler: type) type {
log.warn("unimplemented mode: {}", .{mode_int});
}
}
- } else log.warn("unimplemented CSI callback: {}", .{input}),
+ } else log.warn("unimplemented CSI callback: {f}", .{input}),
// RM - Reset Mode
'l' => if (@hasDecl(T, "setMode")) mode: {
@@ -933,7 +933,7 @@ pub fn Stream(comptime Handler: type) type {
if (input.intermediates.len == 1 and
input.intermediates[0] == '?') break :ansi false;
- log.warn("invalid set mode command: {}", .{input});
+ log.warn("invalid set mode command: {f}", .{input});
break :mode;
};
@@ -944,7 +944,7 @@ pub fn Stream(comptime Handler: type) type {
log.warn("unimplemented mode: {}", .{mode_int});
}
}
- } else log.warn("unimplemented CSI callback: {}", .{input}),
+ } else log.warn("unimplemented CSI callback: {f}", .{input}),
// SGR - Select Graphic Rendition
'm' => switch (input.intermediates.len) {
@@ -958,7 +958,7 @@ pub fn Stream(comptime Handler: type) type {
// log.info("SGR attribute: {}", .{attr});
try self.handler.setAttribute(attr);
}
- } else log.warn("unimplemented CSI callback: {}", .{input}),
+ } else log.warn("unimplemented CSI callback: {f}", .{input}),
1 => switch (input.intermediates[0]) {
'>' => if (@hasDecl(T, "setModifyKeyFormat")) blk: {
@@ -974,13 +974,13 @@ pub fn Stream(comptime Handler: type) type {
2 => .{ .function_keys = {} },
4 => .{ .other_keys = .none },
else => {
- log.warn("invalid setModifyKeyFormat: {}", .{input});
+ log.warn("invalid setModifyKeyFormat: {f}", .{input});
break :blk;
},
};
if (input.params.len > 2) {
- log.warn("invalid setModifyKeyFormat: {}", .{input});
+ log.warn("invalid setModifyKeyFormat: {f}", .{input});
break :blk;
}
@@ -1000,7 +1000,7 @@ pub fn Stream(comptime Handler: type) type {
}
try self.handler.setModifyKeyFormat(format);
- } else log.warn("unimplemented setModifyKeyFormat: {}", .{input}),
+ } else log.warn("unimplemented setModifyKeyFormat: {f}", .{input}),
else => log.warn(
"unknown CSI m with intermediate: {}",
@@ -1029,12 +1029,12 @@ pub fn Stream(comptime Handler: type) type {
input.intermediates[0] == '?')
{
if (!@hasDecl(T, "deviceStatusReport")) {
- log.warn("unimplemented CSI callback: {}", .{input});
+ log.warn("unimplemented CSI callback: {f}", .{input});
return;
}
if (input.params.len != 1) {
- log.warn("invalid device status report command: {}", .{input});
+ log.warn("invalid device status report command: {f}", .{input});
return;
}
@@ -1043,12 +1043,12 @@ pub fn Stream(comptime Handler: type) type {
if (input.intermediates.len == 1 and
input.intermediates[0] == '?') break :question true;
- log.warn("invalid set mode command: {}", .{input});
+ log.warn("invalid set mode command: {f}", .{input});
return;
};
const req = device_status.reqFromInt(input.params[0], question) orelse {
- log.warn("invalid device status report command: {}", .{input});
+ log.warn("invalid device status report command: {f}", .{input});
return;
};
@@ -1067,7 +1067,7 @@ pub fn Stream(comptime Handler: type) type {
// only support reverting back to modify other keys in
// numeric except format.
try self.handler.setModifyKeyFormat(.{ .other_keys = .numeric_except });
- } else log.warn("unimplemented setModifyKeyFormat: {}", .{input}),
+ } else log.warn("unimplemented setModifyKeyFormat: {f}", .{input}),
else => log.warn(
"unknown CSI n with intermediate: {}",
@@ -1101,13 +1101,13 @@ pub fn Stream(comptime Handler: type) type {
};
if (input.params.len != 1) {
- log.warn("invalid DECRQM command: {}", .{input});
+ log.warn("invalid DECRQM command: {f}", .{input});
break :decrqm;
}
if (@hasDecl(T, "requestMode")) {
try self.handler.requestMode(input.params[0], ansi_mode);
- } else log.warn("unimplemented DECRQM callback: {}", .{input});
+ } else log.warn("unimplemented DECRQM callback: {f}", .{input});
},
else => log.warn(
@@ -1126,11 +1126,11 @@ pub fn Stream(comptime Handler: type) type {
0 => ansi.CursorStyle.default,
1 => @enumFromInt(input.params[0]),
else => {
- log.warn("invalid set curor style command: {}", .{input});
+ log.warn("invalid set curor style command: {f}", .{input});
return;
},
},
- ) else log.warn("unimplemented CSI callback: {}", .{input});
+ ) else log.warn("unimplemented CSI callback: {f}", .{input});
},
// DECSCA
@@ -1147,12 +1147,12 @@ pub fn Stream(comptime Handler: type) type {
};
const mode = mode_ orelse {
- log.warn("invalid set protected mode command: {}", .{input});
+ log.warn("invalid set protected mode command: {f}", .{input});
return;
};
try self.handler.setProtectedMode(mode);
- } else log.warn("unimplemented CSI callback: {}", .{input});
+ } else log.warn("unimplemented CSI callback: {f}", .{input});
},
// XTVERSION
@@ -1180,10 +1180,10 @@ pub fn Stream(comptime Handler: type) type {
0 => try self.handler.setTopAndBottomMargin(0, 0),
1 => try self.handler.setTopAndBottomMargin(input.params[0], 0),
2 => try self.handler.setTopAndBottomMargin(input.params[0], input.params[1]),
- else => log.warn("invalid DECSTBM command: {}", .{input}),
+ else => log.warn("invalid DECSTBM command: {f}", .{input}),
}
} else log.warn(
- "unimplemented CSI callback: {}",
+ "unimplemented CSI callback: {f}",
.{input},
),
@@ -1203,13 +1203,13 @@ pub fn Stream(comptime Handler: type) type {
},
else => log.warn(
- "unknown CSI s with intermediate: {}",
+ "unknown CSI s with intermediate: {f}",
.{input},
),
},
else => log.warn(
- "ignoring unimplemented CSI s with intermediates: {s}",
+ "ignoring unimplemented CSI s with intermediates: {f}",
.{input},
),
},
@@ -1225,10 +1225,10 @@ pub fn Stream(comptime Handler: type) type {
0 => try self.handler.setLeftAndRightMarginAmbiguous(),
1 => try self.handler.setLeftAndRightMargin(input.params[0], 0),
2 => try self.handler.setLeftAndRightMargin(input.params[0], input.params[1]),
- else => log.warn("invalid DECSLRM command: {}", .{input}),
+ else => log.warn("invalid DECSLRM command: {f}", .{input}),
}
} else log.warn(
- "unimplemented CSI callback: {}",
+ "unimplemented CSI callback: {f}",
.{input},
),
@@ -1254,30 +1254,30 @@ pub fn Stream(comptime Handler: type) type {
0 => false,
1 => true,
else => {
- log.warn("invalid XTSHIFTESCAPE command: {}", .{input});
+ log.warn("invalid XTSHIFTESCAPE command: {f}", .{input});
break :capture;
},
},
else => {
- log.warn("invalid XTSHIFTESCAPE command: {}", .{input});
+ log.warn("invalid XTSHIFTESCAPE command: {f}", .{input});
break :capture;
},
};
try self.handler.setMouseShiftCapture(capture);
} else log.warn(
- "unimplemented CSI callback: {}",
+ "unimplemented CSI callback: {f}",
.{input},
),
else => log.warn(
- "unknown CSI s with intermediate: {}",
+ "unknown CSI s with intermediate: {f}",
.{input},
),
},
else => log.warn(
- "ignoring unimplemented CSI s with intermediates: {s}",
+ "ignoring unimplemented CSI s with intermediates: {f}",
.{input},
),
},
@@ -1296,7 +1296,7 @@ pub fn Stream(comptime Handler: type) type {
.{},
);
} else log.warn(
- "ignoring CSI 14 t with extra parameters: {}",
+ "ignoring CSI 14 t with extra parameters: {f}",
.{input},
),
16 => if (input.params.len == 1) {
@@ -1308,7 +1308,7 @@ pub fn Stream(comptime Handler: type) type {
.{},
);
} else log.warn(
- "ignoring CSI 16 t with extra parameters: {s}",
+ "ignoring CSI 16 t with extra parameters: {f}",
.{input},
),
18 => if (input.params.len == 1) {
@@ -1320,7 +1320,7 @@ pub fn Stream(comptime Handler: type) type {
.{},
);
} else log.warn(
- "ignoring CSI 18 t with extra parameters: {s}",
+ "ignoring CSI 18 t with extra parameters: {f}",
.{input},
),
21 => if (input.params.len == 1) {
@@ -1332,7 +1332,7 @@ pub fn Stream(comptime Handler: type) type {
.{},
);
} else log.warn(
- "ignoring CSI 21 t with extra parameters: {s}",
+ "ignoring CSI 21 t with extra parameters: {f}",
.{input},
),
inline 22, 23 => |number| if ((input.params.len == 2 or
@@ -1359,21 +1359,21 @@ pub fn Stream(comptime Handler: type) type {
.{},
);
} else log.warn(
- "ignoring CSI 22/23 t with extra parameters: {s}",
+ "ignoring CSI 22/23 t with extra parameters: {f}",
.{input},
),
else => log.warn(
- "ignoring CSI t with unimplemented parameter: {s}",
+ "ignoring CSI t with unimplemented parameter: {f}",
.{input},
),
}
} else log.err(
- "ignoring CSI t with no parameters: {s}",
+ "ignoring CSI t with no parameters: {f}",
.{input},
);
},
else => log.warn(
- "ignoring unimplemented CSI t with intermediates: {s}",
+ "ignoring unimplemented CSI t with intermediates: {f}",
.{input},
),
},
@@ -1382,7 +1382,7 @@ pub fn Stream(comptime Handler: type) type {
0 => if (@hasDecl(T, "restoreCursor"))
try self.handler.restoreCursor()
else
- log.warn("unimplemented CSI callback: {}", .{input}),
+ log.warn("unimplemented CSI callback: {f}", .{input}),
// Kitty keyboard protocol
1 => switch (input.intermediates[0]) {
@@ -1393,7 +1393,7 @@ pub fn Stream(comptime Handler: type) type {
'>' => if (@hasDecl(T, "pushKittyKeyboard")) push: {
const flags: u5 = if (input.params.len == 1)
std.math.cast(u5, input.params[0]) orelse {
- log.warn("invalid pushKittyKeyboard command: {}", .{input});
+ log.warn("invalid pushKittyKeyboard command: {f}", .{input});
break :push;
}
else
@@ -1414,7 +1414,7 @@ pub fn Stream(comptime Handler: type) type {
'=' => if (@hasDecl(T, "setKittyKeyboard")) set: {
const flags: u5 = if (input.params.len >= 1)
std.math.cast(u5, input.params[0]) orelse {
- log.warn("invalid setKittyKeyboard command: {}", .{input});
+ log.warn("invalid setKittyKeyboard command: {f}", .{input});
break :set;
}
else
@@ -1430,7 +1430,7 @@ pub fn Stream(comptime Handler: type) type {
2 => .@"or",
3 => .not,
else => {
- log.warn("invalid setKittyKeyboard command: {}", .{input});
+ log.warn("invalid setKittyKeyboard command: {f}", .{input});
break :set;
},
};
@@ -1442,13 +1442,13 @@ pub fn Stream(comptime Handler: type) type {
},
else => log.warn(
- "unknown CSI s with intermediate: {}",
+ "unknown CSI s with intermediate: {f}",
.{input},
),
},
else => log.warn(
- "ignoring unimplemented CSI u: {}",
+ "ignoring unimplemented CSI u: {f}",
.{input},
),
},
@@ -1458,11 +1458,11 @@ pub fn Stream(comptime Handler: type) type {
0 => if (@hasDecl(T, "insertBlanks")) switch (input.params.len) {
0 => try self.handler.insertBlanks(1),
1 => try self.handler.insertBlanks(input.params[0]),
- else => log.warn("invalid ICH command: {}", .{input}),
- } else log.warn("unimplemented CSI callback: {}", .{input}),
+ else => log.warn("invalid ICH command: {f}", .{input}),
+ } else log.warn("unimplemented CSI callback: {f}", .{input}),
else => log.warn(
- "ignoring unimplemented CSI @: {}",
+ "ignoring unimplemented CSI @: {f}",
.{input},
),
},
@@ -1487,13 +1487,13 @@ pub fn Stream(comptime Handler: type) type {
break :decsasd true;
};
- if (!success) log.warn("unimplemented CSI callback: {}", .{input});
+ if (!success) log.warn("unimplemented CSI callback: {f}", .{input});
},
else => if (@hasDecl(T, "csiUnimplemented"))
try self.handler.csiUnimplemented(input)
else
- log.warn("unimplemented CSI action: {}", .{input}),
+ log.warn("unimplemented CSI action: {f}", .{input}),
}
}
@@ -1690,10 +1690,10 @@ pub fn Stream(comptime Handler: type) type {
'7' => if (@hasDecl(T, "saveCursor")) switch (action.intermediates.len) {
0 => try self.handler.saveCursor(),
else => {
- log.warn("invalid command: {}", .{action});
+ log.warn("invalid command: {f}", .{action});
return;
},
- } else log.warn("unimplemented ESC callback: {}", .{action}),
+ } else log.warn("unimplemented ESC callback: {f}", .{action}),
'8' => blk: {
switch (action.intermediates.len) {
@@ -1701,14 +1701,14 @@ pub fn Stream(comptime Handler: type) type {
0 => if (@hasDecl(T, "restoreCursor")) {
try self.handler.restoreCursor();
break :blk {};
- } else log.warn("unimplemented restore cursor callback: {}", .{action}),
+ } else log.warn("unimplemented restore cursor callback: {f}", .{action}),
1 => switch (action.intermediates[0]) {
// DECALN - Fill Screen with E
'#' => if (@hasDecl(T, "decaln")) {
try self.handler.decaln();
break :blk {};
- } else log.warn("unimplemented ESC callback: {}", .{action}),
+ } else log.warn("unimplemented ESC callback: {f}", .{action}),
else => {},
},
@@ -1716,146 +1716,146 @@ pub fn Stream(comptime Handler: type) type {
else => {}, // fall through
}
- log.warn("unimplemented ESC action: {}", .{action});
+ log.warn("unimplemented ESC action: {f}", .{action});
},
// IND - Index
'D' => if (@hasDecl(T, "index")) switch (action.intermediates.len) {
0 => try self.handler.index(),
else => {
- log.warn("invalid index command: {}", .{action});
+ log.warn("invalid index command: {f}", .{action});
return;
},
- } else log.warn("unimplemented ESC callback: {}", .{action}),
+ } else log.warn("unimplemented ESC callback: {f}", .{action}),
// NEL - Next Line
'E' => if (@hasDecl(T, "nextLine")) switch (action.intermediates.len) {
0 => try self.handler.nextLine(),
else => {
- log.warn("invalid next line command: {}", .{action});
+ log.warn("invalid next line command: {f}", .{action});
return;
},
- } else log.warn("unimplemented ESC callback: {}", .{action}),
+ } else log.warn("unimplemented ESC callback: {f}", .{action}),
// HTS - Horizontal Tab Set
'H' => if (@hasDecl(T, "tabSet")) switch (action.intermediates.len) {
0 => try self.handler.tabSet(),
else => {
- log.warn("invalid tab set command: {}", .{action});
+ log.warn("invalid tab set command: {f}", .{action});
return;
},
- } else log.warn("unimplemented tab set callback: {}", .{action}),
+ } else log.warn("unimplemented tab set callback: {f}", .{action}),
// RI - Reverse Index
'M' => if (@hasDecl(T, "reverseIndex")) switch (action.intermediates.len) {
0 => try self.handler.reverseIndex(),
else => {
- log.warn("invalid reverse index command: {}", .{action});
+ log.warn("invalid reverse index command: {f}", .{action});
return;
},
- } else log.warn("unimplemented ESC callback: {}", .{action}),
+ } else log.warn("unimplemented ESC callback: {f}", .{action}),
// SS2 - Single Shift 2
'N' => if (@hasDecl(T, "invokeCharset")) switch (action.intermediates.len) {
0 => try self.handler.invokeCharset(.GL, .G2, true),
else => {
- log.warn("invalid single shift 2 command: {}", .{action});
+ log.warn("invalid single shift 2 command: {f}", .{action});
return;
},
- } else log.warn("unimplemented invokeCharset: {}", .{action}),
+ } else log.warn("unimplemented invokeCharset: {f}", .{action}),
// SS3 - Single Shift 3
'O' => if (@hasDecl(T, "invokeCharset")) switch (action.intermediates.len) {
0 => try self.handler.invokeCharset(.GL, .G3, true),
else => {
- log.warn("invalid single shift 3 command: {}", .{action});
+ log.warn("invalid single shift 3 command: {f}", .{action});
return;
},
- } else log.warn("unimplemented invokeCharset: {}", .{action}),
+ } else log.warn("unimplemented invokeCharset: {f}", .{action}),
// SPA - Start of Guarded Area
'V' => if (@hasDecl(T, "setProtectedMode") and action.intermediates.len == 0) {
try self.handler.setProtectedMode(ansi.ProtectedMode.iso);
- } else log.warn("unimplemented ESC callback: {}", .{action}),
+ } else log.warn("unimplemented ESC callback: {f}", .{action}),
// EPA - End of Guarded Area
'W' => if (@hasDecl(T, "setProtectedMode") and action.intermediates.len == 0) {
try self.handler.setProtectedMode(ansi.ProtectedMode.off);
- } else log.warn("unimplemented ESC callback: {}", .{action}),
+ } else log.warn("unimplemented ESC callback: {f}", .{action}),
// DECID
'Z' => if (@hasDecl(T, "deviceAttributes") and action.intermediates.len == 0) {
try self.handler.deviceAttributes(.primary, &.{});
- } else log.warn("unimplemented ESC callback: {}", .{action}),
+ } else log.warn("unimplemented ESC callback: {f}", .{action}),
// RIS - Full Reset
'c' => if (@hasDecl(T, "fullReset")) switch (action.intermediates.len) {
0 => try self.handler.fullReset(),
else => {
- log.warn("invalid full reset command: {}", .{action});
+ log.warn("invalid full reset command: {f}", .{action});
return;
},
- } else log.warn("unimplemented ESC callback: {}", .{action}),
+ } else log.warn("unimplemented ESC callback: {f}", .{action}),
// LS2 - Locking Shift 2
'n' => if (@hasDecl(T, "invokeCharset")) switch (action.intermediates.len) {
0 => try self.handler.invokeCharset(.GL, .G2, false),
else => {
- log.warn("invalid single shift 2 command: {}", .{action});
+ log.warn("invalid single shift 2 command: {f}", .{action});
return;
},
- } else log.warn("unimplemented invokeCharset: {}", .{action}),
+ } else log.warn("unimplemented invokeCharset: {f}", .{action}),
// LS3 - Locking Shift 3
'o' => if (@hasDecl(T, "invokeCharset")) switch (action.intermediates.len) {
0 => try self.handler.invokeCharset(.GL, .G3, false),
else => {
- log.warn("invalid single shift 3 command: {}", .{action});
+ log.warn("invalid single shift 3 command: {f}", .{action});
return;
},
- } else log.warn("unimplemented invokeCharset: {}", .{action}),
+ } else log.warn("unimplemented invokeCharset: {f}", .{action}),
// LS1R - Locking Shift 1 Right
'~' => if (@hasDecl(T, "invokeCharset")) switch (action.intermediates.len) {
0 => try self.handler.invokeCharset(.GR, .G1, false),
else => {
- log.warn("invalid locking shift 1 right command: {}", .{action});
+ log.warn("invalid locking shift 1 right command: {f}", .{action});
return;
},
- } else log.warn("unimplemented invokeCharset: {}", .{action}),
+ } else log.warn("unimplemented invokeCharset: {f}", .{action}),
// LS2R - Locking Shift 2 Right
'}' => if (@hasDecl(T, "invokeCharset")) switch (action.intermediates.len) {
0 => try self.handler.invokeCharset(.GR, .G2, false),
else => {
- log.warn("invalid locking shift 2 right command: {}", .{action});
+ log.warn("invalid locking shift 2 right command: {f}", .{action});
return;
},
- } else log.warn("unimplemented invokeCharset: {}", .{action}),
+ } else log.warn("unimplemented invokeCharset: {f}", .{action}),
// LS3R - Locking Shift 3 Right
'|' => if (@hasDecl(T, "invokeCharset")) switch (action.intermediates.len) {
0 => try self.handler.invokeCharset(.GR, .G3, false),
else => {
- log.warn("invalid locking shift 3 right command: {}", .{action});
+ log.warn("invalid locking shift 3 right command: {f}", .{action});
return;
},
- } else log.warn("unimplemented invokeCharset: {}", .{action}),
+ } else log.warn("unimplemented invokeCharset: {f}", .{action}),
// Set application keypad mode
'=' => if (@hasDecl(T, "setMode") and action.intermediates.len == 0) {
try self.handler.setMode(.keypad_keys, true);
- } else log.warn("unimplemented setMode: {}", .{action}),
+ } else log.warn("unimplemented setMode: {f}", .{action}),
// Reset application keypad mode
'>' => if (@hasDecl(T, "setMode") and action.intermediates.len == 0) {
try self.handler.setMode(.keypad_keys, false);
- } else log.warn("unimplemented setMode: {}", .{action}),
+ } else log.warn("unimplemented setMode: {f}", .{action}),
else => if (@hasDecl(T, "escUnimplemented"))
try self.handler.escUnimplemented(action)
else
- log.warn("unimplemented ESC action: {}", .{action}),
+ log.warn("unimplemented ESC action: {f}", .{action}),
// Sets ST (string terminator). We don't have to do anything
// because our parser always accepts ST.
diff --git a/src/terminal/style.zig b/src/terminal/style.zig
index 4f51cbc71..eac577a53 100644
--- a/src/terminal/style.zig
+++ b/src/terminal/style.zig
@@ -60,7 +60,7 @@ pub const Style = struct {
self: Color,
comptime fmt: []const u8,
options: std.fmt.FormatOptions,
- writer: anytype,
+ writer: *std.Io.Writer,
) !void {
_ = fmt;
_ = options;
@@ -228,7 +228,7 @@ pub const Style = struct {
self: Style,
comptime fmt: []const u8,
options: std.fmt.FormatOptions,
- writer: anytype,
+ writer: *std.Io.Writer,
) !void {
_ = fmt;
_ = options;
diff --git a/src/terminal/tmux.zig b/src/terminal/tmux.zig
index 1ea9f8c39..67c5a979c 100644
--- a/src/terminal/tmux.zig
+++ b/src/terminal/tmux.zig
@@ -17,7 +17,7 @@ pub const Client = struct {
state: State = .idle,
/// The buffer used to store in-progress notifications, output, etc.
- buffer: std.ArrayList(u8),
+ buffer: std.Io.Writer.Allocating,
/// The maximum size in bytes of the buffer. This is used to limit
/// memory usage. If the buffer exceeds this size, the client will
@@ -49,7 +49,7 @@ pub const Client = struct {
// Handle a byte of input.
pub fn put(self: *Client, byte: u8) !?Notification {
- if (self.buffer.items.len >= self.max_bytes) {
+ if (self.buffer.written().len >= self.max_bytes) {
self.broken();
return error.OutOfMemory;
}
@@ -81,18 +81,19 @@ pub const Client = struct {
// If we're in a block then we accumulate until we see a newline
// and then we check to see if that line ended the block.
.block => if (byte == '\n') {
+ const written = self.buffer.written();
const idx = if (std.mem.lastIndexOfScalar(
u8,
- self.buffer.items,
+ written,
'\n',
)) |v| v + 1 else 0;
- const line = self.buffer.items[idx..];
+ const line = written[idx..];
if (std.mem.startsWith(u8, line, "%end") or
std.mem.startsWith(u8, line, "%error"))
{
const err = std.mem.startsWith(u8, line, "%error");
- const output = std.mem.trimRight(u8, self.buffer.items[0..idx], "\r\n");
+ const output = std.mem.trimRight(u8, written[0..idx], "\r\n");
// If it is an error then log it.
if (err) log.warn("tmux control mode error={s}", .{output});
@@ -107,7 +108,7 @@ pub const Client = struct {
},
}
- try self.buffer.append(byte);
+ try self.buffer.writer.writeByte(byte);
return null;
}
@@ -116,7 +117,7 @@ pub const Client = struct {
assert(self.state == .notification);
const line = line: {
- var line = self.buffer.items;
+ var line = self.buffer.written();
if (line[line.len - 1] == '\r') line = line[0 .. line.len - 1];
break :line line;
};
@@ -274,7 +275,7 @@ pub const Client = struct {
// Mark the tmux state as broken.
fn broken(self: *Client) void {
self.state = .broken;
- self.buffer.clearAndFree();
+ self.buffer.deinit();
}
};
@@ -313,7 +314,7 @@ test "tmux begin/end empty" {
const testing = std.testing;
const alloc = testing.allocator;
- var c: Client = .{ .buffer = std.ArrayList(u8).init(alloc) };
+ var c: Client = .{ .buffer = .init(alloc) };
defer c.deinit();
for ("%begin 1578922740 269 1\n") |byte| try testing.expect(try c.put(byte) == null);
for ("%end 1578922740 269 1") |byte| try testing.expect(try c.put(byte) == null);
@@ -326,7 +327,7 @@ test "tmux begin/error empty" {
const testing = std.testing;
const alloc = testing.allocator;
- var c: Client = .{ .buffer = std.ArrayList(u8).init(alloc) };
+ var c: Client = .{ .buffer = .init(alloc) };
defer c.deinit();
for ("%begin 1578922740 269 1\n") |byte| try testing.expect(try c.put(byte) == null);
for ("%error 1578922740 269 1") |byte| try testing.expect(try c.put(byte) == null);
@@ -339,7 +340,7 @@ test "tmux begin/end data" {
const testing = std.testing;
const alloc = testing.allocator;
- var c: Client = .{ .buffer = std.ArrayList(u8).init(alloc) };
+ var c: Client = .{ .buffer = .init(alloc) };
defer c.deinit();
for ("%begin 1578922740 269 1\n") |byte| try testing.expect(try c.put(byte) == null);
for ("hello\nworld\n") |byte| try testing.expect(try c.put(byte) == null);
@@ -353,7 +354,7 @@ test "tmux output" {
const testing = std.testing;
const alloc = testing.allocator;
- var c: Client = .{ .buffer = std.ArrayList(u8).init(alloc) };
+ var c: Client = .{ .buffer = .init(alloc) };
defer c.deinit();
for ("%output %42 foo bar baz") |byte| try testing.expect(try c.put(byte) == null);
const n = (try c.put('\n')).?;
@@ -366,7 +367,7 @@ test "tmux session-changed" {
const testing = std.testing;
const alloc = testing.allocator;
- var c: Client = .{ .buffer = std.ArrayList(u8).init(alloc) };
+ var c: Client = .{ .buffer = .init(alloc) };
defer c.deinit();
for ("%session-changed $42 foo") |byte| try testing.expect(try c.put(byte) == null);
const n = (try c.put('\n')).?;
@@ -379,7 +380,7 @@ test "tmux sessions-changed" {
const testing = std.testing;
const alloc = testing.allocator;
- var c: Client = .{ .buffer = std.ArrayList(u8).init(alloc) };
+ var c: Client = .{ .buffer = .init(alloc) };
defer c.deinit();
for ("%sessions-changed") |byte| try testing.expect(try c.put(byte) == null);
const n = (try c.put('\n')).?;
@@ -390,7 +391,7 @@ test "tmux sessions-changed carriage return" {
const testing = std.testing;
const alloc = testing.allocator;
- var c: Client = .{ .buffer = std.ArrayList(u8).init(alloc) };
+ var c: Client = .{ .buffer = .init(alloc) };
defer c.deinit();
for ("%sessions-changed\r") |byte| try testing.expect(try c.put(byte) == null);
const n = (try c.put('\n')).?;
@@ -401,7 +402,7 @@ test "tmux window-add" {
const testing = std.testing;
const alloc = testing.allocator;
- var c: Client = .{ .buffer = std.ArrayList(u8).init(alloc) };
+ var c: Client = .{ .buffer = .init(alloc) };
defer c.deinit();
for ("%window-add @14") |byte| try testing.expect(try c.put(byte) == null);
const n = (try c.put('\n')).?;
@@ -413,7 +414,7 @@ test "tmux window-renamed" {
const testing = std.testing;
const alloc = testing.allocator;
- var c: Client = .{ .buffer = std.ArrayList(u8).init(alloc) };
+ var c: Client = .{ .buffer = .init(alloc) };
defer c.deinit();
for ("%window-renamed @42 bar") |byte| try testing.expect(try c.put(byte) == null);
const n = (try c.put('\n')).?;
diff --git a/src/terminfo/Source.zig b/src/terminfo/Source.zig
index 7692e6f54..91fee1ace 100644
--- a/src/terminfo/Source.zig
+++ b/src/terminfo/Source.zig
@@ -43,7 +43,7 @@ pub const Capability = struct {
/// Encode as a terminfo source file. The encoding is always done in a
/// human-readable format with whitespace. Fields are always written in the
/// order of the slices on this struct; this will not do any reordering.
-pub fn encode(self: Source, writer: anytype) !void {
+pub fn encode(self: Source, writer: *std.Io.Writer) !void {
// Encode the names in the order specified
for (self.names, 0..) |name, i| {
if (i != 0) try writer.writeAll("|");
@@ -115,9 +115,10 @@ pub fn xtgettcapMap(comptime self: Source) std.StaticStringMap([]const u8) {
},
.numeric => |v| numeric: {
var buf: [10]u8 = undefined;
- const num_len = std.fmt.formatIntBuf(&buf, v, 10, .upper, .{});
+ var writer: std.Io.Writer = .fixed(&buf);
+ writer.printInt(v, 10, .upper, .{}) catch unreachable;
const final = buf;
- break :numeric final[0..num_len];
+ break :numeric final[0..writer.end];
},
},
};
@@ -229,8 +230,8 @@ test "encode" {
// Encode
var buf: [1024]u8 = undefined;
- var buf_stream = std.io.fixedBufferStream(&buf);
- try src.encode(buf_stream.writer());
+ var writer: std.Io.Writer = .fixed(&buf);
+ try src.encode(&writer);
const expected =
"ghostty|xterm-ghostty|Ghostty,\n" ++
@@ -238,5 +239,5 @@ test "encode" {
"\tccc@,\n" ++
"\tcolors#256,\n" ++
"\tbel=^G,\n";
- try std.testing.expectEqualStrings(@as([]const u8, expected), buf_stream.getWritten());
+ try std.testing.expectEqualStrings(@as([]const u8, expected), writer.buffered());
}
diff --git a/src/terminfo/ghostty.zig b/src/terminfo/ghostty.zig
index f96154c9b..6451836e7 100644
--- a/src/terminfo/ghostty.zig
+++ b/src/terminfo/ghostty.zig
@@ -391,7 +391,7 @@ pub const ghostty: Source = .{
test "encode" {
// Encode
var buf: [1024 * 16]u8 = undefined;
- var buf_stream = std.io.fixedBufferStream(&buf);
- try ghostty.encode(buf_stream.writer());
- try std.testing.expect(buf_stream.getWritten().len > 0);
+ var writer: std.Io.Writer = .fixed(&buf);
+ try ghostty.encode(&writer);
+ try std.testing.expect(writer.buffered().len > 0);
}
diff --git a/src/termio/Exec.zig b/src/termio/Exec.zig
index 77fd2cc68..319ae0ee6 100644
--- a/src/termio/Exec.zig
+++ b/src/termio/Exec.zig
@@ -591,6 +591,17 @@ const Subprocess = struct {
flatpak_command: ?FlatpakHostCommand = null,
linux_cgroup: Command.LinuxCgroup = Command.linux_cgroup_default,
+ const ArgsFormatter = struct {
+ args: []const [:0]const u8,
+
+ pub fn format(this: @This(), writer: *std.Io.Writer) std.Io.Writer.Error!void {
+ for (this.args, 0..) |a, i| {
+ if (i > 0) try writer.writeAll(", ");
+ try writer.print("`{s}`", .{a});
+ }
+ }
+ };
+
/// Initialize the subprocess. This will NOT start it, this only sets
/// up the internal state necessary to start it later.
pub fn init(gpa: Allocator, cfg: Config) !Subprocess {
@@ -897,7 +908,7 @@ const Subprocess = struct {
self.pty = null;
};
- log.debug("starting command command={s}", .{self.args});
+ log.debug("starting command command={f}", .{ArgsFormatter{ .args = self.args }});
// If we can't access the cwd, then don't set any cwd and inherit.
// This is important because our cwd can be set by the shell (OSC 7)
@@ -960,7 +971,7 @@ const Subprocess = struct {
const pid = try cmd.spawn(alloc);
errdefer killCommandFlatpak(cmd);
- log.info("started subcommand on host via flatpak API path={s} pid={?}", .{
+ log.info("started subcommand on host via flatpak API path={s} pid={}", .{
self.args[0],
pid,
});
@@ -1157,7 +1168,7 @@ const Subprocess = struct {
const res = posix.waitpid(pid, std.c.W.NOHANG);
log.debug("waitpid result={}", .{res.pid});
if (res.pid != 0) break;
- std.time.sleep(10 * std.time.ns_per_ms);
+ std.Thread.sleep(10 * std.time.ns_per_ms);
}
},
}
@@ -1180,7 +1191,7 @@ const Subprocess = struct {
const pgid = c.getpgid(pid);
if (pgid == my_pgid) {
log.warn("pgid is our own, retrying", .{});
- std.time.sleep(10 * std.time.ns_per_ms);
+ std.Thread.sleep(10 * std.time.ns_per_ms);
continue;
}
@@ -1429,7 +1440,7 @@ fn execCommand(
// grow if necessary for a longer command (uncommon).
9,
);
- defer args.deinit();
+ defer args.deinit(alloc);
// The reason for executing login this way is unclear. This
// comment will attempt to explain but prepare for a truly
@@ -1476,40 +1487,41 @@ fn execCommand(
// macOS.
//
// Awesome.
- try args.append("/usr/bin/login");
- if (hush) try args.append("-q");
- try args.append("-flp");
- try args.append(username);
+ try args.append(alloc, "/usr/bin/login");
+ if (hush) try args.append(alloc, "-q");
+ try args.append(alloc, "-flp");
+ try args.append(alloc, username);
switch (command) {
// Direct args can be passed directly to login, since
// login uses execvp we don't need to worry about PATH
// searching.
- .direct => |v| try args.appendSlice(v),
+ .direct => |v| try args.appendSlice(alloc, v),
.shell => |v| {
// Use "exec" to replace the bash process with
// our intended command so we don't have a parent
// process hanging around.
- const cmd = try std.fmt.allocPrintZ(
+ const cmd = try std.fmt.allocPrintSentinel(
alloc,
"exec -l {s}",
.{v},
+ 0,
);
// We execute bash with "--noprofile --norc" so that it doesn't
// load startup files so that (1) our shell integration doesn't
// break and (2) user configuration doesn't mess this process
// up.
- try args.append("/bin/bash");
- try args.append("--noprofile");
- try args.append("--norc");
- try args.append("-c");
- try args.append(cmd);
+ try args.append(alloc, "/bin/bash");
+ try args.append(alloc, "--noprofile");
+ try args.append(alloc, "--norc");
+ try args.append(alloc, "-c");
+ try args.append(alloc, cmd);
},
}
- return try args.toOwnedSlice();
+ return try args.toOwnedSlice(alloc);
}
return switch (command) {
@@ -1518,7 +1530,7 @@ fn execCommand(
.shell => |v| shell: {
var args: std.ArrayList([:0]const u8) = try .initCapacity(alloc, 4);
- defer args.deinit();
+ defer args.deinit(alloc);
if (comptime builtin.os.tag == .windows) {
// We run our shell wrapped in `cmd.exe` so that we don't have
@@ -1539,21 +1551,21 @@ fn execCommand(
"cmd.exe",
});
- try args.append(cmd);
- try args.append("/C");
+ try args.append(alloc, cmd);
+ try args.append(alloc, "/C");
} else {
// We run our shell wrapped in `/bin/sh` so that we don't have
// to parse the command line ourselves if it has arguments.
// Additionally, some environments (NixOS, I found) use /bin/sh
// to setup some environment variables that are important to
// have set.
- try args.append("/bin/sh");
- if (internal_os.isFlatpak()) try args.append("-l");
- try args.append("-c");
+ try args.append(alloc, "/bin/sh");
+ if (internal_os.isFlatpak()) try args.append(alloc, "-l");
+ try args.append(alloc, "-c");
}
- try args.append(v);
- break :shell try args.toOwnedSlice();
+ try args.append(alloc, v);
+ break :shell try args.toOwnedSlice(alloc);
},
};
}
diff --git a/src/termio/shell_integration.zig b/src/termio/shell_integration.zig
index 90a697409..8b2648dbd 100644
--- a/src/termio/shell_integration.zig
+++ b/src/termio/shell_integration.zig
@@ -175,7 +175,9 @@ pub fn setupFeatures(
inline for (fields) |field| n += field.name.len;
break :capacity n;
};
- var buffer = try std.BoundedArray(u8, capacity).init(0);
+
+ var buf: [capacity]u8 = undefined;
+ var writer: std.Io.Writer = .fixed(&buf);
// Sort the fields so that the output is deterministic. This is
// done at comptime so it has no runtime cost
@@ -197,13 +199,13 @@ pub fn setupFeatures(
inline for (fields_sorted) |name| {
if (@field(features, name)) {
- if (buffer.len > 0) try buffer.append(',');
- try buffer.appendSlice(name);
+ if (writer.end > 0) try writer.writeByte(',');
+ try writer.writeAll(name);
}
}
- if (buffer.len > 0) {
- try env.put("GHOSTTY_SHELL_FEATURES", buffer.slice());
+ if (writer.end > 0) {
+ try env.put("GHOSTTY_SHELL_FEATURES", buf[0..writer.end]);
}
}
@@ -257,8 +259,8 @@ fn setupBash(
resource_dir: []const u8,
env: *EnvMap,
) !?config.Command {
- var args = try std.ArrayList([:0]const u8).initCapacity(alloc, 3);
- defer args.deinit();
+ var args: std.ArrayList([:0]const u8) = try .initCapacity(alloc, 3);
+ defer args.deinit(alloc);
// Iterator that yields each argument in the original command line.
// This will allocate once proportionate to the command line length.
@@ -267,21 +269,22 @@ fn setupBash(
// Start accumulating arguments with the executable and initial flags.
if (iter.next()) |exe| {
- try args.append(try alloc.dupeZ(u8, exe));
+ try args.append(alloc, try alloc.dupeZ(u8, exe));
} else return null;
- try args.append("--posix");
+ try args.append(alloc, "--posix");
// On macOS, we request a login shell to match that platform's norms.
if (comptime builtin.target.os.tag.isDarwin()) {
- try args.append("--login");
+ try args.append(alloc, "--login");
}
// Stores the list of intercepted command line flags that will be passed
// to our shell integration script: --norc --noprofile
// We always include at least "1" so the script can differentiate between
// being manually sourced or automatically injected (from here).
- var inject = try std.BoundedArray(u8, 32).init(0);
- try inject.appendSlice("1");
+ var buf: [32]u8 = undefined;
+ var inject: std.Io.Writer = .fixed(&buf);
+ try inject.writeAll("1");
// Walk through the rest of the given arguments. If we see an option that
// would require complex or unsupported integration behavior, we bail out
@@ -296,9 +299,9 @@ fn setupBash(
if (std.mem.eql(u8, arg, "--posix")) {
return null;
} else if (std.mem.eql(u8, arg, "--norc")) {
- try inject.appendSlice(" --norc");
+ try inject.writeAll(" --norc");
} else if (std.mem.eql(u8, arg, "--noprofile")) {
- try inject.appendSlice(" --noprofile");
+ try inject.writeAll(" --noprofile");
} else if (std.mem.eql(u8, arg, "--rcfile") or std.mem.eql(u8, arg, "--init-file")) {
rcfile = iter.next();
} else if (arg.len > 1 and arg[0] == '-' and arg[1] != '-') {
@@ -306,20 +309,20 @@ fn setupBash(
if (std.mem.indexOfScalar(u8, arg, 'c') != null) {
return null;
}
- try args.append(try alloc.dupeZ(u8, arg));
+ try args.append(alloc, try alloc.dupeZ(u8, arg));
} else if (std.mem.eql(u8, arg, "-") or std.mem.eql(u8, arg, "--")) {
// All remaining arguments should be passed directly to the shell
// command. We shouldn't perform any further option processing.
- try args.append(try alloc.dupeZ(u8, arg));
+ try args.append(alloc, try alloc.dupeZ(u8, arg));
while (iter.next()) |remaining_arg| {
- try args.append(try alloc.dupeZ(u8, remaining_arg));
+ try args.append(alloc, try alloc.dupeZ(u8, remaining_arg));
}
break;
} else {
- try args.append(try alloc.dupeZ(u8, arg));
+ try args.append(alloc, try alloc.dupeZ(u8, arg));
}
}
- try env.put("GHOSTTY_BASH_INJECT", inject.slice());
+ try env.put("GHOSTTY_BASH_INJECT", buf[0..inject.end]);
if (rcfile) |v| {
try env.put("GHOSTTY_BASH_RCFILE", v);
}
@@ -356,7 +359,7 @@ fn setupBash(
// Since we built up a command line, we don't need to wrap it in
// ANOTHER shell anymore and can do a direct command.
- return .{ .direct = try args.toOwnedSlice() };
+ return .{ .direct = try args.toOwnedSlice(alloc) };
}
test "bash" {
diff --git a/src/termio/stream_handler.zig b/src/termio/stream_handler.zig
index 9a7e8b416..06ff29809 100644
--- a/src/termio/stream_handler.zig
+++ b/src/termio/stream_handler.zig
@@ -310,11 +310,11 @@ pub const StreamHandler = struct {
.kitty => |*kitty_cmd| {
if (self.terminal.kittyGraphics(self.alloc, kitty_cmd)) |resp| {
var buf: [1024]u8 = undefined;
- var buf_stream = std.io.fixedBufferStream(&buf);
- try resp.encode(buf_stream.writer());
- const final = buf_stream.getWritten();
+ var writer: std.Io.Writer = .fixed(&buf);
+ try resp.encode(&writer);
+ const final = writer.buffered();
if (final.len > 2) {
- log.debug("kitty graphics response: {s}", .{std.fmt.fmtSliceHexLower(final)});
+ log.debug("kitty graphics response: {x}", .{final});
self.messageWriter(try termio.Message.writeReq(self.alloc, final));
}
}
@@ -1141,7 +1141,7 @@ pub const StreamHandler = struct {
// We need to unescape the path. We first try to unescape onto
// the stack and fall back to heap allocation if we have to.
- var pathBuf: [1024]u8 = undefined;
+ var path_buf: [1024]u8 = undefined;
const path, const heap = path: {
// Get the raw string of the URI. Its unclear to me if the various
// tags of this enum guarantee no percent-encoding so we just
@@ -1156,15 +1156,16 @@ pub const StreamHandler = struct {
break :path .{ path, false };
// First try to stack-allocate
- var fba = std.heap.FixedBufferAllocator.init(&pathBuf);
- if (std.fmt.allocPrint(fba.allocator(), "{raw}", .{uri.path})) |v|
- break :path .{ v, false }
- else |_| {}
+ var stack_writer: std.Io.Writer = .fixed(&path_buf);
+ if (uri.path.formatRaw(&stack_writer)) |_| {
+ break :path .{ stack_writer.buffered(), false };
+ } else |_| {}
// Fall back to heap
- if (std.fmt.allocPrint(self.alloc, "{raw}", .{uri.path})) |v|
- break :path .{ v, true }
- else |_| {}
+ var alloc_writer: std.Io.Writer.Allocating = .init(self.alloc);
+ if (uri.path.formatRaw(&alloc_writer.writer)) |_| {
+ break :path .{ alloc_writer.written(), true };
+ } else |_| {}
// Fall back to using it directly...
log.warn("failed to unescape OSC 7 path, using it directly path={s}", .{path});
@@ -1471,15 +1472,15 @@ pub const StreamHandler = struct {
self: *StreamHandler,
request: terminal.kitty.color.OSC,
) !void {
- var buf = std.ArrayList(u8).init(self.alloc);
- defer buf.deinit();
- const writer = buf.writer();
+ var stream: std.Io.Writer.Allocating = .init(self.alloc);
+ defer stream.deinit();
+ const writer = &stream.writer;
for (request.list.items) |item| {
switch (item) {
.query => |key| {
// If the writer buffer is empty, we need to write our prefix
- if (buf.items.len == 0) try writer.writeAll("\x1b]21");
+ if (stream.written().len == 0) try writer.writeAll("\x1b]21");
const color: terminal.color.RGB = switch (key) {
.palette => |palette| self.terminal.color_palette.colors[palette],
@@ -1488,17 +1489,17 @@ pub const StreamHandler = struct {
.background => self.background_color orelse self.default_background_color,
.cursor => self.cursor_color orelse self.default_cursor_color,
else => {
- log.warn("ignoring unsupported kitty color protocol key: {}", .{key});
+ log.warn("ignoring unsupported kitty color protocol key: {f}", .{key});
continue;
},
},
} orelse {
- try writer.print(";{}=", .{key});
+ try writer.print(";{f}=", .{key});
continue;
};
try writer.print(
- ";{}=rgb:{x:0>2}/{x:0>2}/{x:0>2}",
+ ";{f}=rgb:{x:0>2}/{x:0>2}/{x:0>2}",
.{ key, color.r, color.g, color.b },
);
},
@@ -1525,7 +1526,7 @@ pub const StreamHandler = struct {
},
else => {
log.warn(
- "ignoring unsupported kitty color protocol key: {}",
+ "ignoring unsupported kitty color protocol key: {f}",
.{v.key},
);
continue;
@@ -1560,7 +1561,7 @@ pub const StreamHandler = struct {
},
else => {
log.warn(
- "ignoring unsupported kitty color protocol key: {}",
+ "ignoring unsupported kitty color protocol key: {f}",
.{key},
);
continue;
@@ -1576,12 +1577,12 @@ pub const StreamHandler = struct {
}
// If we had any writes to our buffer, we queue them now
- if (buf.items.len > 0) {
+ if (stream.written().len > 0) {
try writer.writeAll(request.terminator.string());
self.messageWriter(.{
.write_alloc = .{
.alloc = self.alloc,
- .data = try buf.toOwnedSlice(),
+ .data = try stream.toOwnedSlice(),
},
});
}
diff --git a/src/unicode/Properties.zig b/src/unicode/Properties.zig
index b7840743a..c8c4a581c 100644
--- a/src/unicode/Properties.zig
+++ b/src/unicode/Properties.zig
@@ -24,13 +24,9 @@ pub fn eql(a: Properties, b: Properties) bool {
// Needed for lut.Generator
pub fn format(
self: Properties,
- comptime layout: []const u8,
- opts: std.fmt.FormatOptions,
- writer: anytype,
+ writer: *std.Io.Writer,
) !void {
- _ = layout;
- _ = opts;
- try std.fmt.format(writer,
+ try writer.print(
\\.{{
\\ .width= {},
\\ .grapheme_boundary_class= .{s},
diff --git a/src/unicode/lut.zig b/src/unicode/lut.zig
index e10c5c0b8..da90f1ee7 100644
--- a/src/unicode/lut.zig
+++ b/src/unicode/lut.zig
@@ -54,12 +54,14 @@ pub fn Generator(
defer blocks_map.deinit();
// Our stages
- var stage1 = std.ArrayList(u16).init(alloc);
- defer stage1.deinit();
- var stage2 = std.ArrayList(u16).init(alloc);
- defer stage2.deinit();
- var stage3 = std.ArrayList(Elem).init(alloc);
- defer stage3.deinit();
+ var stage1: std.ArrayList(u16) = .empty;
+ var stage2: std.ArrayList(u16) = .empty;
+ var stage3: std.ArrayList(Elem) = .empty;
+ defer {
+ stage1.deinit(alloc);
+ stage2.deinit(alloc);
+ stage3.deinit(alloc);
+ }
var block: Block = undefined;
var block_len: u16 = 0;
@@ -74,7 +76,7 @@ pub fn Generator(
}
const idx = stage3.items.len;
- try stage3.append(elem);
+ try stage3.append(alloc, elem);
break :block_idx idx;
};
@@ -96,11 +98,11 @@ pub fn Generator(
u16,
stage2.items.len,
) orelse return error.Stage2TooLarge;
- for (block[0..block_len]) |entry| try stage2.append(entry);
+ for (block[0..block_len]) |entry| try stage2.append(alloc, entry);
}
// Map stage1 => stage2 and reset our block
- try stage1.append(gop.value_ptr.*);
+ try stage1.append(alloc, gop.value_ptr.*);
block_len = 0;
}
@@ -109,11 +111,11 @@ pub fn Generator(
assert(stage2.items.len <= std.math.maxInt(u16));
assert(stage3.items.len <= std.math.maxInt(u16));
- const stage1_owned = try stage1.toOwnedSlice();
+ const stage1_owned = try stage1.toOwnedSlice(alloc);
errdefer alloc.free(stage1_owned);
- const stage2_owned = try stage2.toOwnedSlice();
+ const stage2_owned = try stage2.toOwnedSlice(alloc);
errdefer alloc.free(stage2_owned);
- const stage3_owned = try stage3.toOwnedSlice();
+ const stage3_owned = try stage3.toOwnedSlice(alloc);
errdefer alloc.free(stage3_owned);
return .{
@@ -145,7 +147,7 @@ pub fn Tables(comptime Elem: type) type {
/// Writes the lookup table as Zig to the given writer. The
/// written file exports three constants: stage1, stage2, and
/// stage3. These can be used to rebuild the lookup table in Zig.
- pub fn writeZig(self: *const Self, writer: anytype) !void {
+ pub fn writeZig(self: *const Self, writer: *std.Io.Writer) !void {
try writer.print(
\\//! This file is auto-generated. Do not edit.
\\
@@ -168,7 +170,13 @@ pub fn Tables(comptime Elem: type) type {
\\
\\pub const stage3: [{}]Elem = .{{
, .{self.stage3.len});
- for (self.stage3) |entry| try writer.print("{},", .{entry});
+ for (self.stage3) |entry| {
+ if (@typeInfo(@TypeOf(entry)) == .@"struct" and
+ @hasDecl(@TypeOf(entry), "format"))
+ try writer.print("{f},", .{entry})
+ else
+ try writer.print("{},", .{entry});
+ }
try writer.writeAll(
\\};
\\ };
diff --git a/src/unicode/props_uucode.zig b/src/unicode/props_uucode.zig
index ba0511ea4..6aed7d7d5 100644
--- a/src/unicode/props_uucode.zig
+++ b/src/unicode/props_uucode.zig
@@ -84,7 +84,11 @@ pub fn main() !void {
defer alloc.free(t.stage1);
defer alloc.free(t.stage2);
defer alloc.free(t.stage3);
- try t.writeZig(std.io.getStdOut().writer());
+
+ var buf: [4096]u8 = undefined;
+ var stdout = std.fs.File.stdout().writer(&buf);
+ try t.writeZig(&stdout.interface);
+ try stdout.end();
// Uncomment when manually debugging to see our table sizes.
// std.log.warn("stage1={} stage2={} stage3={}", .{
diff --git a/src/unicode/symbols_uucode.zig b/src/unicode/symbols_uucode.zig
index 3da019e81..8cbd59211 100644
--- a/src/unicode/symbols_uucode.zig
+++ b/src/unicode/symbols_uucode.zig
@@ -30,7 +30,11 @@ pub fn main() !void {
defer alloc.free(t.stage1);
defer alloc.free(t.stage2);
defer alloc.free(t.stage3);
- try t.writeZig(std.io.getStdOut().writer());
+
+ var buf: [4096]u8 = undefined;
+ var stdout = std.fs.File.stdout().writer(&buf);
+ try t.writeZig(&stdout.interface);
+ try stdout.end();
// Uncomment when manually debugging to see our table sizes.
// std.log.warn("stage1={} stage2={} stage3={}", .{