diff --git a/README.md b/README.md index a7fb43e555390f8ed23e40d044c58742fff66373..5edb94b94ec04501f1138cf1cfc2af1c86e1bb09 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ C version (1.x). ## Requirements -- Zig 0.8 or 0.8.1 +- Zig 0.9.0 - Some sort of POSIX-like OS - ncurses libraries and header files diff --git a/src/browser.zig b/src/browser.zig index de1ffa79d6710fe4fb4a70e50fe362c44da8e8db..2f3c1c0b2e66bada1d97b97c92859e0125129adf 100644 --- a/src/browser.zig +++ b/src/browser.zig @@ -8,7 +8,7 @@ const scan = @import("scan.zig"); const delete = @import("delete.zig"); const ui = @import("ui.zig"); const c = @cImport(@cInclude("time.h")); -usingnamespace @import("util.zig"); +const util = @import("util.zig"); // Currently opened directory. pub var dir_parent: *model.Dir = undefined; @@ -188,9 +188,9 @@ const Row = struct { width += 2 + width; defer self.col += width; const item = self.item orelse return; - const siz = if (main.config.show_blocks) blocksToSize(item.blocks) else item.size; - var shr = if (item.dir()) |d| (if (main.config.show_blocks) blocksToSize(d.shared_blocks) else d.shared_size) else 0; - if (main.config.show_shared == .unique) shr = saturateSub(siz, shr); + const siz = if (main.config.show_blocks) util.blocksToSize(item.blocks) else item.size; + var shr = if (item.dir()) |d| (if (main.config.show_blocks) util.blocksToSize(d.shared_blocks) else d.shared_size) else 0; + if (main.config.show_shared == .unique) shr = siz -| shr; ui.move(self.row, self.col); ui.addsize(self.bg, siz); @@ -231,7 +231,7 @@ const Row = struct { var siz: u64 = 0; self.bg.fg(.graph); while (i < bar_size) : (i += 1) { - siz = saturateAdd(siz, perblock); + siz = siz +| perblock; ui.addch(if (siz <= num) '#' else ' '); } } @@ -284,7 +284,7 @@ const Row = struct { if (self.item) |i| { self.bg.fg(if (i.etype == .dir) .dir else .default); ui.addch(if (i.isDirectory()) '/' else ' '); - ui.addstr(ui.shorten(ui.toUtf8(i.name()), saturateSub(ui.cols, self.col + 1))); + ui.addstr(ui.shorten(ui.toUtf8(i.name()), ui.cols -| self.col +| 1)); } else { self.bg.fg(.dir); ui.addstr("/.."); @@ -383,7 +383,7 @@ const info = struct { } fn drawLinks(box: ui.Box, row: *u32, rows: u32, cols: u32) void { - const numrows = saturateSub(rows, 4); + const numrows = rows -| 4; if (links_idx < links_top) links_top = links_idx; if (links_idx >= links_top + numrows) links_top = links_idx - numrows + 1; @@ -396,7 +396,7 @@ const info = struct { ui.addch(if (&e.entry == entry) '*' else ' '); const path = e.path(false); defer main.allocator.free(path); - ui.addstr(ui.shorten(ui.toUtf8(path), saturateSub(cols, 5))); + ui.addstr(ui.shorten(ui.toUtf8(path), cols -| 5)); row.* += 1; } ui.style(.default); @@ -420,7 +420,7 @@ const info = struct { if (shared > 0) { ui.style(.default); drawSizeRow(box, row, " > shared: ", shared); - drawSizeRow(box, row, " > unique: ", saturateSub(size, shared)); + drawSizeRow(box, row, " > unique: ", size -| shared); } } @@ -466,8 +466,8 @@ const info = struct { } // Disk usage & Apparent size - drawSize(box, row, " Disk usage: ", blocksToSize(e.blocks), if (e.dir()) |d| blocksToSize(d.shared_blocks) else 0); - drawSize(box, row, "Apparent size: ", e.size, if (e.dir()) |d| d.shared_size else 0); + drawSize(box, row, " Disk usage: ", util.blocksToSize(e.blocks), if (e.dir()) |d| util.blocksToSize(d.shared_blocks) else 0); + drawSize(box, row, "Apparent size: ", e.size, if (e.dir()) |d| d.shared_size else 0); // Number of items if (e.dir()) |d| { @@ -552,7 +552,7 @@ const info = struct { set(null, .info); } } - if (keyInputSelection(ch, &cursor_idx, dir_items.items.len, saturateSub(ui.rows, 3))) { + if (keyInputSelection(ch, &cursor_idx, dir_items.items.len, ui.rows -| 3)) { set(dir_items.items[cursor_idx], .info); return true; } @@ -725,10 +725,10 @@ pub fn draw() void { ui.style(.hd); ui.addstr(" for help"); if (main.config.imported) { - ui.move(0, saturateSub(ui.cols, 10)); + ui.move(0, ui.cols -| 10); ui.addstr("[imported]"); } else if (!main.config.can_delete.?) { - ui.move(0, saturateSub(ui.cols, 10)); + ui.move(0, ui.cols -| 10); ui.addstr("[readonly]"); } @@ -741,13 +741,13 @@ pub fn draw() void { var pathbuf = std.ArrayList(u8).init(main.allocator); dir_parent.fmtPath(true, &pathbuf); - ui.addstr(ui.shorten(ui.toUtf8(arrayListBufZ(&pathbuf)), saturateSub(ui.cols, 5))); + ui.addstr(ui.shorten(ui.toUtf8(util.arrayListBufZ(&pathbuf)), ui.cols -| 5)); pathbuf.deinit(); ui.style(.default); ui.addch(' '); - const numrows = saturateSub(ui.rows, 3); + const numrows = ui.rows -| 3; if (cursor_idx < current_view.top) current_view.top = cursor_idx; if (cursor_idx >= current_view.top + numrows) current_view.top = cursor_idx - numrows + 1; @@ -770,7 +770,7 @@ pub fn draw() void { ui.move(ui.rows-1, 1); ui.style(if (main.config.show_blocks) .bold_hd else .hd); ui.addstr("Total disk usage: "); - ui.addsize(.hd, blocksToSize(dir_parent.entry.blocks)); + ui.addsize(.hd, util.blocksToSize(dir_parent.entry.blocks)); ui.style(if (main.config.show_blocks) .hd else .bold_hd); ui.addstr(" Apparent size: "); ui.addsize(.hd, dir_parent.entry.size); @@ -810,9 +810,9 @@ fn keyInputSelection(ch: i32, idx: *usize, len: usize, page: u32) bool { if (idx.* > 0) idx.* -= 1; }, ui.c.KEY_HOME => idx.* = 0, - ui.c.KEY_END, ui.c.KEY_LL => idx.* = saturateSub(len, 1), - ui.c.KEY_PPAGE => idx.* = saturateSub(idx.*, page), - ui.c.KEY_NPAGE => idx.* = std.math.min(saturateSub(len, 1), idx.* + page), + ui.c.KEY_END, ui.c.KEY_LL => idx.* = len -| 1, + ui.c.KEY_PPAGE => idx.* = idx.* -| page, + ui.c.KEY_NPAGE => idx.* = std.math.min(len -| 1, idx.* + page), else => return false, } return true; @@ -930,6 +930,6 @@ pub fn keyInput(ch: i32) void { .unique => .off, }, - else => _ = keyInputSelection(ch, &cursor_idx, dir_items.items.len, saturateSub(ui.rows, 3)), + else => _ = keyInputSelection(ch, &cursor_idx, dir_items.items.len, ui.rows -| 3), } } diff --git a/src/delete.zig b/src/delete.zig index b9e68510adad9745242060b9ccbf8b97f3a96b39..663035ffb2566c4870be23963203afb22dd12c90 100644 --- a/src/delete.zig +++ b/src/delete.zig @@ -6,7 +6,7 @@ const main = @import("main.zig"); const model = @import("model.zig"); const ui = @import("ui.zig"); const browser = @import("browser.zig"); -usingnamespace @import("util.zig"); +const util = @import("util.zig"); var parent: *model.Dir = undefined; var entry: *model.Entry = undefined; @@ -89,7 +89,7 @@ pub fn delete() ?*model.Entry { path.append('/') catch unreachable; path.appendSlice(entry.name()) catch unreachable; - _ = deleteItem(std.fs.cwd(), arrayListBufZ(&path), it); + _ = deleteItem(std.fs.cwd(), util.arrayListBufZ(&path), it); model.inodes.addAllStats(); return if (it.* == e) e else next_sel; } @@ -132,7 +132,7 @@ fn drawProgress() void { const box = ui.Box.create(6, 60, "Deleting..."); box.move(2, 2); - ui.addstr(ui.shorten(ui.toUtf8(arrayListBufZ(&path)), 56)); + ui.addstr(ui.shorten(ui.toUtf8(util.arrayListBufZ(&path)), 56)); box.move(4, 41); ui.addstr("Press "); ui.style(.key); @@ -151,7 +151,7 @@ fn drawErr() void { const box = ui.Box.create(6, 60, "Error"); box.move(1, 2); ui.addstr("Error deleting "); - ui.addstr(ui.shorten(ui.toUtf8(arrayListBufZ(&path)), 41)); + ui.addstr(ui.shorten(ui.toUtf8(util.arrayListBufZ(&path)), 41)); box.move(2, 4); ui.addstr(ui.errorString(error_code)); diff --git a/src/main.zig b/src/main.zig index e7b7786904f7448ccbf2e6ccbdca52f5a9289cef..d98a4fc643647a1e16801bae6d7d0c42ed9695f9 100644 --- a/src/main.zig +++ b/src/main.zig @@ -16,27 +16,25 @@ const c = @cImport(@cInclude("locale.h")); // This allocator never returns an error, it either succeeds or causes ncdu to quit. // (Which means you'll find a lot of "catch unreachable" sprinkled through the code, // they look scarier than they are) -fn wrapAlloc(alloc: *std.mem.Allocator, len: usize, alignment: u29, len_align: u29, return_address: usize) error{OutOfMemory}![]u8 { +fn wrapAlloc(_: *anyopaque, len: usize, alignment: u29, len_align: u29, return_address: usize) error{OutOfMemory}![]u8 { while (true) { - if (std.heap.c_allocator.allocFn(alloc, len, alignment, len_align, return_address)) |r| + if (std.heap.c_allocator.vtable.alloc(undefined, len, alignment, len_align, return_address)) |r| return r else |_| {} ui.oom(); } } -fn wrapResize(alloc: *std.mem.Allocator, buf: []u8, buf_align: u29, new_len: usize, len_align: u29, return_address: usize) std.mem.Allocator.Error!usize { - // AFAIK, all uses of resizeFn to grow an allocation will fall back to allocFn on failure. - return std.heap.c_allocator.resizeFn(alloc, buf, buf_align, new_len, len_align, return_address); -} - -var allocator_state = std.mem.Allocator{ - .allocFn = wrapAlloc, - .resizeFn = wrapResize, +pub const allocator = std.mem.Allocator{ + .ptr = undefined, + .vtable = &.{ + .alloc = wrapAlloc, + // AFAIK, all uses of resize() to grow an allocation will fall back to alloc() on failure. + .resize = std.heap.c_allocator.vtable.resize, + .free = std.heap.c_allocator.vtable.free, + }, }; -pub const allocator = &allocator_state; -//var general_purpose_allocator = std.heap.GeneralPurposeAllocator(.{}){}; -//pub const allocator = &general_purpose_allocator.allocator; + pub const config = struct { pub const SortCol = enum { name, blocks, size, items, mtime }; @@ -388,7 +386,7 @@ pub fn main() void { _ = c.setlocale(c.LC_ALL, ""); if (c.localeconv()) |locale| { if (locale.*.thousands_sep) |sep| { - const span = std.mem.spanZ(sep); + const span = std.mem.sliceTo(sep, 0); if (span.len > 0) config.thousands_sep = span; } @@ -444,7 +442,7 @@ pub fn main() void { } } - if (std.builtin.os.tag != .linux and config.exclude_kernfs) + if (@import("builtin").os.tag != .linux and config.exclude_kernfs) ui.die("The --exclude-kernfs tag is currently only supported on Linux.\n", .{}); const out_tty = std.io.getStdOut().isTty(); diff --git a/src/model.zig b/src/model.zig index 5d611ba6fbe4e8c1e94aa3ea7082aa3cc406cf56..1839b7e57f44fbddf6a8cd5170d220f4d471ffbf 100644 --- a/src/model.zig +++ b/src/model.zig @@ -4,7 +4,7 @@ const std = @import("std"); const main = @import("main.zig"); const ui = @import("ui.zig"); -usingnamespace @import("util.zig"); +const util = @import("util.zig"); // While an arena allocator is optimimal for almost all scenarios in which ncdu // is used, it doesn't allow for re-using deleted nodes after doing a delete or @@ -12,9 +12,10 @@ usingnamespace @import("util.zig"); // will leak memory, but I'd say that's worth the efficiency gains. // TODO: Can still implement a simple bucketed free list on top of this arena // allocator to reuse nodes, if necessary. -var allocator = std.heap.ArenaAllocator.init(std.heap.page_allocator); +var allocator_state = std.heap.ArenaAllocator.init(std.heap.page_allocator); +const allocator = allocator_state.allocator(); -pub const EType = packed enum(u2) { dir, link, file }; +pub const EType = enum(u2) { dir, link, file }; // Type for the Entry.blocks field. Smaller than a u64 to make room for flags. pub const Blocks = u60; @@ -66,15 +67,15 @@ pub const Entry = packed struct { fn nameOffset(etype: EType) usize { return switch (etype) { - .dir => @byteOffsetOf(Dir, "name"), - .link => @byteOffsetOf(Link, "name"), - .file => @byteOffsetOf(File, "name"), + .dir => @offsetOf(Dir, "name"), + .link => @offsetOf(Link, "name"), + .file => @offsetOf(File, "name"), }; } pub fn name(self: *const Self) [:0]const u8 { const ptr = @ptrCast([*:0]const u8, self) + nameOffset(self.etype); - return ptr[0..std.mem.lenZ(ptr) :0]; + return std.mem.sliceTo(ptr, 0); } pub fn ext(self: *Self) ?*Ext { @@ -87,7 +88,7 @@ pub const Entry = packed struct { const size = nameOffset(etype) + ename.len + 1 + extsize; var ptr = blk: { while (true) { - if (allocator.allocator.allocWithOptions(u8, size, std.math.max(@alignOf(Ext), @alignOf(Entry)), null)) |p| + if (allocator.allocWithOptions(u8, size, std.math.max(@alignOf(Ext), @alignOf(Entry)), null)) |p| break :blk p else |_| {} ui.oom(); @@ -124,7 +125,7 @@ pub const Entry = packed struct { var d = inodes.map.getOrPut(l) catch unreachable; if (!d.found_existing) { d.value_ptr.* = .{ .counted = false, .nlink = nlink }; - inodes.total_blocks = saturateAdd(inodes.total_blocks, self.blocks); + inodes.total_blocks +|= self.blocks; l.next = l; } else { inodes.setStats(.{ .key_ptr = d.key_ptr, .value_ptr = d.value_ptr }, false); @@ -142,10 +143,10 @@ pub const Entry = packed struct { if (self.ext()) |e| if (p.entry.ext()) |pe| if (e.mtime > pe.mtime) { pe.mtime = e.mtime; }; - p.items = saturateAdd(p.items, 1); + p.items +|= 1; if (self.etype != .link) { - p.entry.size = saturateAdd(p.entry.size, self.size); - p.entry.blocks = saturateAdd(p.entry.blocks, self.blocks); + p.entry.size +|= self.size; + p.entry.blocks +|= self.blocks; } } } @@ -174,7 +175,7 @@ pub const Entry = packed struct { if (l.next == l) { _ = inodes.map.remove(l); _ = inodes.uncounted.remove(l); - inodes.total_blocks = saturateSub(inodes.total_blocks, self.blocks); + inodes.total_blocks -|= self.blocks; } else { if (d.key_ptr.* == l) d.key_ptr.* = l.next; @@ -193,10 +194,10 @@ pub const Entry = packed struct { var it: ?*Dir = parent; while(it) |p| : (it = p.parent) { - p.items = saturateSub(p.items, 1); + p.items -|= 1; if (self.etype != .link) { - p.entry.size = saturateSub(p.entry.size, self.size); - p.entry.blocks = saturateSub(p.entry.blocks, self.blocks); + p.entry.size -|= self.size; + p.entry.blocks -|= self.blocks; } } } @@ -234,7 +235,7 @@ pub const Dir = packed struct { err: bool, suberr: bool, - // Only used to find the @byteOffsetOff, the name is written at this point as a 0-terminated string. + // Only used to find the @offsetOff, the name is written at this point as a 0-terminated string. // (Old C habits die hard) name: u8, @@ -418,20 +419,20 @@ pub const inodes = struct { var dir_iter = dirs.iterator(); if (add) { while (dir_iter.next()) |de| { - de.key_ptr.*.entry.blocks = saturateAdd(de.key_ptr.*.entry.blocks, entry.key_ptr.*.entry.blocks); - de.key_ptr.*.entry.size = saturateAdd(de.key_ptr.*.entry.size, entry.key_ptr.*.entry.size); + de.key_ptr.*.entry.blocks +|= entry.key_ptr.*.entry.blocks; + de.key_ptr.*.entry.size +|= entry.key_ptr.*.entry.size; if (de.value_ptr.* < nlink) { - de.key_ptr.*.shared_blocks = saturateAdd(de.key_ptr.*.shared_blocks, entry.key_ptr.*.entry.blocks); - de.key_ptr.*.shared_size = saturateAdd(de.key_ptr.*.shared_size, entry.key_ptr.*.entry.size); + de.key_ptr.*.shared_blocks +|= entry.key_ptr.*.entry.blocks; + de.key_ptr.*.shared_size +|= entry.key_ptr.*.entry.size; } } } else { while (dir_iter.next()) |de| { - de.key_ptr.*.entry.blocks = saturateSub(de.key_ptr.*.entry.blocks, entry.key_ptr.*.entry.blocks); - de.key_ptr.*.entry.size = saturateSub(de.key_ptr.*.entry.size, entry.key_ptr.*.entry.size); + de.key_ptr.*.entry.blocks -|= entry.key_ptr.*.entry.blocks; + de.key_ptr.*.entry.size -|= entry.key_ptr.*.entry.size; if (de.value_ptr.* < nlink) { - de.key_ptr.*.shared_blocks = saturateSub(de.key_ptr.*.shared_blocks, entry.key_ptr.*.entry.blocks); - de.key_ptr.*.shared_size = saturateSub(de.key_ptr.*.shared_size, entry.key_ptr.*.entry.size); + de.key_ptr.*.shared_blocks -|= entry.key_ptr.*.entry.blocks; + de.key_ptr.*.shared_size -|= entry.key_ptr.*.entry.size; } } } diff --git a/src/scan.zig b/src/scan.zig index ed92a353b74db5457ff6507beff87a235682861a..01b01a0a6d0a66f9e022b4afb217358334d388ba 100644 --- a/src/scan.zig +++ b/src/scan.zig @@ -5,7 +5,7 @@ const std = @import("std"); const main = @import("main.zig"); const model = @import("model.zig"); const ui = @import("ui.zig"); -usingnamespace @import("util.zig"); +const util = @import("util.zig"); const c_statfs = @cImport(@cInclude("sys/vfs.h")); const c_fnmatch = @cImport(@cInclude("fnmatch.h")); @@ -24,25 +24,25 @@ const Stat = struct { ext: model.Ext = .{}, fn clamp(comptime T: type, comptime field: anytype, x: anytype) std.meta.fieldInfo(T, field).field_type { - return castClamp(std.meta.fieldInfo(T, field).field_type, x); + return util.castClamp(std.meta.fieldInfo(T, field).field_type, x); } fn truncate(comptime T: type, comptime field: anytype, x: anytype) std.meta.fieldInfo(T, field).field_type { - return castTruncate(std.meta.fieldInfo(T, field).field_type, x); + return util.castTruncate(std.meta.fieldInfo(T, field).field_type, x); } fn read(parent: std.fs.Dir, name: [:0]const u8, follow: bool) !Stat { - const stat = try std.os.fstatatZ(parent.fd, name, if (follow) 0 else std.os.AT_SYMLINK_NOFOLLOW); + const stat = try std.os.fstatatZ(parent.fd, name, if (follow) 0 else std.os.AT.SYMLINK_NOFOLLOW); return Stat{ .blocks = clamp(Stat, .blocks, stat.blocks), .size = clamp(Stat, .size, stat.size), .dev = truncate(Stat, .dev, stat.dev), .ino = truncate(Stat, .ino, stat.ino), .nlink = clamp(Stat, .nlink, stat.nlink), - .hlinkc = stat.nlink > 1 and !std.os.system.S_ISDIR(stat.mode), - .dir = std.os.system.S_ISDIR(stat.mode), - .reg = std.os.system.S_ISREG(stat.mode), - .symlink = std.os.system.S_ISLNK(stat.mode), + .hlinkc = stat.nlink > 1 and !std.os.system.S.ISDIR(stat.mode), + .dir = std.os.system.S.ISDIR(stat.mode), + .reg = std.os.system.S.ISREG(stat.mode), + .symlink = std.os.system.S.ISLNK(stat.mode), .ext = .{ .mtime = clamp(model.Ext, .mtime, stat.mtime().tv_sec), .uid = truncate(model.Ext, .uid, stat.uid), @@ -141,7 +141,7 @@ const ScanDir = struct { var count: Map.Size = 0; var it = dir.sub; while (it) |e| : (it = e.next) count += 1; - self.entries.ensureCapacity(count) catch unreachable; + self.entries.ensureUnusedCapacity(count) catch unreachable; it = dir.sub; while (it) |e| : (it = e.next) @@ -345,7 +345,7 @@ const Context = struct { } fn pathZ(self: *Self) [:0]const u8 { - return arrayListBufZ(&self.path); + return util.arrayListBufZ(&self.path); } // Set a flag to indicate that there was an error listing file entries in the current directory. @@ -396,7 +396,7 @@ const Context = struct { try w.writeAll("{\"name\":"); try writeJsonString(w, self.name); if (self.stat.size > 0) try w.print(",\"asize\":{d}", .{ self.stat.size }); - if (self.stat.blocks > 0) try w.print(",\"dsize\":{d}", .{ blocksToSize(self.stat.blocks) }); + if (self.stat.blocks > 0) try w.print(",\"dsize\":{d}", .{ util.blocksToSize(self.stat.blocks) }); if (self.stat.dir and self.stat.dev != dir_dev) try w.print(",\"dev\":{d}", .{ self.stat.dev }); if (self.stat.hlinkc) try w.print(",\"ino\":{d},\"hlnkc\":true,\"nlink\":{d}", .{ self.stat.ino, self.stat.nlink }); if (!self.stat.dir and !self.stat.reg) try w.writeAll(",\"notreg\":true"); @@ -508,7 +508,7 @@ fn scanDir(ctx: *Context, dir: std.fs.Dir, dir_dev: u64) void { } else null; defer if (edir != null) edir.?.close(); - if (std.builtin.os.tag == .linux and main.config.exclude_kernfs and ctx.stat.dir and isKernfs(edir.?, ctx.stat.dev)) { + if (@import("builtin").os.tag == .linux and main.config.exclude_kernfs and ctx.stat.dir and isKernfs(edir.?, ctx.stat.dev)) { ctx.addSpecial(.kernfs); continue; } @@ -980,18 +980,18 @@ var animation_pos: u32 = 0; var need_confirm_quit = false; fn drawError(err: anyerror) void { - const width = saturateSub(ui.cols, 5); + const width = ui.cols -| 5; const box = ui.Box.create(7, width, "Scan error"); box.move(2, 2); ui.addstr("Path: "); - ui.addstr(ui.shorten(ui.toUtf8(active_context.last_error.?), saturateSub(width, 10))); + ui.addstr(ui.shorten(ui.toUtf8(active_context.last_error.?), width -| 10)); box.move(3, 2); ui.addstr("Error: "); - ui.addstr(ui.shorten(ui.errorString(err), saturateSub(width, 6))); + ui.addstr(ui.shorten(ui.errorString(err), width -| 6)); - box.move(5, saturateSub(width, 27)); + box.move(5, width -| 27); ui.addstr("Press any key to continue"); } @@ -999,7 +999,7 @@ fn drawBox() void { ui.init(); const ctx = active_context; if (ctx.fatal_error) |err| return drawError(err); - const width = saturateSub(ui.cols, 5); + const width = ui.cols -| 5; const box = ui.Box.create(10, width, "Scanning..."); box.move(2, 2); ui.addstr("Total items: "); @@ -1009,12 +1009,12 @@ fn drawBox() void { box.move(2, 30); ui.addstr("size: "); // TODO: Should display the size of the dir-to-be-refreshed on refreshing, not the root. - ui.addsize(.default, blocksToSize(saturateAdd(model.root.entry.blocks, model.inodes.total_blocks))); + ui.addsize(.default, util.blocksToSize(model.root.entry.blocks +| model.inodes.total_blocks)); } box.move(3, 2); ui.addstr("Current item: "); - ui.addstr(ui.shorten(ui.toUtf8(ctx.pathZ()), saturateSub(width, 18))); + ui.addstr(ui.shorten(ui.toUtf8(ctx.pathZ()), width -| 18)); if (ctx.last_error) |path| { box.move(5, 2); @@ -1022,20 +1022,20 @@ fn drawBox() void { ui.addstr("Warning: "); ui.style(.default); ui.addstr("error scanning "); - ui.addstr(ui.shorten(ui.toUtf8(path), saturateSub(width, 28))); + ui.addstr(ui.shorten(ui.toUtf8(path), width -| 28)); box.move(6, 3); ui.addstr("some directory sizes may not be correct."); } if (need_confirm_quit) { - box.move(8, saturateSub(width, 20)); + box.move(8, width -| 20); ui.addstr("Press "); ui.style(.key); ui.addch('y'); ui.style(.default); ui.addstr(" to confirm"); } else { - box.move(8, saturateSub(width, 18)); + box.move(8, width -| 18); ui.addstr("Press "); ui.style(.key); ui.addch('q'); @@ -1074,7 +1074,7 @@ pub fn draw() void { .{ ui.shorten(active_context.pathZ(), 63), active_context.items_seen } ) catch return; } else { - const r = ui.FmtSize.fmt(blocksToSize(model.root.entry.blocks)); + const r = ui.FmtSize.fmt(util.blocksToSize(model.root.entry.blocks)); line = std.fmt.bufPrint(&buf, "\x1b7\x1b[J{s: <51} {d:>9} files / {s}{s}\x1b8", .{ ui.shorten(active_context.pathZ(), 51), active_context.items_seen, r.num(), r.unit } ) catch return; diff --git a/src/ui.zig b/src/ui.zig index 08fbdea865a0e7d2c345fc1ed8a8f6c14429efd2..c2cfb5c29448383c4ab4af68c0923a632408e49e 100644 --- a/src/ui.zig +++ b/src/ui.zig @@ -5,7 +5,7 @@ const std = @import("std"); const main = @import("main.zig"); -usingnamespace @import("util.zig"); +const util = @import("util.zig"); pub const c = @cImport({ @cInclude("stdio.h"); @@ -73,7 +73,7 @@ pub fn errorString(e: anyerror) [:0]const u8 { error.ReadOnlyFilesystem => "Read-only filesystem", error.SymlinkLoop => "Symlink loop", error.SystemFdQuotaExceeded => "System file descriptor limit exceeded", - else => @bitCast([:0]const u8, @errorName(e)), // XXX: The bitCast can be removed after a Zig >0.8 release. + else => @errorName(e), }; } @@ -113,7 +113,7 @@ pub fn toUtf8(in: [:0]const u8) [:0]const u8 { to_utf8_buf.writer().print("\\x{X:0>2}", .{in[i]}) catch unreachable; i += 1; } - return arrayListBufZ(&to_utf8_buf); + return util.arrayListBufZ(&to_utf8_buf); } var shorten_buf = std.ArrayList(u8).init(main.allocator); @@ -163,7 +163,7 @@ pub fn shorten(in: [:0]const u8, max_width: u32) [:0] const u8 { break; } } - return arrayListBufZ(&shorten_buf); + return util.arrayListBufZ(&shorten_buf); } fn shortenTest(in: [:0]const u8, max_width: u32, out: [:0]const u8) !void { @@ -348,7 +348,7 @@ pub fn init() void { clearScr(); if (main.config.nc_tty) { var tty = c.fopen("/dev/tty", "r+"); - if (tty == null) die("Error opening /dev/tty: {s}.\n", .{ c.strerror(std.c.getErrno(-1)) }); + if (tty == null) die("Error opening /dev/tty: {s}.\n", .{ c.strerror(@enumToInt(std.c.getErrno(-1))) }); var term = c.newterm(null, tty, tty); if (term == null) die("Error initializing ncurses.\n", .{}); _ = c.set_term(term); @@ -439,7 +439,7 @@ pub const FmtSize = struct { } pub fn num(self: *const @This()) [:0]const u8 { - return std.mem.spanZ(&self.buf); + return std.mem.sliceTo(&self.buf, 0); } }; @@ -478,14 +478,14 @@ pub fn addnum(bg: Bg, v: u64) void { // Print a file mode, takes 10 columns pub fn addmode(mode: u32) void { - addch(switch (mode & std.os.S_IFMT) { - std.os.S_IFDIR => 'd', - std.os.S_IFREG => '-', - std.os.S_IFLNK => 'l', - std.os.S_IFIFO => 'p', - std.os.S_IFSOCK => 's', - std.os.S_IFCHR => 'c', - std.os.S_IFBLK => 'b', + addch(switch (mode & std.os.S.IFMT) { + std.os.S.IFDIR => 'd', + std.os.S.IFREG => '-', + std.os.S.IFLNK => 'l', + std.os.S.IFIFO => 'p', + std.os.S.IFSOCK => 's', + std.os.S.IFCHR => 'c', + std.os.S.IFBLK => 'b', else => '?' }); addch(if (mode & 0o400 > 0) 'r' else '-'); @@ -496,12 +496,12 @@ pub fn addmode(mode: u32) void { addch(if (mode & 0o2000 > 0) 's' else if (mode & 0o010 > 0) @as(u7, 'x') else '-'); addch(if (mode & 0o004 > 0) 'r' else '-'); addch(if (mode & 0o002 > 0) 'w' else '-'); - addch(if (mode & 0o1000 > 0) (if (std.os.S_ISDIR(mode)) @as(u7, 't') else 'T') else if (mode & 0o001 > 0) @as(u7, 'x') else '-'); + addch(if (mode & 0o1000 > 0) (if (std.os.S.ISDIR(mode)) @as(u7, 't') else 'T') else if (mode & 0o001 > 0) @as(u7, 'x') else '-'); } // Print a timestamp, takes 25 columns pub fn addts(bg: Bg, ts: u64) void { - const t = castClamp(c.time_t, ts); + const t = util.castClamp(c.time_t, ts); var buf: [32:0]u8 = undefined; const len = c.strftime(&buf, buf.len, "%Y-%m-%d %H:%M:%S %z", c.localtime(&t)); if (len > 0) { @@ -526,8 +526,8 @@ pub const Box = struct { pub fn create(height: u32, width: u32, title: [:0]const u8) Self { const s = Self{ - .start_row = saturateSub(rows>>1, height>>1), - .start_col = saturateSub(cols>>1, width>>1), + .start_row = (rows>>1) -| (height>>1), + .start_col = (cols>>1) -| (width>>1), }; style(.default); if (width < 6 or height < 3) return s; @@ -597,5 +597,5 @@ pub fn getch(block: bool) i32 { return ch; } die("Error reading keyboard input, assuming TTY has been lost.\n(Potentially nonsensical error message: {s})\n", - .{ c.strerror(std.c.getErrno(-1)) }); + .{ c.strerror(@enumToInt(std.c.getErrno(-1))) }); } diff --git a/src/util.zig b/src/util.zig index 4c5c8a930adc8130581b572e64fa026b02796b99..e6191af8a8bff75212de64cd18ebaffbf528bd74 100644 --- a/src/util.zig +++ b/src/util.zig @@ -3,16 +3,6 @@ const std = @import("std"); -pub fn saturateAdd(a: anytype, b: @TypeOf(a)) @TypeOf(a) { - std.debug.assert(@typeInfo(@TypeOf(a)).Int.signedness == .unsigned); - return std.math.add(@TypeOf(a), a, b) catch std.math.maxInt(@TypeOf(a)); -} - -pub fn saturateSub(a: anytype, b: @TypeOf(a)) @TypeOf(a) { - std.debug.assert(@typeInfo(@TypeOf(a)).Int.signedness == .unsigned); - return std.math.sub(@TypeOf(a), a, b) catch std.math.minInt(@TypeOf(a)); -} - // Cast any integer type to the target type, clamping the value to the supported maximum if necessary. pub fn castClamp(comptime T: type, x: anytype) T { // (adapted from std.math.cast)