diff --git a/src/Surface.zig b/src/Surface.zig index 3393d8d31..3f0e0b25b 100644 --- a/src/Surface.zig +++ b/src/Surface.zig @@ -1106,6 +1106,13 @@ pub fn keyCallback( try self.io_thread.wakeup.notify(); }, + .jump_to_prompt => |delta| { + _ = self.io_thread.mailbox.push(.{ + .jump_to_prompt = @intCast(delta), + }, .{ .forever = {} }); + try self.io_thread.wakeup.notify(); + }, + .toggle_dev_mode => if (DevMode.enabled) { DevMode.instance.visible = !DevMode.instance.visible; try self.queueRender(); diff --git a/src/config.zig b/src/config.zig index 456ba97b0..a54c5e062 100644 --- a/src/config.zig +++ b/src/config.zig @@ -491,6 +491,18 @@ pub const Config = struct { .{ .clear_screen = {} }, ); + // Semantic prompts + try result.keybind.set.put( + alloc, + .{ .key = .up, .mods = .{ .super = true, .shift = true } }, + .{ .jump_to_prompt = -1 }, + ); + try result.keybind.set.put( + alloc, + .{ .key = .down, .mods = .{ .super = true, .shift = true } }, + .{ .jump_to_prompt = 1 }, + ); + // Mac windowing try result.keybind.set.put( alloc, diff --git a/src/input/Binding.zig b/src/input/Binding.zig index 2cb9c346e..010992960 100644 --- a/src/input/Binding.zig +++ b/src/input/Binding.zig @@ -169,6 +169,11 @@ pub const Action = union(enum) { /// Clear the screen. This also clears all scrollback. clear_screen: void, + /// Jump the viewport forward or back by prompt. Positive + /// number is the number of prompts to jump forward, negative + /// is backwards. + jump_to_prompt: i16, + /// Dev mode toggle_dev_mode: void, diff --git a/src/terminal/Screen.zig b/src/terminal/Screen.zig index 6255fd333..a45650395 100644 --- a/src/terminal/Screen.zig +++ b/src/terminal/Screen.zig @@ -1682,6 +1682,8 @@ fn jumpPrompt(self: *Screen, delta: isize) bool { } } + //log.warn("delta={} delta_rem={} start_y={} y={}", .{ delta, delta_rem, start_y, y }); + // If we didn't find any, do nothing. if (delta_rem == delta_start) return false; @@ -1690,6 +1692,7 @@ fn jumpPrompt(self: *Screen, delta: isize) bool { const new_y: usize = @intCast(start_y + y_delta); const old_viewport = self.viewport; self.scroll(.{ .row = .{ .screen = new_y } }) catch unreachable; + //log.warn("delta={} y_delta={} start_y={} new_y={}", .{ delta, y_delta, start_y, new_y }); return self.viewport != old_viewport; } diff --git a/src/terminal/Terminal.zig b/src/terminal/Terminal.zig index 35c2f3834..b1fba7f90 100644 --- a/src/terminal/Terminal.zig +++ b/src/terminal/Terminal.zig @@ -1504,7 +1504,7 @@ pub fn setScrollingRegion(self: *Terminal, top: usize, bottom: usize) void { /// (OSC 133) only allow setting this for wherever the current active cursor /// is located. pub fn markSemanticPrompt(self: *Terminal, p: SemanticPrompt) void { - // log.warn("semantic_prompt: {}", .{p}); + //log.warn("semantic_prompt y={} p={}", .{ self.screen.cursor.y, p }); const row = self.screen.getRow(.{ .active = self.screen.cursor.y }); row.setSemanticPrompt(switch (p) { .prompt => .prompt, diff --git a/src/termio/Exec.zig b/src/termio/Exec.zig index 9c735fb2d..d6a9dafa5 100644 --- a/src/termio/Exec.zig +++ b/src/termio/Exec.zig @@ -288,6 +288,21 @@ pub fn clearScreen(self: *Exec, history: bool) !void { try self.queueWrite(&[_]u8{0x0C}); } +/// Jump the viewport to the prompt. +pub fn jumpToPrompt(self: *Exec, delta: isize) !void { + const wakeup: bool = wakeup: { + self.renderer_state.mutex.lock(); + defer self.renderer_state.mutex.unlock(); + break :wakeup self.terminal.screen.jump(.{ + .prompt_delta = delta, + }); + }; + + if (wakeup) { + try self.renderer_wakeup.notify(); + } +} + pub inline fn queueWrite(self: *Exec, data: []const u8) !void { const ev = self.data.?; diff --git a/src/termio/Thread.zig b/src/termio/Thread.zig index d034ede3d..d64200792 100644 --- a/src/termio/Thread.zig +++ b/src/termio/Thread.zig @@ -156,6 +156,7 @@ fn drainMailbox(self: *Thread) !void { }, .resize => |v| self.handleResize(v), .clear_screen => |v| try self.impl.clearScreen(v.history), + .jump_to_prompt => |v| try self.impl.jumpToPrompt(v), .write_small => |v| try self.impl.queueWrite(v.data[0..v.len]), .write_stable => |v| try self.impl.queueWrite(v), .write_alloc => |v| { diff --git a/src/termio/message.zig b/src/termio/message.zig index e19af749e..20579c4e0 100644 --- a/src/termio/message.zig +++ b/src/termio/message.zig @@ -45,6 +45,9 @@ pub const Message = union(enum) { history: bool, }, + /// Jump forward/backward n prompts. + jump_to_prompt: isize, + /// Write where the data fits in the union. write_small: WriteReq.Small,