Something went wrong. Try again.
A GPU terminal emulator for Wayland and Windows on libghostty-vt, drawing with Vulkan, running a program on a pty or a serial port.
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120// SPDX-FileCopyrightText: © 2026 Jeffrey C. Ollie <jeff@ocjtech.us>// SPDX-License-Identifier: MIT
//! Nothing on the other side but some text, already finished.//!//! What a window shows in place of a program that could not be started, so//! that the person who asked for it is told why rather than seeing nothing//! happen. The text is read and drawn as a program's output would be, and//! then it ends as a program's output would: on Linux it goes through a//! pipe; on Windows, where nothing waits on an anonymous pipe, it is kept//! here, with an event that is always set.
const std = @import("std");const builtin = @import("builtin");
const backend = @import("Backend.zig");const Size = backend.Size;const Handle = backend.Handle;
const Message = @This();
/// Linux: the pipe's read end, non-blocking; the write end is closed once/// the text is in. Windows: an event that is always set.handle_: Handle,/// Windows: the text not yet read. Owned.text: []u8 = &.{},read_to: usize = 0,gpa: ?std.mem.Allocator = null,
pub const Error = error{ SystemResources, OutOfMemory };
const windows = builtin.os.tag == .windows;const linux = std.os.linux;const win32 = if (windows) @import("win32").everything else struct {};
/// On Linux `text` must fit in a pipe's buffer: 64 KiB, and never less/// than 4 KiB. A message is a line or two.pub fn init(text: []const u8) Error!Message { if (windows) { const event = win32.CreateEventW(null, win32.TRUE, win32.TRUE, null) orelse return error.SystemResources; const gpa = std.heap.page_allocator; return .{ .handle_ = event, .text = try gpa.dupe(u8, text), .gpa = gpa }; } var fds: [2]linux.fd_t = undefined; if (linux.errno(linux.pipe2(&fds, .{ .NONBLOCK = true, .CLOEXEC = true })) != .SUCCESS) return error.SystemResources; defer _ = linux.close(fds[1]); var sent: usize = 0; while (sent < text.len) { const rc = linux.write(fds[1], text[sent..].ptr, text.len - sent); switch (linux.errno(rc)) { .SUCCESS => sent += rc, .INTR => continue, // Full: the rest is dropped rather than blocking. else => break, } } return .{ .handle_ = fds[0] };}
pub fn handle(m: *const Message) Handle { return m.handle_;}
pub fn waitHandles(m: *const Message, buf: *[backend.max_wait_handles]Handle) []const Handle { buf[0] = m.handle_; return buf[0..1];}
pub fn read(m: *Message, buf: []u8) backend.ReadError!usize { if (windows) { const n = @min(buf.len, m.text.len - m.read_to); @memcpy(buf[0..n], m.text[m.read_to..][0..n]); m.read_to += n; return n; } while (true) { const rc = linux.read(m.handle_, buf.ptr, buf.len); return switch (linux.errno(rc)) { .SUCCESS => rc, .INTR => continue, .AGAIN => error.WouldBlock, else => error.Unexpected, }; }}
/// There is no one to send anything to; what is typed goes nowhere.pub fn write(m: *Message, bytes: []const u8) backend.WriteError!usize { _ = m; return bytes.len;}
pub fn resize(m: *Message, size: Size) void { _ = m; _ = size;}
pub fn describe(m: *const Message, w: *std.Io.Writer) std.Io.Writer.Error!void { _ = m; try w.writeAll("harrier");}
pub fn deinit(m: *Message) void { if (windows) { _ = win32.CloseHandle(m.handle_); if (m.gpa) |gpa| gpa.free(m.text); return; } _ = linux.close(m.handle_);}
test "the text comes out, and then the end" { var m = try init("no such program\r\n"); defer m.deinit(); var buf: [64]u8 = undefined; const n = try m.read(&buf); try std.testing.expectEqualStrings("no such program\r\n", buf[0..n]); try std.testing.expectEqual(@as(usize, 0), try m.read(&buf));}