Merge pull request #261 from mitchellh/scroll-page

scroll keybindings: top, bottom, page up, page down, page fractional
This commit is contained in:
Mitchell Hashimoto
2023-08-09 07:49:33 -07:00
committed by GitHub
7 changed files with 128 additions and 2 deletions

View File

@ -2050,6 +2050,45 @@ pub fn performBindingAction(self: *Surface, action: input.Binding.Action) !void
try self.io_thread.wakeup.notify();
},
.scroll_to_top => {
_ = self.io_thread.mailbox.push(.{
.scroll_viewport = .{ .top = {} },
}, .{ .forever = {} });
try self.io_thread.wakeup.notify();
},
.scroll_to_bottom => {
_ = self.io_thread.mailbox.push(.{
.scroll_viewport = .{ .bottom = {} },
}, .{ .forever = {} });
try self.io_thread.wakeup.notify();
},
.scroll_page_up => {
const rows: isize = @intCast(self.grid_size.rows);
_ = self.io_thread.mailbox.push(.{
.scroll_viewport = .{ .delta = -1 * rows },
}, .{ .forever = {} });
try self.io_thread.wakeup.notify();
},
.scroll_page_down => {
const rows: isize = @intCast(self.grid_size.rows);
_ = self.io_thread.mailbox.push(.{
.scroll_viewport = .{ .delta = rows },
}, .{ .forever = {} });
try self.io_thread.wakeup.notify();
},
.scroll_page_fractional => |fraction| {
const rows: f32 = @floatFromInt(self.grid_size.rows);
const delta: isize = @intFromFloat(@floor(fraction * rows));
_ = self.io_thread.mailbox.push(.{
.scroll_viewport = .{ .delta = delta },
}, .{ .forever = {} });
try self.io_thread.wakeup.notify();
},
.jump_to_prompt => |delta| {
_ = self.io_thread.mailbox.push(.{
.jump_to_prompt = @intCast(delta),

View File

@ -435,15 +435,37 @@ pub const Config = struct {
.{ .goto_split = .right },
);
// Semantic prompts
// Viewport scrolling
try result.keybind.set.put(
alloc,
.{ .key = .home, .mods = .{ .shift = true } },
.{ .scroll_to_top = {} },
);
try result.keybind.set.put(
alloc,
.{ .key = .end, .mods = .{ .shift = true } },
.{ .scroll_to_bottom = {} },
);
try result.keybind.set.put(
alloc,
.{ .key = .page_up, .mods = .{ .shift = true } },
.{ .jump_to_prompt = -1 },
.{ .scroll_page_up = {} },
);
try result.keybind.set.put(
alloc,
.{ .key = .page_down, .mods = .{ .shift = true } },
.{ .scroll_page_down = {} },
);
// Semantic prompts
try result.keybind.set.put(
alloc,
.{ .key = .page_up, .mods = .{ .shift = true, .ctrl = true } },
.{ .jump_to_prompt = -1 },
);
try result.keybind.set.put(
alloc,
.{ .key = .page_down, .mods = .{ .shift = true, .ctrl = true } },
.{ .jump_to_prompt = 1 },
);
}
@ -489,6 +511,28 @@ pub const Config = struct {
.{ .clear_screen = {} },
);
// Viewport scrolling
try result.keybind.set.put(
alloc,
.{ .key = .home, .mods = .{ .super = true } },
.{ .scroll_to_top = {} },
);
try result.keybind.set.put(
alloc,
.{ .key = .end, .mods = .{ .super = true } },
.{ .scroll_to_bottom = {} },
);
try result.keybind.set.put(
alloc,
.{ .key = .page_up, .mods = .{ .super = true } },
.{ .scroll_page_up = {} },
);
try result.keybind.set.put(
alloc,
.{ .key = .page_down, .mods = .{ .super = true } },
.{ .scroll_page_down = {} },
);
// Semantic prompts
try result.keybind.set.put(
alloc,

View File

@ -132,6 +132,14 @@ pub fn parse(input: []const u8) !Binding {
break :action @unionInit(Action, field.name, value);
},
.Float => {
const idx = colonIdx orelse return Error.InvalidFormat;
const param = actionRaw[idx + 1 ..];
const value = std.fmt.parseFloat(field.type, param) catch
return Error.InvalidFormat;
break :action @unionInit(Action, field.name, value);
},
else => unreachable,
},
}
@ -177,6 +185,13 @@ pub const Action = union(enum) {
/// Clear the screen. This also clears all scrollback.
clear_screen: void,
/// Scroll the screen varying amounts.
scroll_to_top: void,
scroll_to_bottom: void,
scroll_page_up: void,
scroll_page_down: void,
scroll_page_fractional: f32,
/// Jump the viewport forward or back by prompt. Positive
/// number is the number of prompts to jump forward, negative
/// is backwards.
@ -442,3 +457,19 @@ test "parse: action with int" {
try testing.expectEqual(@as(i16, 10), binding.action.jump_to_prompt);
}
}
test "parse: action with float" {
const testing = std.testing;
// parameter
{
const binding = try parse("a=scroll_page_fractional:-0.5");
try testing.expect(binding.action == .scroll_page_fractional);
try testing.expectEqual(@as(f32, -0.5), binding.action.scroll_page_fractional);
}
{
const binding = try parse("a=scroll_page_fractional:+0.5");
try testing.expect(binding.action == .scroll_page_fractional);
try testing.expectEqual(@as(f32, 0.5), binding.action.scroll_page_fractional);
}
}

View File

@ -1460,6 +1460,7 @@ pub const ScrollViewport = union(enum) {
/// Scroll to the bottom, i.e. the top of the active area
bottom: void,
/// Scroll by some delta amount, up is negative.
delta: isize,
};

View File

@ -300,6 +300,13 @@ pub fn clearScreen(self: *Exec, history: bool) !void {
try self.queueWrite(&[_]u8{0x0C});
}
/// Scroll the viewport
pub fn scrollViewport(self: *Exec, scroll: terminal.Terminal.ScrollViewport) !void {
self.renderer_state.mutex.lock();
defer self.renderer_state.mutex.unlock();
try self.terminal.scrollViewport(scroll);
}
/// Jump the viewport to the prompt.
pub fn jumpToPrompt(self: *Exec, delta: isize) !void {
const wakeup: bool = wakeup: {

View File

@ -156,6 +156,7 @@ fn drainMailbox(self: *Thread) !void {
},
.resize => |v| self.handleResize(v),
.clear_screen => |v| try self.impl.clearScreen(v.history),
.scroll_viewport => |v| try self.impl.scrollViewport(v),
.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),

View File

@ -45,6 +45,9 @@ pub const Message = union(enum) {
history: bool,
},
/// Scroll the viewport
scroll_viewport: terminal.Terminal.ScrollViewport,
/// Jump forward/backward n prompts.
jump_to_prompt: isize,