╭ changed ────────────╮ │src/ui/Repo/Files.zig│ ╰─────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────╮ │245 pub const View = struct { │ │246 // a vertical stack: the "viewing <ref>" banner on top, then a horizontal │ │247 // split with the file/directory list on the left and a detail pane on the │ │248 - // right showing the selected file's contents. each subdirectory row is an │ │249 - // `a:` link to its /repo/.../files/<path> route, so following it (click or │ │250 - // Enter) navigates through the host's link handling; a ".." row at the top │ │251 - // links to the parent. file rows aren't links — selecting one shows its │ │252 - // contents in the detail pane in-page, like the commits view's diff pane. │ │248 + // right showing the selected file's contents. │ │249 box: wgt.Box(ui.Widget), // vert: [sub_header_index] = banner, [content_index] = split│ │250 data: *const Self, │ │251 session: *ui.Session, │ ╰───────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │290 try addRow(allocator, &list_box, "..", try dirLink(session.page_arena, data, parentDir(data.dir))); │ │291 } │ │292 for (data.entries) |entry| { │ │293 + const path = try childDir(aa, data.dir, entry.name); │ │294 const label = if (entry.is_dir) try std.fmt.allocPrint(aa, "{s}/", .{entry.name}) else entry.name; │ │298 - const link = if (entry.is_dir) try dirLink(session.page_arena, data, try childDir(aa, data.dir, entry.name)) else "";│ │295 + const link = if (entry.is_dir) │ │296 + try dirLink(session.page_arena, data, path) │ │297 + else │ │298 + try fileLink(session.page_arena, data, path); │ │299 try addRow(allocator, &list_box, label, link); │ │300 } │ │301 // select the file the route named, else prefer a README so its │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │841 return null; │ │842 } │ │843 │ │844 -// the "a:" link for the files route at `dir`, pinned to the listing's ref. │ │845 -fn dirLink(page_arena: *std.heap.ArenaAllocator, data: *const Self, dir: []const u8) ![]const u8 { │ │846 - const route = ui.RoutablePage.repoFilesRoute(data.identity, data.ref_or_oid, data.ref_or_oid_value, dir, 0) orelse return error.RouteTooLong; │ │847 - const url = try route.urlAlloc(page_arena); │ │848 - return std.fmt.allocPrint(page_arena.allocator(), "a:{s}", .{url}); │ │844 +// an "a:" link to the files route at `path`, pinned to the listing's ref, so │ │845 +// following it navigates to that directory's listing. │ │846 +fn dirLink(page_arena: *std.heap.ArenaAllocator, data: *const Self, path: []const u8) ![]const u8 { │ │847 + const route = ui.RoutablePage.repoFilesRoute(data.identity, data.ref_or_oid, data.ref_or_oid_value, path, 0) orelse return error.RouteTooLong;│ │848 + return std.fmt.allocPrint(page_arena.allocator(), "a:{s}", .{try route.urlAlloc(page_arena)}); │ │849 } │ │850 │ │851 +// an "ai:" link to the file's route: crossPageLink ignores it, so a wasm click │ │852 +// selects the row in place and shows its contents in the detail pane. │ │853 +fn fileLink(page_arena: *std.heap.ArenaAllocator, data: *const Self, path: []const u8) ![]const u8 { │ │854 + const route = ui.RoutablePage.repoFilesRoute(data.identity, data.ref_or_oid, data.ref_or_oid_value, path, 0) orelse return error.RouteTooLong;│ │855 + return std.fmt.allocPrint(page_arena.allocator(), "ai:{s}", .{try route.urlAlloc(page_arena)}); │ │856 +} │ │857 + │ │858 // `dir`/`name`, or just `name` at the root. │ │859 pub fn childDir(arena: std.mem.Allocator, dir: []const u8, name: []const u8) ![]const u8 { │ │860 return if (dir.len == 0) name else std.fmt.allocPrint(arena, "{s}/{s}", .{ dir, name }); │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯