mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-16 16:56:09 +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();
|
self.renderer_state.mutex.lock();
|
||||||
defer self.renderer_state.mutex.unlock();
|
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| {
|
self.queueRender() catch |err| {
|
||||||
@ -2372,6 +2372,9 @@ fn linkAtPos(
|
|||||||
break :mouse_pt viewport_point.toScreen(&self.io.terminal.screen);
|
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.
|
// Get the line we're hovering over.
|
||||||
const line = self.io.terminal.screen.getLine(mouse_pt) orelse
|
const line = self.io.terminal.screen.getLine(mouse_pt) orelse
|
||||||
return null;
|
return null;
|
||||||
@ -2382,7 +2385,7 @@ fn linkAtPos(
|
|||||||
for (self.config.links) |link| {
|
for (self.config.links) |link| {
|
||||||
switch (link.highlight) {
|
switch (link.highlight) {
|
||||||
.always, .hover => {},
|
.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);
|
var it = strmap.searchIterator(link.regex);
|
||||||
@ -2398,6 +2401,25 @@ fn linkAtPos(
|
|||||||
return null;
|
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
|
/// Attempt to invoke the action of any link that is under the
|
||||||
/// given position.
|
/// given position.
|
||||||
///
|
///
|
||||||
|
@ -36,6 +36,11 @@ pub const Highlight = union(enum) {
|
|||||||
/// hovering or always. For always, all links will be highlighted
|
/// hovering or always. For always, all links will be highlighted
|
||||||
/// when the mods are pressed regardless of if the mouse is hovering
|
/// when the mods are pressed regardless of if the mouse is hovering
|
||||||
/// over them.
|
/// 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,
|
always_mods: Mods,
|
||||||
hover_mods: Mods,
|
hover_mods: Mods,
|
||||||
};
|
};
|
||||||
|
@ -1551,12 +1551,12 @@ fn rebuildCells(
|
|||||||
const arena_alloc = arena.allocator();
|
const arena_alloc = arena.allocator();
|
||||||
|
|
||||||
// Create our match set for the links.
|
// 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,
|
arena_alloc,
|
||||||
screen,
|
screen,
|
||||||
mouse.point orelse .{},
|
mouse_pt,
|
||||||
mouse.mods,
|
mouse.mods,
|
||||||
);
|
) else .{};
|
||||||
|
|
||||||
// Determine our x/y range for preedit. We don't want to render anything
|
// Determine our x/y range for preedit. We don't want to render anything
|
||||||
// here because we will render the preedit separately.
|
// here because we will render the preedit separately.
|
||||||
|
@ -987,12 +987,12 @@ pub fn rebuildCells(
|
|||||||
self.gl_cells_written = 0;
|
self.gl_cells_written = 0;
|
||||||
|
|
||||||
// Create our match set for the links.
|
// 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,
|
arena_alloc,
|
||||||
screen,
|
screen,
|
||||||
mouse.point orelse .{},
|
mouse_pt,
|
||||||
mouse.mods,
|
mouse.mods,
|
||||||
);
|
) else .{};
|
||||||
|
|
||||||
// Determine our x/y range for preedit. We don't want to render anything
|
// Determine our x/y range for preedit. We don't want to render anything
|
||||||
// here because we will render the preedit separately.
|
// here because we will render the preedit separately.
|
||||||
|
@ -139,7 +139,7 @@ pub const MatchSet = struct {
|
|||||||
/// The matches.
|
/// The matches.
|
||||||
///
|
///
|
||||||
/// Important: this must be in left-to-right top-to-bottom order.
|
/// Important: this must be in left-to-right top-to-bottom order.
|
||||||
matches: []const terminal.Selection,
|
matches: []const terminal.Selection = &.{},
|
||||||
i: usize = 0,
|
i: usize = 0,
|
||||||
|
|
||||||
pub fn deinit(self: *MatchSet, alloc: Allocator) void {
|
pub fn deinit(self: *MatchSet, alloc: Allocator) void {
|
||||||
|
Reference in New Issue
Block a user