Add document and half-page motions
This commit is contained in:
+42
@@ -324,11 +324,16 @@ pub const Client = struct {
|
||||
const gutter_digits = @max(@as(usize, 2), decimalDigits(total_lines));
|
||||
const gutter_width = @min(self.viewport.width, gutter_digits + 2);
|
||||
const content_width = if (self.viewport.width > gutter_width) self.viewport.width - gutter_width else 0;
|
||||
const first_visible_line = firstVisibleLineForCursor(cursor_line, max_body_lines);
|
||||
var visible_line_index: usize = 0;
|
||||
var body_lines_used: usize = 0;
|
||||
var line_start_byte: usize = 0;
|
||||
var line_iter = std.mem.splitScalar(u8, snap.bytes, '\n');
|
||||
while (line_iter.next()) |line| : (visible_line_index += 1) {
|
||||
if (visible_line_index < first_visible_line) {
|
||||
line_start_byte += line.len + 1;
|
||||
continue;
|
||||
}
|
||||
if (body_lines_used >= max_body_lines) break;
|
||||
try appendEditorLine(
|
||||
allocator,
|
||||
@@ -1076,6 +1081,7 @@ pub const Client = struct {
|
||||
if (std.mem.eql(u8, text, "L") or std.mem.eql(u8, text, "$")) return self.applyProtocol("command move_line_end");
|
||||
if (std.mem.eql(u8, text, "%")) return self.jumpToMatch(null);
|
||||
if (std.mem.eql(u8, text, "m")) return self.openPrefix(.match);
|
||||
if (std.mem.eql(u8, text, "G")) return self.applyProtocol("command move_document_end");
|
||||
if (std.mem.eql(u8, text, "g")) return self.openPrefix(.go);
|
||||
if (std.mem.eql(u8, text, "j")) return self.repeatProtocol("command move_down", self.takeRepeat());
|
||||
if (std.mem.eql(u8, text, "k")) return self.repeatProtocol("command move_up", self.takeRepeat());
|
||||
@@ -1100,6 +1106,8 @@ pub const Client = struct {
|
||||
.end => try self.applyProtocol("command move_line_end"),
|
||||
.page_up => try self.repeatProtocol("command move_up", @max(@as(usize, 1), self.viewport.height - 2)),
|
||||
.page_down => try self.repeatProtocol("command move_down", @max(@as(usize, 1), self.viewport.height - 2)),
|
||||
.ctrl_u => try self.halfPage(.up),
|
||||
.ctrl_d => try self.halfPage(.down),
|
||||
else => self.unknownPrefixOrInput("normal"),
|
||||
},
|
||||
.unknown => self.unknownPrefixOrInput("normal"),
|
||||
@@ -1810,6 +1818,10 @@ pub const Client = struct {
|
||||
|
||||
fn applyGoRail(self: *Client, event: input.Event) !void {
|
||||
const text = eventText(event) orelse return self.unknownPrefixOrInput("normal");
|
||||
if (std.mem.eql(u8, text, "g")) return self.applyProtocol("command move_document_start");
|
||||
if (std.mem.eql(u8, text, "G")) return self.applyProtocol("command move_document_end");
|
||||
if (std.mem.eql(u8, text, "u")) return self.halfPage(.up);
|
||||
if (std.mem.eql(u8, text, "d")) return self.halfPage(.down);
|
||||
if (std.mem.eql(u8, text, "a")) return self.moveParameter(.next);
|
||||
if (std.mem.eql(u8, text, "A")) return self.moveParameter(.previous);
|
||||
if (std.mem.eql(u8, text, "e")) return self.gotoDiagnostic(.next);
|
||||
@@ -2201,6 +2213,17 @@ pub const Client = struct {
|
||||
self.noteDocumentChanged();
|
||||
}
|
||||
|
||||
const PageDirection = enum { up, down };
|
||||
|
||||
fn halfPage(self: *Client, direction: PageDirection) !void {
|
||||
const rows = @max(@as(usize, 1), (self.viewport.height - 1) / 2);
|
||||
const command = switch (direction) {
|
||||
.up => "command move_up",
|
||||
.down => "command move_down",
|
||||
};
|
||||
try self.repeatProtocol(command, rows);
|
||||
}
|
||||
|
||||
fn repeatProtocol(self: *Client, line: []const u8, repeat: usize) !void {
|
||||
var i: usize = 0;
|
||||
while (i < repeat) : (i += 1) try self.applyProtocol(line);
|
||||
@@ -2571,6 +2594,12 @@ fn countDocumentLines(bytes: []const u8) usize {
|
||||
return lines;
|
||||
}
|
||||
|
||||
fn firstVisibleLineForCursor(cursor_line: usize, max_body_lines: usize) usize {
|
||||
if (max_body_lines == 0) return cursor_line;
|
||||
if (cursor_line < max_body_lines) return 0;
|
||||
return cursor_line - max_body_lines + 1;
|
||||
}
|
||||
|
||||
fn decimalDigits(value: usize) usize {
|
||||
var digits: usize = 1;
|
||||
var n = value;
|
||||
@@ -5143,3 +5172,16 @@ test "regular: insert Enter copies current line indent and Tab follows tab-inden
|
||||
snap = try tabs.session.snapshot();
|
||||
try std.testing.expectEqualStrings("\titem x", snap.bytes);
|
||||
}
|
||||
|
||||
test "regular: vertical viewport follows cursor line" {
|
||||
var client = try Client.init(std.testing.allocator, .{ .width = 32, .height = 6 });
|
||||
defer client.deinit();
|
||||
|
||||
try client.handleTraceLine("open l1\nl2\nl3\nl4\nl5\nl6\nl7\nl8\nl9\nl10\nl11\nl12");
|
||||
try client.applyProtocol("command move_document_end");
|
||||
const frame = try client.render(std.testing.allocator);
|
||||
defer std.testing.allocator.free(frame);
|
||||
|
||||
try std.testing.expect(std.mem.indexOf(u8, frame, "12│") != null);
|
||||
try std.testing.expect(std.mem.indexOf(u8, frame, " 1│") == null);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user