fix selection regression caused by screen copy optimization

This commit is contained in:
Mitchell Hashimoto
2022-11-20 20:05:07 -08:00
parent 7c17497623
commit d213c1a939
5 changed files with 61 additions and 5 deletions

View File

@ -1650,13 +1650,13 @@ fn posToViewport(self: Window, xpos: f64, ypos: f64) terminal.point.Viewport {
// Can be off the screen if the user drags it out, so max
// it out on our available columns
break :x @min(x, self.io.terminal.cols - 1);
break :x @min(x, self.grid_size.columns - 1);
},
.y = if (ypos < 0) 0 else y: {
const cell_height = @floatCast(f64, self.cell_size.height);
const y = @floatToInt(usize, ypos / cell_height);
break :y @min(y, self.io.terminal.rows - 1);
break :y @min(y, self.grid_size.rows - 1);
},
};
}

View File

@ -203,7 +203,6 @@ test {
_ = @import("TempDir.zig");
_ = @import("font/main.zig");
_ = @import("renderer.zig");
_ = @import("terminal/Terminal.zig");
_ = @import("termio.zig");
_ = @import("input.zig");

View File

@ -458,10 +458,17 @@ pub fn render(
);
errdefer screen_copy.deinit();
// Convert our selection to viewport points because we copy only
// the viewport above.
const selection: ?terminal.Selection = if (state.terminal.selection) |sel|
sel.toViewport(&state.terminal.screen)
else
null;
break :critical .{
.bg = self.background,
.devmode = if (state.devmode) |dm| dm.visible else false,
.selection = state.terminal.selection,
.selection = selection,
.screen = screen_copy,
.draw_cursor = self.cursor_visible and state.terminal.screen.viewportIsBottom(),
};

View File

@ -593,11 +593,18 @@ pub fn render(
);
errdefer screen_copy.deinit();
// Convert our selection to viewport points because we copy only
// the viewport above.
const selection: ?terminal.Selection = if (state.terminal.selection) |sel|
sel.toViewport(&state.terminal.screen)
else
null;
break :critical .{
.gl_bg = self.background,
.devmode_data = devmode_data,
.active_screen = state.terminal.active_screen,
.selection = state.terminal.selection,
.selection = selection,
.screen = screen_copy,
.draw_cursor = self.cursor_visible and state.terminal.screen.viewportIsBottom(),
};

View File

@ -4,6 +4,7 @@ const Selection = @This();
const std = @import("std");
const point = @import("point.zig");
const Screen = @import("Screen.zig");
const ScreenPoint = point.ScreenPoint;
/// Start and end of the selection. There is no guarantee that
@ -13,6 +14,25 @@ const ScreenPoint = point.ScreenPoint;
start: ScreenPoint,
end: ScreenPoint,
/// Converts a selection screen points to viewport points (still typed
/// as ScreenPoints) if the selection is present within the viewport
/// of the screen.
pub fn toViewport(self: Selection, screen: *const Screen) ?Selection {
const top = (point.Viewport{ .x = 0, .y = 0 }).toScreen(screen);
const bot = (point.Viewport{ .x = 0, .y = screen.rows - 1 }).toScreen(screen);
// If our selection isn't within the viewport, do nothing.
if (!self.within(top, bot)) return null;
// Convert
const start = self.start.toViewport(screen);
const end = self.end.toViewport(screen);
return Selection{
.start = .{ .x = start.x, .y = start.y },
.end = .{ .x = end.x, .y = end.y },
};
}
/// Returns true if the selection contains the given point.
///
/// This recalculates top left and bottom right each call. If you have
@ -40,6 +60,15 @@ pub fn contains(self: Selection, p: ScreenPoint) bool {
return p.y > tl.y and p.y < br.y;
}
/// Returns true if the selection contains any of the points between
/// (and including) the start and end. The x values are ignored this is
/// just a section match
pub fn within(self: Selection, start: ScreenPoint, end: ScreenPoint) bool {
const tl = self.topLeft();
const br = self.bottomRight();
return tl.y >= start.y and br.y <= end.y;
}
/// Returns true if the selection contains the row of the given point,
/// regardless of the x value.
pub fn containsRow(self: Selection, p: ScreenPoint) bool {
@ -116,3 +145,17 @@ test "Selection: contains" {
try testing.expect(!sel.contains(.{ .x = 12, .y = 1 }));
}
}
test "Selection: within" {
const testing = std.testing;
{
const sel: Selection = .{
.start = .{ .x = 5, .y = 1 },
.end = .{ .x = 3, .y = 2 },
};
try testing.expect(sel.within(.{ .x = 6, .y = 0 }, .{ .x = 6, .y = 3 }));
try testing.expect(sel.within(.{ .x = 3, .y = 1 }, .{ .x = 6, .y = 3 }));
try testing.expect(sel.within(.{ .x = 3, .y = 0 }, .{ .x = 6, .y = 2 }));
}
}