diff --git a/src/config/Config.zig b/src/config/Config.zig index a28bb2d2d..6ee459635 100644 --- a/src/config/Config.zig +++ b/src/config/Config.zig @@ -14,6 +14,7 @@ const terminal = @import("../terminal/main.zig"); const internal_os = @import("../os/main.zig"); const cli = @import("../cli.zig"); +const url = @import("url.zig"); const Key = @import("key.zig").Key; const KeyValue = @import("key.zig").Value; const ErrorList = @import("ErrorList.zig"); @@ -329,6 +330,21 @@ command: ?[]const u8 = null, /// indicate that it is a login shell, depending on the OS). @"command-arg": RepeatableString = .{}, +/// Match a regular expression against the terminal text and associate +/// clicking it with an action. This can be used to match URLs, file paths, +/// etc. Actions can be opening using the system opener (i.e. "open" or +/// "xdg-open") or executing any arbitrary binding action. +/// +/// Links that are configured earlier take precedence over links that +/// are configured later. +/// +/// A default link that matches a URL and opens it in the system opener +/// always exists. +/// +/// TODO: This can't currently be set! +/// TODO: make URL matching disable-able +link: RepeatableLink = .{}, + /// Start new windows in fullscreen. This setting applies to new /// windows and does not apply to tabs, splits, etc. However, this /// setting will apply to all new windows, not just the first one. @@ -1189,6 +1205,13 @@ pub fn default(alloc_gpa: Allocator) Allocator.Error!Config { ); } + // Add our default link for URL detection + try result.link.links.append(alloc, .{ + .regex = url.regex, + .action = .{ .open = {} }, + .highlight = .{ .hover = {} }, + }); + return result; } @@ -2508,6 +2531,34 @@ pub const FontStyle = union(enum) { } }; +/// See "link" for documentation. +pub const RepeatableLink = struct { + const Self = @This(); + + links: std.ArrayListUnmanaged(inputpkg.Link) = .{}, + + pub fn parseCLI(self: *Self, alloc: Allocator, input_: ?[]const u8) !void { + _ = self; + _ = alloc; + _ = input_; + return error.NotImplemented; + } + + /// Deep copy of the struct. Required by Config. + pub fn clone(self: *const Self, alloc: Allocator) !Self { + _ = self; + _ = alloc; + return .{}; + } + + /// Compare if two of our value are requal. Required by Config. + pub fn equal(self: Self, other: Self) bool { + _ = self; + _ = other; + return true; + } +}; + /// Options for copy on select behavior. pub const CopyOnSelect = enum { /// Disables copy on select entirely. diff --git a/src/input.zig b/src/input.zig index f3afce97d..14140a524 100644 --- a/src/input.zig +++ b/src/input.zig @@ -7,6 +7,7 @@ pub const function_keys = @import("input/function_keys.zig"); pub const keycodes = @import("input/keycodes.zig"); pub const kitty = @import("input/kitty.zig"); pub const Binding = @import("input/Binding.zig"); +pub const Link = @import("input/Link.zig"); pub const KeyEncoder = @import("input/KeyEncoder.zig"); pub const InspectorMode = Binding.Action.InspectorMode; pub const SplitDirection = Binding.Action.SplitDirection; diff --git a/src/input/Link.zig b/src/input/Link.zig new file mode 100644 index 000000000..67ba65ef0 --- /dev/null +++ b/src/input/Link.zig @@ -0,0 +1,42 @@ +//! A link is a clickable element that can be used to trigger some action. +//! A link is NOT just a URL that opens in a browser. A link is any generic +//! regular expression match over terminal text that can trigger various +//! action types. +const Link = @This(); + +const oni = @import("oniguruma"); + +/// The regular expression that will be used to match the link. Ownership +/// of this memory is up to the caller. The link will never free this memory. +regex: []const u8, + +/// The action that will be triggered when the link is clicked. +action: Action, + +/// The situations in which the link will be highlighted. +highlight: Highlight, + +pub const Action = union(enum) { + /// Open the full matched value using the default open program. + /// For example, on macOS this is "open" and on Linux this is "xdg-open". + open: void, +}; + +pub const Highlight = union(enum) { + /// Always highlight the link. + always: void, + + /// Only highlight the link when the mouse is hovering over it. + hover: void, +}; + +/// Returns a new oni.Regex that can be used to match the link. +pub fn oniRegex(self: *const Link) !oni.Regex { + return try oni.Regex.init( + self.regex, + .{}, + oni.Encoding.utf8, + oni.Syntax.default, + null, + ); +}