diff --git a/src/Surface.zig b/src/Surface.zig index 3b4bf872f..686647a67 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(); @@ -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/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/gresource.zig b/src/apprt/gtk/build/gresource.zig index 7adcd3e44..fabd5763e 100644 --- a/src/apprt/gtk/build/gresource.zig +++ b/src/apprt/gtk/build/gresource.zig @@ -166,7 +166,7 @@ pub fn main() !void { /// 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( \\ \\ @@ -208,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( \\ \\ @@ -240,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/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/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/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 d49885256..20b8b5cba 100644 --- a/src/apprt/gtk/class/surface.zig +++ b/src/apprt/gtk/class/surface.zig @@ -2117,13 +2117,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 +2149,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 +2162,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 +2176,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/tab.zig b/src/apprt/gtk/class/tab.zig index 26b006bb6..941fa00a9 100644 --- a/src/apprt/gtk/class/tab.zig +++ b/src/apprt/gtk/class/tab.zig @@ -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/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/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/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/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 ff85e820b..2c0192d03 100644 --- a/src/extra/vim.zig +++ b/src/extra/vim.zig @@ -72,7 +72,7 @@ fn comptimeGenSyntax() []const u8 { } /// 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/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/inspector/Inspector.zig b/src/inspector/Inspector.zig index d23510949..49b05bd7f 100644 --- a/src/inspector/Inspector.zig +++ b/src/inspector/Inspector.zig @@ -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, + }; + } - const Writer = std.io.Writer(*ShellEscapeWriter(T), error{Error}, write); + fn drain(w: *Writer, data: []const []const u8, splat: usize) Writer.Error!usize { + const self: *ShellEscapeWriter = @fieldParentPtr("writer", w); - pub fn init(child_writer: T) ShellEscapeWriter(T) { - return .{ .child_writer = child_writer }; - } + // 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); - pub fn writer(self: *ShellEscapeWriter(T)) Writer { - return .{ .context = self }; + 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; } - }; -} + } +}; 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/shadertoy.zig b/src/renderer/shadertoy.zig index a8f62cdea..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; }; diff --git a/src/synthetic/cli/Ascii.zig b/src/synthetic/cli/Ascii.zig index 25e5bb00b..14de5edb8 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 = .{ diff --git a/src/synthetic/cli/Osc.zig b/src/synthetic/cli/Osc.zig index 4792cda6b..8dd3d46ed 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", diff --git a/src/synthetic/cli/Utf8.zig b/src/synthetic/cli/Utf8.zig index 28a11f891..65437d1ae 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 = .{ diff --git a/src/terminal/PageList.zig b/src/terminal/PageList.zig index 2f6864784..9bf116598 100644 --- a/src/terminal/PageList.zig +++ b/src/terminal/PageList.zig @@ -2723,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/Terminal.zig b/src/terminal/Terminal.zig index d15f2deb3..69bcbcb84 100644 --- a/src/terminal/Terminal.zig +++ b/src/terminal/Terminal.zig @@ -239,6 +239,11 @@ pub fn deinit(self: *Terminal, alloc: Allocator) void { 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/kitty/graphics_command.zig b/src/terminal/kitty/graphics_command.zig index 2ce01f83a..08b2e378a 100644 --- a/src/terminal/kitty/graphics_command.zig +++ b/src/terminal/kitty/graphics_command.zig @@ -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; diff --git a/src/terminal/osc.zig b/src/terminal/osc.zig index d244310bb..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()); } 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/terminfo/Source.zig b/src/terminfo/Source.zig index d5c3f427a..6a068c906 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("|"); diff --git a/src/termio/Exec.zig b/src/termio/Exec.zig index 8c729fddc..d822377c9 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) @@ -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; } 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(), }, }); }