mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-14 15:56:13 +03:00
termio/exec: use message to writer thread so we can output failed cmd
This commit is contained in:
@ -544,6 +544,56 @@ pub fn jumpToPrompt(self: *Exec, delta: isize) !void {
|
||||
}
|
||||
}
|
||||
|
||||
/// Called when the child process exited abnormally but before
|
||||
/// the surface is notified.
|
||||
pub fn childExitedAbnormally(self: *Exec) !void {
|
||||
// Build up our command for the error message
|
||||
const command = try std.mem.join(
|
||||
self.alloc,
|
||||
" ",
|
||||
self.subprocess.args,
|
||||
);
|
||||
defer self.alloc.free(command);
|
||||
|
||||
// Build our error message. Do this outside of the renderer lock.
|
||||
var msg = std.ArrayList(u8).init(self.alloc);
|
||||
defer msg.deinit();
|
||||
var writer = msg.writer();
|
||||
try writer.print(
|
||||
\\Ghostty failed to launch the requested command.
|
||||
\\Please check your "command" configuration.
|
||||
\\
|
||||
\\Command: {s}
|
||||
\\
|
||||
\\Press any key to close this window.
|
||||
, .{command});
|
||||
|
||||
// Modify the terminal to show our error message. This
|
||||
// requires grabbing the renderer state lock.
|
||||
self.renderer_state.mutex.lock();
|
||||
defer self.renderer_state.mutex.unlock();
|
||||
const t = self.renderer_state.terminal;
|
||||
|
||||
// Reset the terminal completely.
|
||||
// NOTE: The error output is in the terminal at this point. In the
|
||||
// future, we can make an even better error message by scrolling,
|
||||
// writing at the bottom, etc.
|
||||
t.fullReset(self.alloc);
|
||||
|
||||
// Write our message out.
|
||||
const view = try std.unicode.Utf8View.init(msg.items);
|
||||
var it = view.iterator();
|
||||
while (it.nextCodepoint()) |cp| {
|
||||
if (cp == '\n') {
|
||||
t.carriageReturn();
|
||||
try t.linefeed();
|
||||
continue;
|
||||
}
|
||||
|
||||
try t.print(cp);
|
||||
}
|
||||
}
|
||||
|
||||
pub inline fn queueWrite(self: *Exec, data: []const u8, linefeed: bool) !void {
|
||||
const ev = self.data.?;
|
||||
|
||||
@ -757,40 +807,12 @@ fn processExit(
|
||||
if (runtime > abnormal_runtime_threshold_ms) break :runtime;
|
||||
log.warn("abnormal process exit detected, showing error message", .{});
|
||||
|
||||
// Build our error message. Do this outside of the renderer lock.
|
||||
const alloc = ev.terminal_stream.handler.alloc;
|
||||
var msg = std.ArrayList(u8).init(alloc);
|
||||
defer msg.deinit();
|
||||
var writer = msg.writer();
|
||||
writer.writeAll(
|
||||
\\ Ghostty failed to launch the requested command.
|
||||
\\ Please check your "command" configuration.
|
||||
\\
|
||||
\\ Press any key to close this window.
|
||||
) catch break :runtime;
|
||||
|
||||
// Modify the terminal to show our error message. This
|
||||
// requires grabbing the renderer state lock.
|
||||
ev.renderer_state.mutex.lock();
|
||||
defer ev.renderer_state.mutex.unlock();
|
||||
const t = ev.renderer_state.terminal;
|
||||
|
||||
// Reset the terminal completely.
|
||||
t.fullReset(alloc);
|
||||
|
||||
// Write our message out.
|
||||
const view = std.unicode.Utf8View.init(msg.items) catch
|
||||
break :runtime;
|
||||
var it = view.iterator();
|
||||
while (it.nextCodepoint()) |cp| {
|
||||
if (cp == '\n') {
|
||||
t.carriageReturn();
|
||||
t.linefeed() catch break :runtime;
|
||||
continue;
|
||||
}
|
||||
|
||||
t.print(cp) catch break :runtime;
|
||||
}
|
||||
// Notify our main writer thread which has access to more
|
||||
// information so it can show a better error message.
|
||||
_ = ev.writer_mailbox.push(.{
|
||||
.child_exited_abnormally = {},
|
||||
}, .{ .forever = {} });
|
||||
ev.writer_wakeup.notify() catch break :runtime;
|
||||
|
||||
return .disarm;
|
||||
}
|
||||
|
@ -186,6 +186,7 @@ fn drainMailbox(self: *Thread) !void {
|
||||
.jump_to_prompt => |v| try self.impl.jumpToPrompt(v),
|
||||
.start_synchronized_output => self.startSynchronizedOutput(),
|
||||
.linefeed_mode => |v| self.flags.linefeed_mode = v,
|
||||
.child_exited_abnormally => try self.impl.childExitedAbnormally(),
|
||||
.write_small => |v| try self.impl.queueWrite(v.data[0..v.len], self.flags.linefeed_mode),
|
||||
.write_stable => |v| try self.impl.queueWrite(v, self.flags.linefeed_mode),
|
||||
.write_alloc => |v| {
|
||||
|
@ -62,6 +62,12 @@ pub const Message = union(enum) {
|
||||
/// Enable or disable linefeed mode (mode 20).
|
||||
linefeed_mode: bool,
|
||||
|
||||
/// The child exited abnormally. The termio state is marked
|
||||
/// as process exited but the surface hasn't been notified to
|
||||
/// close because termio can use this to update the terminal
|
||||
/// with an error message.
|
||||
child_exited_abnormally: void,
|
||||
|
||||
/// Write where the data fits in the union.
|
||||
write_small: WriteReq.Small,
|
||||
|
||||
|
Reference in New Issue
Block a user