地圖 (Jido) is a lightweight Unix TUI file explorer designed for speed and simplicity.

fix: Removed need for stored offset for directory rendering. This change removes the stored offset from the List component and moves offset calculation to the render.

+13 -9
src/directories.zig
··· 5 5 const vaxis = @import("vaxis"); 6 6 const fuzzig = @import("fuzzig"); 7 7 8 - const History = struct { 9 - selected: usize, 10 - offset: usize, 11 - }; 12 - 13 8 const history_len: usize = 100; 14 9 15 10 const Self = @This(); ··· 20 15 file_contents: [4096]u8 = undefined, 21 16 pdf_contents: ?[]u8 = null, 22 17 entries: List(std.fs.Dir.Entry), 23 - history: CircStack(History, history_len), 18 + history: CircStack(usize, history_len), 24 19 child_entries: List([]const u8), 25 20 searcher: fuzzig.Ascii, 26 21 ··· 29 24 .alloc = alloc, 30 25 .dir = try std.fs.cwd().openDir(".", .{ .iterate = true }), 31 26 .entries = List(std.fs.Dir.Entry).init(alloc), 32 - .history = CircStack(History, history_len).init(), 27 + .history = CircStack(usize, history_len).init(), 33 28 .child_entries = List([]const u8).init(alloc), 34 29 .searcher = try fuzzig.Ascii.init( 35 30 alloc, ··· 159 154 selected_list_item_style: vaxis.Style, 160 155 list_item_style: vaxis.Style, 161 156 ) !void { 162 - for (self.entries.all()[self.entries.offset..], 0..) |item, i| { 163 - const selected = self.entries.selected - self.entries.offset; 157 + const win_height = window.height; 158 + var offset: usize = 0; 159 + 160 + while (self.entries.all()[offset..].len > win_height and 161 + self.entries.selected >= offset + (win_height / 2)) 162 + { 163 + offset += 1; 164 + } 165 + 166 + for (self.entries.all()[offset..], 0..) |item, i| { 167 + const selected = self.entries.selected - offset; 164 168 const is_selected = selected == i; 165 169 166 170 if (i > window.height) continue;
+6 -12
src/event_handlers.zig
··· 56 56 }; 57 57 58 58 for (app.directories.entries.all()) |entry| { 59 - // Update offset as we search for last selected entry. 60 - app.directories.entries.updateOffset(app.last_known_height, .next); 61 59 if (std.mem.eql(u8, entry.name, prev_selected_name)) return; 62 60 app.directories.entries.selected += 1; 63 61 } ··· 175 173 app.state = .command; 176 174 }, 177 175 .jump_bottom => { 178 - app.directories.entries.selectLast(app.last_known_height); 176 + app.directories.entries.selectLast(); 179 177 }, 180 178 .jump_top => app.directories.entries.selectFirst(), 181 179 .toggle_verbose_file_information => app.drawer.verbose = !app.drawer.verbose, ··· 199 197 }; 200 198 201 199 if (app.directories.history.pop()) |history| { 202 - if (history.selected < app.directories.entries.len()) { 203 - app.directories.entries.selected = history.selected; 204 - app.directories.entries.offset = history.offset; 200 + if (history < app.directories.entries.len()) { 201 + app.directories.entries.selected = history; 205 202 } 206 203 } 207 204 } else |err| { ··· 225 222 app.directories.dir.close(); 226 223 app.directories.dir = dir; 227 224 228 - _ = app.directories.history.push(.{ 229 - .selected = app.directories.entries.selected, 230 - .offset = app.directories.entries.offset, 231 - }); 225 + _ = app.directories.history.push(app.directories.entries.selected); 232 226 233 227 app.directories.clearEntries(); 234 228 const fuzzy = inputToSlice(app); ··· 267 261 } 268 262 }, 269 263 'j', Key.down => { 270 - app.directories.entries.next(app.last_known_height); 264 + app.directories.entries.next(); 271 265 }, 272 266 'k', Key.up => { 273 - app.directories.entries.previous(app.last_known_height); 267 + app.directories.entries.previous(); 274 268 }, 275 269 'u' => { 276 270 if (app.actions.pop()) |action| {
+3 -24
src/list.zig
··· 8 8 alloc: std.mem.Allocator, 9 9 items: std.ArrayList(T), 10 10 selected: usize, 11 - offset: usize, 12 11 13 12 pub fn init(alloc: std.mem.Allocator) Self { 14 13 return Self{ 15 14 .alloc = alloc, 16 15 .items = std.ArrayList(T).init(alloc), 17 16 .selected = 0, 18 - .offset = 0, 19 17 }; 20 18 } 21 19 ··· 30 28 pub fn clear(self: *Self) void { 31 29 self.items.clearAndFree(); 32 30 self.selected = 0; 33 - self.offset = 0; 34 31 } 35 32 36 33 pub fn get(self: Self, index: usize) !T { ··· 61 58 return self.items.items.len; 62 59 } 63 60 64 - pub fn next(self: *Self, win_height: usize) void { 61 + pub fn next(self: *Self) void { 65 62 if (self.selected + 1 < self.len()) { 66 63 self.selected += 1; 67 - self.updateOffset(win_height, .next); 68 64 } 69 65 } 70 66 71 - pub fn previous(self: *Self, win_height: usize) void { 67 + pub fn previous(self: *Self) void { 72 68 if (self.selected > 0) { 73 69 self.selected -= 1; 74 - self.updateOffset(win_height, .previous); 75 70 } 76 71 } 77 72 78 - pub fn updateOffset(self: *Self, win_height: usize, direction: enum { next, previous }) void { 79 - if (direction == .next) { 80 - if (self.all()[self.offset..].len > win_height and self.selected >= self.offset + (win_height / 2)) { 81 - self.offset += 1; 82 - } 83 - } else if (direction == .previous) { 84 - if (self.offset > 0 and self.selected < self.offset + (win_height / 2)) { 85 - self.offset -= 1; 86 - } 87 - } 88 - } 89 - 90 - pub fn selectLast(self: *Self, win_height: usize) void { 73 + pub fn selectLast(self: *Self) void { 91 74 self.selected = self.len() - 1; 92 - if (self.selected >= win_height) { 93 - self.offset = self.selected - (win_height - 1); 94 - } 95 75 } 96 76 97 77 pub fn selectFirst(self: *Self) void { 98 78 self.selected = 0; 99 - self.offset = 0; 100 79 } 101 80 }; 102 81 }