Merge pull request #899 from Raiden1411/select-all

core: implement select all binding
This commit is contained in:
Mitchell Hashimoto
2023-11-17 21:37:57 -08:00
committed by GitHub
4 changed files with 110 additions and 0 deletions

View File

@ -2534,6 +2534,14 @@ pub fn performBindingAction(self: *Surface, action: input.Binding.Action) !bool
} else log.warn("runtime doesn't implement toggleFullscreen", .{}); } else log.warn("runtime doesn't implement toggleFullscreen", .{});
}, },
.select_all => {
const sel = self.io.terminal.screen.selectAll();
if (sel) |s| {
self.setSelection(s);
try self.queueRender();
}
},
.inspector => |mode| { .inspector => |mode| {
if (@hasDecl(apprt.Surface, "controlInspector")) { if (@hasDecl(apprt.Surface, "controlInspector")) {
self.rt_surface.controlInspector(mode); self.rt_surface.controlInspector(mode);

View File

@ -913,6 +913,13 @@ pub fn default(alloc_gpa: Allocator) Allocator.Error!Config {
} }
} }
// Select all
try result.keybind.set.put(
alloc,
.{ .key = .a, .mods = ctrlOrSuper(.{}) },
.{ .select_all = {} },
);
// Toggle fullscreen // Toggle fullscreen
try result.keybind.set.put( try result.keybind.set.put(
alloc, alloc,

View File

@ -152,6 +152,9 @@ pub const Action = union(enum) {
/// Clear the screen. This also clears all scrollback. /// Clear the screen. This also clears all scrollback.
clear_screen: void, clear_screen: void,
/// Select all text on the screen.
select_all: void,
/// Scroll the screen varying amounts. /// Scroll the screen varying amounts.
scroll_to_top: void, scroll_to_top: void,
scroll_to_bottom: void, scroll_to_bottom: void,

View File

@ -1392,6 +1392,73 @@ pub fn clear(self: *Screen, mode: ClearMode) !void {
} }
} }
/// Return the selection for all contents on the screen. Surrounding
/// whitespace is omitted. If there is no selection, this returns null.
pub fn selectAll(self: *Screen) ?Selection {
const whitespace = &[_]u32{ 0, ' ', '\t' };
const y_max = self.rowsWritten() - 1;
const start: point.ScreenPoint = start: {
var y: usize = 0;
while (y <= y_max) : (y += 1) {
const current_row = self.getRow(.{ .screen = y });
var x: usize = 0;
while (x < self.cols) : (x += 1) {
const cell = current_row.getCell(x);
// Empty is whitespace
if (cell.empty()) continue;
// Non-empty means we found it.
const this_whitespace = std.mem.indexOfAny(
u32,
whitespace,
&[_]u32{cell.char},
) != null;
if (this_whitespace) continue;
break :start .{ .x = x, .y = y };
}
}
// There is no start point and therefore no line that can be selected.
return null;
};
const end: point.ScreenPoint = end: {
var y: usize = y_max;
while (true) {
const current_row = self.getRow(.{ .screen = y });
var x: usize = 0;
while (x < self.cols) : (x += 1) {
const real_x = self.cols - x - 1;
const cell = current_row.getCell(real_x);
// Empty or whitespace, ignore.
if (cell.empty()) continue;
const this_whitespace = std.mem.indexOfAny(
u32,
whitespace,
&[_]u32{cell.char},
) != null;
if (this_whitespace) continue;
// Got it
break :end .{ .x = real_x, .y = y };
}
if (y == 0) break;
y -= 1;
}
};
return Selection{
.start = start,
.end = end,
};
}
/// Select the line under the given point. This will select across soft-wrapped /// Select the line under the given point. This will select across soft-wrapped
/// lines and will omit the leading and trailing whitespace. If the point is /// lines and will omit the leading and trailing whitespace. If the point is
/// over whitespace but the line has non-whitespace characters elsewhere, the /// over whitespace but the line has non-whitespace characters elsewhere, the
@ -3856,6 +3923,31 @@ test "Screen: selectLine" {
try testing.expectEqual(@as(usize, 0), sel.end.y); try testing.expectEqual(@as(usize, 0), sel.end.y);
} }
} }
test "Screen: selectAll" {
const testing = std.testing;
const alloc = testing.allocator;
var s = try init(alloc, 10, 10, 0);
defer s.deinit();
{
try s.testWriteString("ABC DEF\n 123\n456");
const sel = s.selectAll().?;
try testing.expectEqual(@as(usize, 0), sel.start.x);
try testing.expectEqual(@as(usize, 0), sel.start.y);
try testing.expectEqual(@as(usize, 2), sel.end.x);
try testing.expectEqual(@as(usize, 2), sel.end.y);
}
{
try s.testWriteString("\nFOO\n BAR\n BAZ\n QWERTY\n 12345678");
const sel = s.selectAll().?;
try testing.expectEqual(@as(usize, 0), sel.start.x);
try testing.expectEqual(@as(usize, 0), sel.start.y);
try testing.expectEqual(@as(usize, 8), sel.end.x);
try testing.expectEqual(@as(usize, 7), sel.end.y);
}
}
test "Screen: selectLine across soft-wrap" { test "Screen: selectLine across soft-wrap" {
const testing = std.testing; const testing = std.testing;