╭ changed ──────╮ │src/ui/Home.zig│ ╰───────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │119 const header = &self.box.children.values()[header_index].widget.home_header; │ │120 const stack = &self.box.children.values()[stack_index].widget.stack; │ │121 │ │122 - // each header tab maps 1:1 to a stack child by position │ │122 + // each header tab maps 1:1 to a stack child by position; mirror the │ │123 + // selected child's page into the url, keyed by its kind │ │124 if (header.getSelectedIndex()) |index| { │ │125 stack.getFocus().child_id = stack.children.keys()[index]; │ │125 - switch (index) { │ │126 + switch (std.meta.activeTag(stack.children.values()[index])) { │ │127 // mirror each list tab's built pagination window so the url stays │ │128 // consistent with what's shown (and so a build doesn't reset it). │ │128 - 0 => self.session.data.current_page = .{ .home_users = self.data.users.after }, │ │129 - 1 => self.session.data.current_page = .{ .home_repos = self.data.repos.after }, │ │130 - 2 => self.session.data.current_page = .home_settings, │ │131 - 3 => self.session.data.current_page = .home_auth, │ │129 + .home_users => self.session.data.current_page = .{ .home_users = self.data.users.after },│ │130 + .home_repos => self.session.data.current_page = .{ .home_repos = self.data.repos.after },│ │131 + .home_settings => self.session.data.current_page = .home_settings, │ │132 + .home_auth => self.session.data.current_page = .home_auth, │ │133 // the quit tab is tty-only and not a route, so leave current_page │ │134 // alone (nothing to mirror into the url). │ │135 else => {}, │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ─────────────╮ │src/ui/Home/Header.zig│ ╰──────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────╮ │57 .min_size = .{ .width = 1, .height = null }, │ │58 }); │ │59 } │ │60 + │ │61 + // the tab matching the current page is focused initially; matching by│ │62 + // link (rather than position) keeps this robust to tab changes. │ │63 + const current_link: []const u8 = switch (session.data.current_page) { │ │64 + .home_repos => "a:/repos", │ │65 + .home_settings => "a:/settings", │ │66 + .home_auth => "a:/auth", │ │67 + else => "a:/users", │ │68 + }; │ │69 + var selected_tab: ?usize = null; │ │70 │ │71 // tabs │ │72 for ( │ ╰──────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │88 var auth_tab = try AuthTab.View.init(allocator, &data.auth_tab, session); │ │89 errdefer auth_tab.deinit(allocator); │ │90 try tab_ids.put(allocator, auth_tab.getFocus().id, {}); │ │91 + if (std.mem.eql(u8, focus_name, current_link)) selected_tab = auth_tab.getFocus().id;│ │92 try box.children.put(allocator, auth_tab.getFocus().id, .{ │ │93 .widget = .{ .auth_tab = auth_tab }, │ │94 .rect = null, │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │102 text_box.getFocus().focusable = true; │ │103 text_box.getFocus().kind = .{ .custom = focus_name }; │ │104 try tab_ids.put(allocator, text_box.getFocus().id, {}); │ │105 + if (std.mem.eql(u8, focus_name, current_link)) selected_tab = text_box.getFocus().id;│ │106 try box.children.put(allocator, text_box.getFocus().id, .{ │ │107 .widget = .{ .text_box = text_box }, │ │108 .rect = null, │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────╮ │127 } │ │128 │ │129 var self = View{ .box = box, .data = data, .tab_ids = tab_ids }; │ │118 - // initial selected tab │ │119 - self.getFocus().child_id = self.tab_ids.keys()[ │ │120 - switch (session.data.current_page) { │ │121 - .home_users => 0, │ │122 - .home_repos => 1, │ │123 - .home_settings => 2, │ │124 - .home_auth => 3, │ │125 - else => 0, │ │126 - } │ │127 - ]; │ │130 + self.getFocus().child_id = selected_tab orelse self.tab_ids.keys()[0];│ │131 return self; │ │132 } │ │133 │ ╰───────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ──────╮ │src/ui/Repo.zig│ ╰───────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │173 // rather than navigating. │ │174 if (header.getSelectedIndex()) |index| { │ │175 stack.getFocus().child_id = stack.children.keys()[index]; │ │176 - switch (index) { │ │176 + switch (std.meta.activeTag(stack.children.values()[index])) { │ │177 // files/commits carry this page's content route (directory / log │ │178 // page); settings/auth carry only "owner/name". │ │179 - 1 => self.session.data.current_page = .{ .repo_commits = .{ .name = self.data.commits_route_name } }, │ │180 - 2 => self.session.data.current_page = .{ .repo_settings = self.data.identity }, │ │181 - 3 => self.session.data.current_page = .{ .repo_auth = self.data.identity }, │ │179 + .repo_commits => self.session.data.current_page = .{ .repo_commits = .{ .name = self.data.commits_route_name } },│ │180 + .home_settings => self.session.data.current_page = .{ .repo_settings = self.data.identity }, │ │181 + .home_auth => self.session.data.current_page = .{ .repo_auth = self.data.identity }, │ │182 // the quit tab is tty-only and not a route, so leave current_page │ │183 // alone (nothing to mirror into the url). │ │184 - 4 => {}, │ │184 + .quit => {}, │ │185 + // the files tab (this page's directory route) │ │186 else => self.session.data.current_page = .{ .repo = self.data.route_name }, │ │187 } │ │188 } │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ─────────────╮ │src/ui/Repo/Header.zig│ ╰──────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │ 94 const commits_link = try std.fmt.allocPrint(aa, "a:{s}", .{try commits_route.urlAlloc(session.page_arena)}); │ │ 95 const settings_link = try std.fmt.allocPrint(aa, "a:/repo/{s}/{s}/settings", .{ data.owner_name, data.name });│ │ 96 const auth_link = try std.fmt.allocPrint(aa, "a:/repo/{s}/{s}/auth", .{ data.owner_name, data.name }); │ │ 97 + │ │ 98 + // the tab matching the current page is focused initially; matching by │ │ 99 + // link (rather than position) keeps this robust to tab changes. │ │100 + const current_link: []const u8 = switch (session.data.current_page) { │ │101 + .repo_commits => commits_link, │ │102 + .repo_settings => settings_link, │ │103 + .repo_auth => auth_link, │ │104 + else => files_link, │ │105 + }; │ │106 + var selected_tab: ?usize = null; │ │107 │ │108 // files tab │ │109 { │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────╮ │112 text_box.getFocus().focusable = true; │ │113 text_box.getFocus().kind = .{ .custom = files_link }; │ │114 try tab_ids.put(allocator, text_box.getFocus().id, {}); │ │115 + if (std.mem.eql(u8, files_link, current_link)) selected_tab = text_box.getFocus().id;│ │116 try box.children.put(allocator, text_box.getFocus().id, .{ │ │117 .widget = .{ .text_box = text_box }, │ │118 .rect = null, │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │127 text_box.getFocus().focusable = true; │ │128 text_box.getFocus().kind = .{ .custom = commits_link }; │ │129 try tab_ids.put(allocator, text_box.getFocus().id, {}); │ │130 + if (std.mem.eql(u8, commits_link, current_link)) selected_tab = text_box.getFocus().id;│ │131 try box.children.put(allocator, text_box.getFocus().id, .{ │ │132 .widget = .{ .text_box = text_box }, │ │133 .rect = null, │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │153 text_box.getFocus().focusable = true; │ │154 text_box.getFocus().kind = .{ .custom = settings_link }; │ │155 try tab_ids.put(allocator, text_box.getFocus().id, {}); │ │156 + if (std.mem.eql(u8, settings_link, current_link)) selected_tab = text_box.getFocus().id;│ │157 try box.children.put(allocator, text_box.getFocus().id, .{ │ │158 .widget = .{ .text_box = text_box }, │ │159 .rect = null, │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯