Only keep total_items + Zig test update + pointless churn

This commit is contained in:
Yorhel 2021-05-24 11:02:26 +02:00
parent 7b3ebf9241
commit 9474aa4329
4 changed files with 84 additions and 80 deletions

View file

@ -85,8 +85,8 @@ fn sortLt(_: void, ap: ?*model.Entry, bp: ?*model.Entry) bool {
if (sortIntLt(a.blocks, b.blocks)) |r| return r; if (sortIntLt(a.blocks, b.blocks)) |r| return r;
}, },
.items => { .items => {
const ai = if (a.dir()) |d| d.total_items else 0; const ai = if (a.dir()) |d| d.items else 0;
const bi = if (b.dir()) |d| d.total_items else 0; const bi = if (b.dir()) |d| d.items else 0;
if (sortIntLt(ai, bi)) |r| return r; if (sortIntLt(ai, bi)) |r| return r;
if (sortIntLt(a.blocks, b.blocks)) |r| return r; if (sortIntLt(a.blocks, b.blocks)) |r| return r;
if (sortIntLt(a.size, b.size)) |r| return r; if (sortIntLt(a.size, b.size)) |r| return r;
@ -208,11 +208,15 @@ const Row = struct {
} }
if (main.config.show_graph == .both) ui.addch(' '); if (main.config.show_graph == .both) ui.addch(' ');
if (main.config.show_graph == .both or main.config.show_graph == .graph) { if (main.config.show_graph == .both or main.config.show_graph == .graph) {
const perblock = std.math.divCeil(u64, if (main.config.show_blocks) dir_max_blocks else dir_max_size, bar_size) catch unreachable; const perblock = std.math.divFloor(u64, if (main.config.show_blocks) dir_max_blocks else dir_max_size, bar_size) catch unreachable;
const num = if (main.config.show_blocks) item.blocks else item.size; const num = if (main.config.show_blocks) item.blocks else item.size;
var i: u32 = 0; var i: u32 = 0;
var siz: u64 = 0;
self.bg.fg(.graph); self.bg.fg(.graph);
while (i < bar_size) : (i += 1) ui.addch(if (i*perblock <= num) '#' else ' '); while (i < bar_size) : (i += 1) {
siz = saturateAdd(siz, perblock);
ui.addch(if (siz <= num) '#' else ' ');
}
} }
self.bg.fg(.default); self.bg.fg(.default);
ui.addch(']'); ui.addch(']');
@ -221,14 +225,16 @@ const Row = struct {
fn items(self: *Self) void { fn items(self: *Self) void {
if (!main.config.show_items) return; if (!main.config.show_items) return;
defer self.col += 7; defer self.col += 7;
const d = if (self.item) |d| d.dir() orelse return else return; const n = (if (self.item) |d| d.dir() orelse return else return).items;
const n = d.total_items;
ui.move(self.row, self.col); ui.move(self.row, self.col);
self.bg.fg(.num); self.bg.fg(.num);
if (n < 1000) if (n < 1000)
ui.addprint(" {d:>4}", .{n}) ui.addprint(" {d:>4}", .{n})
else if (n < 100_000) else if (n < 10_000) {
ui.addprint("{d:>6.3}", .{ @intToFloat(f32, n) / 1000 }) ui.addch(' ');
ui.addnum(self.bg, n);
} else if (n < 100_000)
ui.addnum(self.bg, n)
else if (n < 1000_000) { else if (n < 1000_000) {
ui.addprint("{d:>5.1}", .{ @intToFloat(f32, n) / 1000 }); ui.addprint("{d:>5.1}", .{ @intToFloat(f32, n) / 1000 });
self.bg.fg(.default); self.bg.fg(.default);
@ -360,18 +366,20 @@ pub fn draw() !void {
ui.move(ui.rows-1, 0); ui.move(ui.rows-1, 0);
ui.hline(' ', ui.cols); ui.hline(' ', ui.cols);
ui.move(ui.rows-1, 1); ui.move(ui.rows-1, 1);
ui.style(if (main.config.show_blocks) .bold_hd else .hd);
ui.addstr("Total disk usage: "); ui.addstr("Total disk usage: ");
ui.addsize(.hd, blocksToSize(dir_parents.top().entry.blocks)); ui.addsize(.hd, blocksToSize(dir_parents.top().entry.blocks));
ui.style(if (main.config.show_blocks) .hd else .bold_hd);
ui.addstr(" Apparent size: "); ui.addstr(" Apparent size: ");
ui.addsize(.hd, dir_parents.top().entry.size); ui.addsize(.hd, dir_parents.top().entry.size);
ui.addstr(" Items: "); ui.addstr(" Items: ");
ui.addnum(.hd, dir_parents.top().total_items); ui.addnum(.hd, dir_parents.top().items);
if (need_confirm_quit) drawQuit(); if (need_confirm_quit) drawQuit();
if (sel_row > 0) ui.move(sel_row, 0); if (sel_row > 0) ui.move(sel_row, 0);
} }
fn sortToggle(col: main.SortCol, default_order: main.SortOrder) void { fn sortToggle(col: main.config.SortCol, default_order: main.config.SortOrder) void {
if (main.config.sort_col != col) main.config.sort_order = default_order if (main.config.sort_col != col) main.config.sort_order = default_order
else if (main.config.sort_order == .asc) main.config.sort_order = .desc else if (main.config.sort_order == .asc) main.config.sort_order = .desc
else main.config.sort_order = .asc; else main.config.sort_order = .asc;

View file

@ -9,40 +9,38 @@ const c = @cImport(@cInclude("locale.h"));
pub const allocator = std.heap.c_allocator; pub const allocator = std.heap.c_allocator;
pub const SortCol = enum { name, blocks, size, items, mtime }; pub const config = struct {
pub const SortOrder = enum { asc, desc }; pub const SortCol = enum { name, blocks, size, items, mtime };
pub const SortOrder = enum { asc, desc };
pub const Config = struct { pub var same_fs: bool = true;
same_fs: bool = true, pub var extended: bool = false;
extended: bool = false, pub var follow_symlinks: bool = false;
follow_symlinks: bool = false, pub var exclude_caches: bool = false;
exclude_caches: bool = false, pub var exclude_kernfs: bool = false;
exclude_kernfs: bool = false, pub var exclude_patterns: std.ArrayList([:0]const u8) = std.ArrayList([:0]const u8).init(allocator);
exclude_patterns: std.ArrayList([:0]const u8) = std.ArrayList([:0]const u8).init(allocator),
update_delay: u64 = 100*std.time.ns_per_ms, pub var update_delay: u64 = 100*std.time.ns_per_ms;
scan_ui: enum { none, line, full } = .full, pub var scan_ui: enum { none, line, full } = .full;
si: bool = false, pub var si: bool = false;
nc_tty: bool = false, pub var nc_tty: bool = false;
ui_color: enum { off, dark } = .off, pub var ui_color: enum { off, dark } = .off;
thousands_sep: []const u8 = ".", pub var thousands_sep: []const u8 = ",";
show_hidden: bool = true, pub var show_hidden: bool = true;
show_blocks: bool = true, pub var show_blocks: bool = true;
show_items: bool = false, pub var show_items: bool = false;
show_mtime: bool = false, pub var show_mtime: bool = false;
show_graph: enum { off, graph, percent, both } = .graph, pub var show_graph: enum { off, graph, percent, both } = .graph;
sort_col: SortCol = .blocks, pub var sort_col: SortCol = .blocks;
sort_order: SortOrder = .desc, pub var sort_order: SortOrder = .desc;
sort_dirsfirst: bool = false, pub var sort_dirsfirst: bool = false;
read_only: bool = false, pub var read_only: bool = false;
can_shell: bool = true, pub var can_shell: bool = true;
confirm_quit: bool = false, pub var confirm_quit: bool = false;
}; };
pub var config = Config{};
pub var state: enum { scan, browse } = .browse; pub var state: enum { scan, browse } = .browse;
// Simple generic argument parser, supports getopt_long() style arguments. // Simple generic argument parser, supports getopt_long() style arguments.
@ -298,30 +296,30 @@ test "argument parser" {
const l = L{ .lst = &lst }; const l = L{ .lst = &lst };
const T = struct { const T = struct {
a: Args(L), a: Args(L),
fn opt(self: *@This(), isopt: bool, val: []const u8) void { fn opt(self: *@This(), isopt: bool, val: []const u8) !void {
const o = self.a.next().?; const o = self.a.next().?;
std.testing.expectEqual(isopt, o.opt); try std.testing.expectEqual(isopt, o.opt);
std.testing.expectEqualStrings(val, o.val); try std.testing.expectEqualStrings(val, o.val);
std.testing.expectEqual(o.is(val), isopt); try std.testing.expectEqual(o.is(val), isopt);
} }
fn arg(self: *@This(), val: []const u8) void { fn arg(self: *@This(), val: []const u8) !void {
std.testing.expectEqualStrings(val, self.a.arg()); try std.testing.expectEqualStrings(val, self.a.arg());
} }
}; };
var t = T{ .a = Args(L).init(l) }; var t = T{ .a = Args(L).init(l) };
t.opt(false, "a"); try t.opt(false, "a");
t.opt(true, "-a"); try t.opt(true, "-a");
t.opt(true, "-b"); try t.opt(true, "-b");
t.arg("cd=e"); try t.arg("cd=e");
t.opt(true, "--opt1"); try t.opt(true, "--opt1");
t.arg("arg1"); try t.arg("arg1");
t.opt(true, "--opt2"); try t.opt(true, "--opt2");
t.arg("arg2"); try t.arg("arg2");
t.opt(true, "-x"); try t.opt(true, "-x");
t.arg("foo"); try t.arg("foo");
t.opt(false, ""); try t.opt(false, "");
t.opt(false, "--arg"); try t.opt(false, "--arg");
t.opt(false, ""); try t.opt(false, "");
t.opt(false, "-"); try t.opt(false, "-");
std.testing.expectEqual(t.a.next(), null); try std.testing.expectEqual(t.a.next(), null);
} }

View file

@ -113,6 +113,7 @@ pub const Entry = packed struct {
if (self.ext()) |e| if (self.ext()) |e|
if (p.entry.ext()) |pe| if (p.entry.ext()) |pe|
if (e.mtime > pe.mtime) { pe.mtime = e.mtime; }; if (e.mtime > pe.mtime) { pe.mtime = e.mtime; };
p.items = saturateAdd(p.items, 1);
// Hardlink in a subdirectory with a different device, only count it the first time. // Hardlink in a subdirectory with a different device, only count it the first time.
if (self.link() != null and dev != p.dev) { if (self.link() != null and dev != p.dev) {
@ -128,12 +129,10 @@ pub const Entry = packed struct {
add_total = true; add_total = true;
p.shared_size = saturateAdd(p.shared_size, self.size); p.shared_size = saturateAdd(p.shared_size, self.size);
p.shared_blocks = saturateAdd(p.shared_blocks, self.blocks); p.shared_blocks = saturateAdd(p.shared_blocks, self.blocks);
p.shared_items = saturateAdd(p.shared_items, 1);
// Encountered this file in this dir the same number of times as its link count, meaning it's not shared with other dirs. // Encountered this file in this dir the same number of times as its link count, meaning it's not shared with other dirs.
} else if(d.entry.key.num_files == l.nlink) { } else if(d.entry.key.num_files == l.nlink) {
p.shared_size = saturateSub(p.shared_size, self.size); p.shared_size = saturateSub(p.shared_size, self.size);
p.shared_blocks = saturateSub(p.shared_blocks, self.blocks); p.shared_blocks = saturateSub(p.shared_blocks, self.blocks);
p.shared_items = saturateSub(p.shared_items, 1);
} }
} else { } else {
add_total = true; add_total = true;
@ -141,7 +140,6 @@ pub const Entry = packed struct {
if(add_total) { if(add_total) {
p.entry.size = saturateAdd(p.entry.size, self.size); p.entry.size = saturateAdd(p.entry.size, self.size);
p.entry.blocks = saturateAdd(p.entry.blocks, self.blocks); p.entry.blocks = saturateAdd(p.entry.blocks, self.blocks);
p.total_items = saturateAdd(p.total_items, 1);
} }
} }
} }
@ -161,10 +159,7 @@ pub const Dir = packed struct {
// (space reclaimed by deleting a dir =~ entry. - shared_) // (space reclaimed by deleting a dir =~ entry. - shared_)
shared_blocks: u64, shared_blocks: u64,
shared_size: u64, shared_size: u64,
shared_items: u32, items: u32,
total_items: u32,
// TODO: ncdu1 only keeps track of a total item count including duplicate hardlinks.
// That number seems useful, too. Include it somehow?
// Indexes into the global 'devices' array // Indexes into the global 'devices' array
dev: DevId, dev: DevId,

View file

@ -118,25 +118,25 @@ pub fn shorten(in: [:0]const u8, max_width: u32) ![:0] const u8 {
return try arrayListBufZ(&shorten_buf); return try arrayListBufZ(&shorten_buf);
} }
fn shortenTest(in: [:0]const u8, max_width: u32, out: [:0]const u8) void { fn shortenTest(in: [:0]const u8, max_width: u32, out: [:0]const u8) !void {
std.testing.expectEqualStrings(out, shorten(in, max_width) catch unreachable); try std.testing.expectEqualStrings(out, try shorten(in, max_width));
} }
test "shorten" { test "shorten" {
_ = c.setlocale(c.LC_ALL, ""); // libc wcwidth() may not recognize Unicode without this _ = c.setlocale(c.LC_ALL, ""); // libc wcwidth() may not recognize Unicode without this
const t = shortenTest; const t = shortenTest;
t("abcde", 3, "..."); try t("abcde", 3, "...");
t("abcde", 5, "abcde"); try t("abcde", 5, "abcde");
t("abcde", 4, "...e"); try t("abcde", 4, "...e");
t("abcdefgh", 6, "a...gh"); try t("abcdefgh", 6, "a...gh");
t("abcdefgh", 7, "ab...gh"); try t("abcdefgh", 7, "ab...gh");
t("", 16, ""); try t("", 16, "");
t("", 7, "..."); try t("", 7, "...");
t("", 8, "..."); try t("", 8, "...");
t("", 9, "..."); try t("", 9, "...");
t("a", 8, "..."); // could optimize this, but w/e try t("a", 8, "..."); // could optimize this, but w/e
t("a", 8, "...a"); try t("a", 8, "...a");
t("", 15, "..."); try t("", 15, "...");
} }
// ncurses_refs.c // ncurses_refs.c
@ -167,6 +167,9 @@ const styles = [_]StyleDef{
.{ .name = "bold", .{ .name = "bold",
.off = .{ .fg = -1, .bg = -1, .attr = c.A_BOLD }, .off = .{ .fg = -1, .bg = -1, .attr = c.A_BOLD },
.dark = .{ .fg = -1, .bg = -1, .attr = c.A_BOLD } }, .dark = .{ .fg = -1, .bg = -1, .attr = c.A_BOLD } },
.{ .name = "bold_hd",
.off = .{ .fg = -1, .bg = -1, .attr = c.A_BOLD|c.A_REVERSE },
.dark = .{ .fg = c.COLOR_BLACK, .bg = c.COLOR_CYAN, .attr = c.A_BOLD } },
.{ .name = "box_title", .{ .name = "box_title",
.off = .{ .fg = -1, .bg = -1, .attr = c.A_BOLD }, .off = .{ .fg = -1, .bg = -1, .attr = c.A_BOLD },
.dark = .{ .fg = c.COLOR_BLUE, .bg = -1, .attr = c.A_BOLD } }, .dark = .{ .fg = c.COLOR_BLUE, .bg = -1, .attr = c.A_BOLD } },