Merge pull request #1981 from injust/adjust-line

Add `adjust_selection` actions for `beginning_of_line` and `end_of_line`
This commit is contained in:
Mitchell Hashimoto
2024-07-22 09:40:45 -07:00
committed by GitHub
3 changed files with 152 additions and 4 deletions

View File

@ -3471,6 +3471,8 @@ pub fn performBindingAction(self: *Surface, action: input.Binding.Action) !bool
.page_down => .page_down, .page_down => .page_down,
.home => .home, .home => .home,
.end => .end, .end => .end,
.beginning_of_line => .beginning_of_line,
.end_of_line => .end_of_line,
}); });
// If the selection endpoint is outside of the current viewpoint, // If the selection endpoint is outside of the current viewpoint,

View File

@ -304,6 +304,8 @@ pub const Action = union(enum) {
page_down, page_down,
home, home,
end, end,
beginning_of_line,
end_of_line,
}; };
pub const SplitDirection = enum { pub const SplitDirection = enum {

View File

@ -344,6 +344,8 @@ pub const Adjustment = enum {
end, end,
page_up, page_up,
page_down, page_down,
beginning_of_line,
end_of_line,
}; };
/// Adjust the selection by some given adjustment. An adjustment allows /// Adjust the selection by some given adjustment. An adjustment allows
@ -353,16 +355,16 @@ pub fn adjust(
s: *const Screen, s: *const Screen,
adjustment: Adjustment, adjustment: Adjustment,
) void { ) void {
// Note that we always adjusts "end" because end always represents // Note that we always adjust "end" because end always represents
// the last point of the selection by mouse, not necessarilly the // the last point of the selection by mouse, not necessarilly the
// top/bottom visually. So this results in the right behavior // top/bottom visually. So this results in the correct behavior
// whether the user drags up or down. // whether the user drags up or down.
const end_pin = self.endPtr(); const end_pin = self.endPtr();
switch (adjustment) { switch (adjustment) {
.up => if (end_pin.up(1)) |new_end| { .up => if (end_pin.up(1)) |new_end| {
end_pin.* = new_end; end_pin.* = new_end;
} else { } else {
end_pin.x = 0; self.adjust(s, .beginning_of_line);
}, },
.down => { .down => {
@ -377,7 +379,7 @@ pub fn adjust(
} }
} else { } else {
// If we're at the bottom, just go to the end of the line // If we're at the bottom, just go to the end of the line
end_pin.x = end_pin.page.data.size.cols - 1; self.adjust(s, .end_of_line);
} }
}, },
@ -440,6 +442,10 @@ pub fn adjust(
} }
} }
}, },
.beginning_of_line => end_pin.x = 0,
.end_of_line => end_pin.x = end_pin.page.data.size.cols - 1,
} }
} }
@ -786,6 +792,144 @@ test "Selection: adjust end with not full screen" {
} }
} }
test "Selection: adjust beginning of line" {
const testing = std.testing;
var s = try Screen.init(testing.allocator, 8, 10, 0);
defer s.deinit();
try s.testWriteString("A12 B34\nC12 D34");
// Not at beginning of the line
{
var sel = Selection.init(
s.pages.pin(.{ .screen = .{ .x = 5, .y = 1 } }).?,
s.pages.pin(.{ .screen = .{ .x = 5, .y = 1 } }).?,
false,
);
defer sel.deinit(&s);
sel.adjust(&s, .beginning_of_line);
// Start line
try testing.expectEqual(point.Point{ .screen = .{
.x = 5,
.y = 1,
} }, s.pages.pointFromPin(.screen, sel.start()).?);
try testing.expectEqual(point.Point{ .screen = .{
.x = 0,
.y = 1,
} }, s.pages.pointFromPin(.screen, sel.end()).?);
}
// Already at beginning of the line
{
var sel = Selection.init(
s.pages.pin(.{ .screen = .{ .x = 5, .y = 1 } }).?,
s.pages.pin(.{ .screen = .{ .x = 0, .y = 1 } }).?,
false,
);
defer sel.deinit(&s);
sel.adjust(&s, .beginning_of_line);
// Start line
try testing.expectEqual(point.Point{ .screen = .{
.x = 5,
.y = 1,
} }, s.pages.pointFromPin(.screen, sel.start()).?);
try testing.expectEqual(point.Point{ .screen = .{
.x = 0,
.y = 1,
} }, s.pages.pointFromPin(.screen, sel.end()).?);
}
// End pin moves to start pin
{
var sel = Selection.init(
s.pages.pin(.{ .screen = .{ .x = 0, .y = 1 } }).?,
s.pages.pin(.{ .screen = .{ .x = 5, .y = 1 } }).?,
false,
);
defer sel.deinit(&s);
sel.adjust(&s, .beginning_of_line);
// Start line
try testing.expectEqual(point.Point{ .screen = .{
.x = 0,
.y = 1,
} }, s.pages.pointFromPin(.screen, sel.start()).?);
try testing.expectEqual(point.Point{ .screen = .{
.x = 0,
.y = 1,
} }, s.pages.pointFromPin(.screen, sel.end()).?);
}
}
test "Selection: adjust end of line" {
const testing = std.testing;
var s = try Screen.init(testing.allocator, 8, 10, 0);
defer s.deinit();
try s.testWriteString("A12 B34\nC12 D34");
// Not at end of the line
{
var sel = Selection.init(
s.pages.pin(.{ .screen = .{ .x = 1, .y = 0 } }).?,
s.pages.pin(.{ .screen = .{ .x = 1, .y = 0 } }).?,
false,
);
defer sel.deinit(&s);
sel.adjust(&s, .end_of_line);
try testing.expectEqual(point.Point{ .screen = .{
.x = 1,
.y = 0,
} }, s.pages.pointFromPin(.screen, sel.start()).?);
try testing.expectEqual(point.Point{ .screen = .{
.x = 7,
.y = 0,
} }, s.pages.pointFromPin(.screen, sel.end()).?);
}
// Already at end of the line
{
var sel = Selection.init(
s.pages.pin(.{ .screen = .{ .x = 1, .y = 0 } }).?,
s.pages.pin(.{ .screen = .{ .x = 7, .y = 0 } }).?,
false,
);
defer sel.deinit(&s);
sel.adjust(&s, .end_of_line);
try testing.expectEqual(point.Point{ .screen = .{
.x = 1,
.y = 0,
} }, s.pages.pointFromPin(.screen, sel.start()).?);
try testing.expectEqual(point.Point{ .screen = .{
.x = 7,
.y = 0,
} }, s.pages.pointFromPin(.screen, sel.end()).?);
}
// End pin moves to start pin
{
var sel = Selection.init(
s.pages.pin(.{ .screen = .{ .x = 7, .y = 0 } }).?,
s.pages.pin(.{ .screen = .{ .x = 1, .y = 0 } }).?,
false,
);
defer sel.deinit(&s);
sel.adjust(&s, .end_of_line);
// Start line
try testing.expectEqual(point.Point{ .screen = .{
.x = 7,
.y = 0,
} }, s.pages.pointFromPin(.screen, sel.start()).?);
try testing.expectEqual(point.Point{ .screen = .{
.x = 7,
.y = 0,
} }, s.pages.pointFromPin(.screen, sel.end()).?);
}
}
test "Selection: order, standard" { test "Selection: order, standard" {
const testing = std.testing; const testing = std.testing;
const alloc = testing.allocator; const alloc = testing.allocator;