input: crash binding can configure which thread to crash

This commit is contained in:
Mitchell Hashimoto
2024-09-01 21:00:12 -07:00
parent 8f477b00da
commit d499f7795b
6 changed files with 45 additions and 7 deletions

View File

@ -3673,7 +3673,19 @@ pub fn performBindingAction(self: *Surface, action: input.Binding.Action) !bool
.quit => try self.app.setQuit(),
.crash => @panic("crash binding action, crashing intentionally"),
.crash => |location| switch (location) {
.main => @panic("crash binding action, crashing intentionally"),
.render => {
_ = self.renderer_thread.mailbox.push(.{ .crash = {} }, .{ .forever = {} });
self.queueRender() catch |err| {
// Not a big deal if this fails.
log.warn("failed to notify renderer of crash message err={}", .{err});
};
},
.io => self.io.queueMessage(.{ .crash = {} }, .unlocked),
},
.adjust_selection => |direction| {
self.renderer_state.mutex.lock();

View File

@ -300,12 +300,27 @@ pub const Action = union(enum) {
/// Quit ghostty.
quit: void,
/// Crash ghostty. This is funny, but is used for testing crash handling.
/// It is shipped in production builds because sometimes we need to
/// test crash handling works for a user who may have some specific
/// configuration. This is not bound by default and I recommend not
/// binding it.
crash: void,
/// Crash ghostty in the desired thread for the focused surface.
///
/// WARNING: This is a hard crash (panic) and data can be lost.
///
/// The purpose of this action is to test crash handling. For some
/// users, it may be useful to test crash reporting functionality in
/// order to determine if it all works as expected.
///
/// The value determines the crash location:
///
/// - "main" - crash on the main (GUI) thread.
/// - "io" - crash on the IO thread for the focused surface.
/// - "render" - crash on the render thread for the focused surface.
///
crash: CrashThread,
pub const CrashThread = enum {
main,
io,
render,
};
pub const CursorKey = struct {
normal: []const u8,

View File

@ -270,6 +270,8 @@ fn drainMailbox(self: *Thread) !void {
while (self.mailbox.pop()) |message| {
log.debug("mailbox message={}", .{message});
switch (message) {
.crash => @panic("crash request, crashing intentionally"),
.visible => |v| {
// Set our visible state
self.flags.visible = v;

View File

@ -8,6 +8,10 @@ const terminal = @import("../terminal/main.zig");
/// The messages that can be sent to a renderer thread.
pub const Message = union(enum) {
/// Purposely crash the renderer. This is used for testing and debugging.
/// See the "crash" binding action.
crash: void,
/// A change in state in the window focus that this renderer is
/// rendering within. This is only sent when a change is detected so
/// the renderer is expected to handle all of these.

View File

@ -268,6 +268,7 @@ fn drainMailbox(
log.debug("mailbox message={}", .{message});
switch (message) {
.crash => @panic("crash request, crashing intentionally"),
.change_config => |config| {
defer config.alloc.destroy(config.ptr);
try io.changeConfig(data, config.ptr);

View File

@ -29,6 +29,10 @@ pub const Message = union(enum) {
padding: renderer.Padding,
};
/// Purposely crash the renderer. This is used for testing and debugging.
/// See the "crash" binding action.
crash: void,
/// The derived configuration to update the implementation with. This
/// is allocated via the allocator and is expected to be freed when done.
change_config: struct {