╭─────────────╮ │scroll to top│ ╰─────────────╯ ╭ Refs.zig ─────────────────────────────────────────────────────╮ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ╰───────────────────────────────────────────────────────────────╯
╭────╮ ╭ clone ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╮ │http│ ssh │ │ ╰────╯ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╯
301 const cur_col = self.activeColumn() orelse return; 302 const target_scroll = columnScroll(&self.box.children.values()[target].widget.box); 303 const target_col = &target_scroll.child.box; 304 // an empty column has nothing to select; ignore. 305 if (target_col.children.count() == 0) return; 306 // keep the same row offset, clamped to the target column's last row. 307 const cur_id = cur_col.getFocus().child_id orelse return; 308 const cur = cur_col.children.getIndex(cur_id) orelse return; 309 const last = target_col.children.count() - 1; 310 const next = @min(cur, last); 311 root_focus.setFocus(target_col.children.keys()[next]); 312 if (target_col.children.values()[next].rect) |rect| target_scroll.scrollToRect(rect); 313 } 314 315 pub fn clearGrid(self: *View) void { 316 self.box.clearGrid(); 317 } 318 319 pub fn getGrid(self: View) ?Grid { 320 return self.box.getGrid(); 321 } 322 323 pub fn getFocus(self: *View) *Focus { 324 return self.box.getFocus(); 325 } 326 327 // the selected row's offset within the active column (0 = first row), so the 328 // parent knows when up should escape to the header. 329 pub fn getSelectedIndex(self: View) ?usize { 330 var copy = self; 331 const col = copy.activeColumn() orelse return null; 332 const cur_id = col.getFocus().child_id orelse return null; 333 return col.children.getIndex(cur_id); 334 } 335 }; 336 337 // the "a:" link to `kind`'s column paginated to `after` within `identity` 338 // ("owner/name"). the other column resets to its first window. 339 fn windowLink(page_arena: *std.heap.ArenaAllocator, identity: []const u8, kind: ui.RoutablePage.RefKind, after: usize) ![]const u8 { 340 const route = ui.RoutablePage.repoRefsRoute(identity, kind, after) orelse return error.RouteTooLong; 341 const url = try route.urlAlloc(page_arena); 342 return std.fmt.allocPrint(page_arena.allocator(), "a:{s}", .{url}); 343 } 344 345 // the "a:" link to the files tab at ref `name` (a branch or tag) within 346 // `identity` ("owner/name"), at its root directory. the name is percent-encoded 347 // since it can contain a '/'. 348 fn refLink(page_arena: *std.heap.ArenaAllocator, identity: []const u8, kind: ui.RoutablePage.RefKind, name: []const u8) ![]const u8 { 349 const aa = page_arena.allocator(); 350 const ref_or_oid: ui.RoutablePage.RefOrOid = switch (kind) { 351 .branch => .branch, 352 .tag => .tag, 353 }; 354 const value = try ui.urlEncodeRef(aa, name); 355 const route = ui.RoutablePage.repoFilesRoute(identity, ref_or_oid, value, "", 0) orelse return error.RouteTooLong; 356 const url = try route.urlAlloc(page_arena); 357 return std.fmt.allocPrint(aa, "a:{s}", .{url}); 358 } 359