mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-16 00:36:07 +03:00
Merge pull request #1431 from mitchellh/mouse-mods-alt
core: handle mouse capture events with link highlighting
This commit is contained in:
@ -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.
|
||||
///
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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 {
|
||||
|
Reference in New Issue
Block a user