From 935063d8924c070ff83415a3eed33117f4a7c70c Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Wed, 13 Mar 2024 13:23:55 -0700 Subject: [PATCH] core: scroll to selection working --- src/Surface.zig | 36 ++++++++++++++++++++---------------- src/terminal/PageList.zig | 13 +++++++++++++ src/terminal/Screen.zig | 2 ++ 3 files changed, 35 insertions(+), 16 deletions(-) diff --git a/src/Surface.zig b/src/Surface.zig index 2418a535c..6ffc001e9 100644 --- a/src/Surface.zig +++ b/src/Surface.zig @@ -1358,14 +1358,14 @@ pub fn keyCallback( if (event.mods.shift) adjust_selection: { self.renderer_state.mutex.lock(); defer self.renderer_state.mutex.unlock(); - var screen = self.io.terminal.screen; + var screen = &self.io.terminal.screen; const sel = if (screen.selection) |*sel| sel else break :adjust_selection; // Silently consume key releases. We only want to process selection // adjust on press. if (event.action != .press and event.action != .repeat) return .consumed; - sel.adjust(&screen, switch (event.key) { + sel.adjust(screen, switch (event.key) { .left => .left, .right => .right, .up => .up, @@ -1378,20 +1378,24 @@ pub fn keyCallback( }); // If the selection endpoint is outside of the current viewpoint, - // scroll it in to view. - // TODO(paged-terminal) - // scroll: { - // const viewport_max = terminal.Screen.RowIndexTag.viewport.maxLen(&screen) - 1; - // const viewport_end = screen.viewport + viewport_max; - // const delta: isize = if (sel.end.y < screen.viewport) - // @intCast(screen.viewport) - // else if (sel.end.y > viewport_end) - // @intCast(viewport_end) - // else - // break :scroll; - // const start_y: isize = @intCast(sel.end.y); - // try self.io.terminal.scrollViewport(.{ .delta = start_y - delta }); - // } + // scroll it in to view. Note we always specifically use sel.end + // because that is what adjust modifies. + scroll: { + const viewport_tl = screen.pages.getTopLeft(.viewport); + const viewport_br = screen.pages.getBottomRight(.viewport).?; + if (sel.end().isBetween(viewport_tl, viewport_br)) + break :scroll; + + // Our end point is not within the viewport. If the end + // point is after the br then we need to adjust the end so + // that it is at the bottom right of the viewport. + const target = if (sel.end().before(viewport_tl)) + sel.end() + else + sel.end().up(screen.pages.rows - 1) orelse sel.end(); + + screen.scroll(.{ .pin = target }); + } // Queue a render so its shown try self.queueRender(); diff --git a/src/terminal/PageList.zig b/src/terminal/PageList.zig index 96a12513c..f0fa6168d 100644 --- a/src/terminal/PageList.zig +++ b/src/terminal/PageList.zig @@ -1413,6 +1413,10 @@ pub const Scroll = union(enum) { /// prompts. If the absolute value is greater than the number of prompts /// in either direction, jump to the furthest prompt in that direction. delta_prompt: isize, + + /// Scroll directly to a specific pin in the page. This will be set + /// as the top left of the viewport (ignoring the pin x value). + pin: Pin, }; /// Scroll the viewport. This will never create new scrollback, allocate @@ -1422,6 +1426,15 @@ pub fn scroll(self: *PageList, behavior: Scroll) void { switch (behavior) { .active => self.viewport = .{ .active = {} }, .top => self.viewport = .{ .top = {} }, + .pin => |p| { + if (self.pinIsActive(p)) { + self.viewport = .{ .active = {} }; + return; + } + + self.viewport_pin.* = p; + self.viewport = .{ .pin = {} }; + }, .delta_prompt => |n| self.scrollPrompt(n), .delta_row => |n| { if (n == 0) return; diff --git a/src/terminal/Screen.zig b/src/terminal/Screen.zig index fe672bb77..571fd1541 100644 --- a/src/terminal/Screen.zig +++ b/src/terminal/Screen.zig @@ -552,6 +552,7 @@ pub const Scroll = union(enum) { /// For all of these, see PageList.Scroll. active, top, + pin: Pin, delta_row: isize, delta_prompt: isize, }; @@ -566,6 +567,7 @@ pub fn scroll(self: *Screen, behavior: Scroll) void { switch (behavior) { .active => self.pages.scroll(.{ .active = {} }), .top => self.pages.scroll(.{ .top = {} }), + .pin => |p| self.pages.scroll(.{ .pin = p }), .delta_row => |v| self.pages.scroll(.{ .delta_row = v }), .delta_prompt => |v| self.pages.scroll(.{ .delta_prompt = v }), }