mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-16 08:46:08 +03:00
fix selection regression caused by screen copy optimization
This commit is contained in:
@ -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
|
// Can be off the screen if the user drags it out, so max
|
||||||
// it out on our available columns
|
// 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: {
|
.y = if (ypos < 0) 0 else y: {
|
||||||
const cell_height = @floatCast(f64, self.cell_size.height);
|
const cell_height = @floatCast(f64, self.cell_size.height);
|
||||||
const y = @floatToInt(usize, ypos / cell_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);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -203,7 +203,6 @@ test {
|
|||||||
_ = @import("TempDir.zig");
|
_ = @import("TempDir.zig");
|
||||||
_ = @import("font/main.zig");
|
_ = @import("font/main.zig");
|
||||||
_ = @import("renderer.zig");
|
_ = @import("renderer.zig");
|
||||||
_ = @import("terminal/Terminal.zig");
|
|
||||||
_ = @import("termio.zig");
|
_ = @import("termio.zig");
|
||||||
_ = @import("input.zig");
|
_ = @import("input.zig");
|
||||||
|
|
||||||
|
@ -458,10 +458,17 @@ pub fn render(
|
|||||||
);
|
);
|
||||||
errdefer screen_copy.deinit();
|
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 .{
|
break :critical .{
|
||||||
.bg = self.background,
|
.bg = self.background,
|
||||||
.devmode = if (state.devmode) |dm| dm.visible else false,
|
.devmode = if (state.devmode) |dm| dm.visible else false,
|
||||||
.selection = state.terminal.selection,
|
.selection = selection,
|
||||||
.screen = screen_copy,
|
.screen = screen_copy,
|
||||||
.draw_cursor = self.cursor_visible and state.terminal.screen.viewportIsBottom(),
|
.draw_cursor = self.cursor_visible and state.terminal.screen.viewportIsBottom(),
|
||||||
};
|
};
|
||||||
|
@ -593,11 +593,18 @@ pub fn render(
|
|||||||
);
|
);
|
||||||
errdefer screen_copy.deinit();
|
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 .{
|
break :critical .{
|
||||||
.gl_bg = self.background,
|
.gl_bg = self.background,
|
||||||
.devmode_data = devmode_data,
|
.devmode_data = devmode_data,
|
||||||
.active_screen = state.terminal.active_screen,
|
.active_screen = state.terminal.active_screen,
|
||||||
.selection = state.terminal.selection,
|
.selection = selection,
|
||||||
.screen = screen_copy,
|
.screen = screen_copy,
|
||||||
.draw_cursor = self.cursor_visible and state.terminal.screen.viewportIsBottom(),
|
.draw_cursor = self.cursor_visible and state.terminal.screen.viewportIsBottom(),
|
||||||
};
|
};
|
||||||
|
@ -4,6 +4,7 @@ const Selection = @This();
|
|||||||
|
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const point = @import("point.zig");
|
const point = @import("point.zig");
|
||||||
|
const Screen = @import("Screen.zig");
|
||||||
const ScreenPoint = point.ScreenPoint;
|
const ScreenPoint = point.ScreenPoint;
|
||||||
|
|
||||||
/// Start and end of the selection. There is no guarantee that
|
/// Start and end of the selection. There is no guarantee that
|
||||||
@ -13,6 +14,25 @@ const ScreenPoint = point.ScreenPoint;
|
|||||||
start: ScreenPoint,
|
start: ScreenPoint,
|
||||||
end: 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.
|
/// Returns true if the selection contains the given point.
|
||||||
///
|
///
|
||||||
/// This recalculates top left and bottom right each call. If you have
|
/// 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;
|
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,
|
/// Returns true if the selection contains the row of the given point,
|
||||||
/// regardless of the x value.
|
/// regardless of the x value.
|
||||||
pub fn containsRow(self: Selection, p: ScreenPoint) bool {
|
pub fn containsRow(self: Selection, p: ScreenPoint) bool {
|
||||||
@ -116,3 +145,17 @@ test "Selection: contains" {
|
|||||||
try testing.expect(!sel.contains(.{ .x = 12, .y = 1 }));
|
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 }));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user