╭─────────────╮ │scroll to top│ ╰─────────────╯ ╭ Files.zig ────────────────────────────────────────────────────╮ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ╰───────────────────────────────────────────────────────────────╯
╭────╮ ╭ clone ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╮ │http│ ssh │ │ ╰────╯ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╯
541 const inner = self.detailInner(); 542 if (inner.children.count() == 0) return; 543 const target = inner.getFocus().child_id orelse inner.children.keys()[0]; 544 try root_focus.setFocus(target); 545 if (root_focus.grandchild_id == target) return; 546 // the detail pane wasn't laid out last build (too narrow to show beside 547 // the list), so its content isn't in the focus tree yet. select the pane 548 // at the box level, and the content will be focused after the next build. 549 self.contentBox().getFocus().child_id = self.detailOuter().getFocus().id; 550 } 551 552 fn focusList(self: *View, root_focus: *Focus) !void { 553 const lb = self.listBox(); 554 const id = lb.getFocus().child_id orelse (if (lb.children.count() > 0) lb.children.keys()[0] else return); 555 try root_focus.setFocus(id); 556 } 557 558 fn moveSelection(self: *View, root_focus: *Focus, delta: isize) !void { 559 const lb = self.listBox(); 560 const keys = lb.children.keys(); 561 if (keys.len == 0) return; 562 const cur_id = lb.getFocus().child_id orelse return; 563 const cur: isize = @intCast(lb.children.getIndex(cur_id) orelse return); 564 const last: isize = @intCast(keys.len - 1); 565 const next: usize = @intCast(std.math.clamp(cur + delta, 0, last)); 566 if (next == @as(usize, @intCast(cur))) return; 567 try root_focus.setFocus(keys[next]); 568 if (lb.children.values()[next].rect) |rect| self.listScroll().scrollToRect(rect); 569 } 570 571 pub fn clearGrid(self: *View) void { 572 self.box.clearGrid(); 573 } 574 575 pub fn getGrid(self: View) ?Grid { 576 return self.box.getGrid(); 577 } 578 579 pub fn getFocus(self: *View) *Focus { 580 return self.box.getFocus(); 581 } 582 583 // for the parent's "scroll up at the top jumps to the header" check. inside 584 // the detail pane up-arrow stays in the pane (scrolling); when the list holds 585 // focus, report its selection directly so up-arrow at the top row ascends. 586 pub fn getSelectedIndex(self: *View) ?usize { 587 if (self.detailActive()) return 1; 588 const lb = self.listBox(); 589 const cid = lb.getFocus().child_id orelse return null; 590 return lb.children.getIndex(cid); 591 } 592 }; 593 594 // the index of the "README"/"README.md" file entry (case-insensitive), or null 595 // if none. used to pick the default selection at the repo root. 596 fn readmeIndex(entries: []const Entry) ?usize { 597 for (entries, 0..) |entry, i| { 598 if (entry.is_dir) continue; 599 if (std.ascii.eqlIgnoreCase(entry.name, "README") or std.ascii.eqlIgnoreCase(entry.name, "README.md")) 600 return i; 601 } 602 return null; 603 } 604 605 // the "a:" link for the files route at `dir`, pinned to the listing's ref. 606 fn dirLink(page_arena: *std.heap.ArenaAllocator, data: *const Self, dir: []const u8) ![]const u8 { 607 const route = ui.RoutablePage.repoFilesRoute(data.identity, data.ref_or_oid, data.ref_or_oid_value, dir) orelse return error.RouteTooLong; 608 const url = try route.urlAlloc(page_arena); 609 return std.fmt.allocPrint(page_arena.allocator(), "a:{s}", .{url}); 610 } 611 612 // `dir`/`name`, or just `name` at the root. 613 fn childDir(arena: std.mem.Allocator, dir: []const u8, name: []const u8) ![]const u8 { 614 return if (dir.len == 0) name else std.fmt.allocPrint(arena, "{s}/{s}", .{ dir, name }); 615 } 616 617 // `dir` with its last segment removed ("" when `dir` has a single segment). 618 fn parentDir(dir: []const u8) []const u8 { 619 const slash = std.mem.lastIndexOfScalar(u8, dir, '/') orelse return ""; 620 return dir[0..slash]; 621 } 622