Merge pull request #1431 from mitchellh/mouse-mods-alt

core: handle mouse capture events with link highlighting
This commit is contained in:
Mitchell Hashimoto
2024-02-01 09:20:04 -08:00
committed by GitHub
5 changed files with 36 additions and 9 deletions

View File

@ -854,7 +854,7 @@ fn modsChanged(self: *Surface, mods: input.Mods) void {
{
self.renderer_state.mutex.lock();
defer self.renderer_state.mutex.unlock();
self.renderer_state.mouse.mods = mods;
self.renderer_state.mouse.mods = self.mouseModsWithCapture(self.mouse.mods);
}
self.queueRender() catch |err| {
@ -2372,6 +2372,9 @@ fn linkAtPos(
break :mouse_pt viewport_point.toScreen(&self.io.terminal.screen);
};
// Get our comparison mods
const mouse_mods = self.mouseModsWithCapture(self.mouse.mods);
// Get the line we're hovering over.
const line = self.io.terminal.screen.getLine(mouse_pt) orelse
return null;
@ -2382,7 +2385,7 @@ fn linkAtPos(
for (self.config.links) |link| {
switch (link.highlight) {
.always, .hover => {},
.always_mods, .hover_mods => |v| if (!v.equal(self.mouse.mods)) continue,
.always_mods, .hover_mods => |v| if (!v.equal(mouse_mods)) continue,
}
var it = strmap.searchIterator(link.regex);
@ -2398,6 +2401,25 @@ fn linkAtPos(
return null;
}
/// This returns the mouse mods to consider for link highlighting or
/// other purposes taking into account when shift is pressed for releasing
/// the mouse from capture.
///
/// The renderer state mutex must be held.
fn mouseModsWithCapture(self: *Surface, mods: input.Mods) input.Mods {
// In any of these scenarios, whatever mods are set (even shift)
// are preserved.
if (self.io.terminal.flags.mouse_event == .none) return mods;
if (!mods.shift) return mods;
if (self.mouseShiftCapture(false)) return mods;
// We have mouse capture, shift set, and we're not allowed to capture
// shift, so we can clear shift.
var final = mods;
final.shift = false;
return final;
}
/// Attempt to invoke the action of any link that is under the
/// given position.
///

View File

@ -36,6 +36,11 @@ pub const Highlight = union(enum) {
/// hovering or always. For always, all links will be highlighted
/// when the mods are pressed regardless of if the mouse is hovering
/// over them.
///
/// Note that if "shift" is specified here, this will NEVER match in
/// TUI programs that capture mouse events. "Shift" with mouse capture
/// escapes the mouse capture but strips the "shift" so it can't be
/// detected.
always_mods: Mods,
hover_mods: Mods,
};

View File

@ -1551,12 +1551,12 @@ fn rebuildCells(
const arena_alloc = arena.allocator();
// Create our match set for the links.
var link_match_set = try self.config.links.matchSet(
var link_match_set: link.MatchSet = if (mouse.point) |mouse_pt| try self.config.links.matchSet(
arena_alloc,
screen,
mouse.point orelse .{},
mouse_pt,
mouse.mods,
);
) else .{};
// Determine our x/y range for preedit. We don't want to render anything
// here because we will render the preedit separately.

View File

@ -987,12 +987,12 @@ pub fn rebuildCells(
self.gl_cells_written = 0;
// Create our match set for the links.
var link_match_set = try self.config.links.matchSet(
var link_match_set: link.MatchSet = if (mouse.point) |mouse_pt| try self.config.links.matchSet(
arena_alloc,
screen,
mouse.point orelse .{},
mouse_pt,
mouse.mods,
);
) else .{};
// Determine our x/y range for preedit. We don't want to render anything
// here because we will render the preedit separately.

View File

@ -139,7 +139,7 @@ pub const MatchSet = struct {
/// The matches.
///
/// Important: this must be in left-to-right top-to-bottom order.
matches: []const terminal.Selection,
matches: []const terminal.Selection = &.{},
i: usize = 0,
pub fn deinit(self: *MatchSet, alloc: Allocator) void {