diff --git a/src/Surface.zig b/src/Surface.zig index 46a63a879..f9adfcfe6 100644 --- a/src/Surface.zig +++ b/src/Surface.zig @@ -2013,7 +2013,10 @@ pub fn mouseButtonCallback( fn linkAtPos( self: *Surface, pos: apprt.CursorPos, -) !?DerivedConfig.Link { +) !?struct { + DerivedConfig.Link, + terminal.Selection, +} { // If we have no configured links we can save a lot of work if (self.config.links.len == 0) return null; @@ -2037,7 +2040,7 @@ fn linkAtPos( defer match.deinit(); const sel = match.selection(); if (!sel.contains(mouse_pt)) continue; - return link; + return .{ link, sel }; } } @@ -2046,9 +2049,22 @@ fn linkAtPos( /// Attempt to invoke the action of any link that is under the /// given position. +/// +/// Requires the renderer state mutex is held. fn processLinks(self: *Surface, pos: apprt.CursorPos) !bool { - const link = try self.linkAtPos(pos) orelse return false; - log.info("link clicked action={}", .{link.action}); + const link, const sel = try self.linkAtPos(pos) orelse return false; + switch (link.action) { + .open => { + const str = try self.io.terminal.screen.selectionString( + self.alloc, + sel, + false, + ); + defer self.alloc.free(str); + try internal_os.open(self.alloc, str); + }, + } + return true; } diff --git a/src/os/main.zig b/src/os/main.zig index 7fdcb2d8b..1782601e0 100644 --- a/src/os/main.zig +++ b/src/os/main.zig @@ -9,6 +9,7 @@ pub usingnamespace @import("homedir.zig"); pub usingnamespace @import("locale.zig"); pub usingnamespace @import("macos_version.zig"); pub usingnamespace @import("mouse.zig"); +pub usingnamespace @import("open.zig"); pub usingnamespace @import("pipe.zig"); pub usingnamespace @import("resourcesdir.zig"); pub const TempDir = @import("TempDir.zig"); diff --git a/src/os/open.zig b/src/os/open.zig new file mode 100644 index 000000000..14e21111f --- /dev/null +++ b/src/os/open.zig @@ -0,0 +1,16 @@ +const std = @import("std"); +const builtin = @import("builtin"); +const Allocator = std.mem.Allocator; + +/// Open a URL in the default handling application. +pub fn open(alloc: Allocator, url: []const u8) !void { + const argv = switch (builtin.os.tag) { + .linux => &.{ "xdg-open", url }, + .macos => &.{ "open", url }, + .windows => &.{ "rundll32", "url.dll,FileProtocolHandler", url }, + else => @compileError("unsupported OS"), + }; + + var exe = std.process.Child.init(argv, alloc); + try exe.spawn(); +}