mirror of
https://code.blicky.net/yorhel/ncdu.git
synced 2026-01-13 01:08:41 -09:00
Support moving files/dirs to trash (fixes #215)
This commit is contained in:
parent
f37362af36
commit
1eac36a7ea
4 changed files with 60 additions and 4 deletions
|
|
@ -13,6 +13,7 @@ pub fn build(b: *std.build.Builder) void {
|
|||
exe.addCSourceFile("src/ncurses_refs.c", &[_][]const u8{});
|
||||
exe.linkLibC();
|
||||
exe.linkSystemLibrary("ncursesw");
|
||||
exe.linkSystemLibrary("gio-2.0");
|
||||
exe.install();
|
||||
|
||||
const run_cmd = exe.run();
|
||||
|
|
|
|||
|
|
@ -583,6 +583,7 @@ const help = struct {
|
|||
"C", "Sort by items (ascending/descending)",
|
||||
"M", "Sort by mtime (-e flag)",
|
||||
"d", "Delete selected file or directory",
|
||||
"D", "Move selected file or directory to trash",
|
||||
"t", "Toggle dirs before files when sorting",
|
||||
"g", "Show percentage and/or graph",
|
||||
"u", "Show/hide hard link shared sizes",
|
||||
|
|
@ -872,6 +873,17 @@ pub fn keyInput(ch: i32) void {
|
|||
delete.setup(dir_parent, e, next);
|
||||
}
|
||||
},
|
||||
'D' => {
|
||||
if (dir_items.items.len == 0) {
|
||||
} else if (dir_items.items[cursor_idx]) |e| {
|
||||
main.state = .trash;
|
||||
const next =
|
||||
if (cursor_idx+1 < dir_items.items.len) dir_items.items[cursor_idx+1]
|
||||
else if (cursor_idx == 0) null
|
||||
else dir_items.items[cursor_idx-1];
|
||||
delete.setupTrash(dir_parent, e, next);
|
||||
}
|
||||
},
|
||||
|
||||
// Sort & filter settings
|
||||
'n' => sortToggle(.name, .asc),
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ const model = @import("model.zig");
|
|||
const ui = @import("ui.zig");
|
||||
const browser = @import("browser.zig");
|
||||
const util = @import("util.zig");
|
||||
const gio = @cImport(@cInclude("gio/gio.h"));
|
||||
const gobject = @cImport(@cInclude("glib-object.h"));
|
||||
|
||||
var parent: *model.Dir = undefined;
|
||||
var entry: *model.Entry = undefined;
|
||||
|
|
@ -24,6 +26,14 @@ pub fn setup(p: *model.Dir, e: *model.Entry, n: ?*model.Entry) void {
|
|||
confirm = .no;
|
||||
}
|
||||
|
||||
pub fn setupTrash(p: *model.Dir, e: *model.Entry, n: ?*model.Entry) void {
|
||||
parent = p;
|
||||
entry = e;
|
||||
next_sel = n;
|
||||
state = .busy;
|
||||
confirm = .no;
|
||||
}
|
||||
|
||||
|
||||
// Returns true to abort scanning.
|
||||
fn err(e: anyerror) bool {
|
||||
|
|
@ -68,6 +78,22 @@ fn deleteItem(dir: std.fs.Dir, path: [:0]const u8, ptr: *align(1) ?*model.Entry)
|
|||
return false;
|
||||
}
|
||||
|
||||
fn trashItem(_: std.fs.Dir, path: [:0]const u8, ptr: *align(1) ?*model.Entry) bool {
|
||||
entry = ptr.*.?;
|
||||
if (main.state != .trash)
|
||||
return true;
|
||||
|
||||
const gfile = gio.g_file_new_for_path(path);
|
||||
defer gobject.g_object_unref(gfile);
|
||||
|
||||
if (gio.g_file_trash(gfile, null, null) > 0) {
|
||||
ptr.*.?.delStats(parent);
|
||||
ptr.* = ptr.*.?.next;
|
||||
}
|
||||
|
||||
return false; // Not used
|
||||
}
|
||||
|
||||
// Returns the item that should be selected in the browser.
|
||||
pub fn delete() ?*model.Entry {
|
||||
while (main.state == .delete and state == .confirm)
|
||||
|
|
@ -75,6 +101,18 @@ pub fn delete() ?*model.Entry {
|
|||
if (main.state != .delete)
|
||||
return entry;
|
||||
|
||||
return performOp(deleteItem);
|
||||
}
|
||||
|
||||
// Returns the item that should be selected in the browser.
|
||||
pub fn trash() ?*model.Entry {
|
||||
if (main.state != .trash)
|
||||
return entry;
|
||||
|
||||
return performOp(trashItem);
|
||||
}
|
||||
|
||||
fn performOp(op: fn (std.fs.Dir, [:0]const u8, *align(1) ?*model.Entry) bool) ?*model.Entry {
|
||||
// Find the pointer to this entry
|
||||
const e = entry;
|
||||
var it = &parent.sub;
|
||||
|
|
@ -89,7 +127,7 @@ pub fn delete() ?*model.Entry {
|
|||
path.append('/') catch unreachable;
|
||||
path.appendSlice(entry.name()) catch unreachable;
|
||||
|
||||
_ = deleteItem(std.fs.cwd(), util.arrayListBufZ(&path), it);
|
||||
_ = op(std.fs.cwd(), util.arrayListBufZ(&path), it);
|
||||
model.inodes.addAllStats();
|
||||
return if (it.* == e) e else next_sel;
|
||||
}
|
||||
|
|
|
|||
11
src/main.zig
11
src/main.zig
|
|
@ -76,7 +76,7 @@ pub const config = struct {
|
|||
pub var ignore_delete_errors: bool = false;
|
||||
};
|
||||
|
||||
pub var state: enum { scan, browse, refresh, shell, delete } = .scan;
|
||||
pub var state: enum { scan, browse, refresh, shell, delete, trash } = .scan;
|
||||
|
||||
// Simple generic argument parser, supports getopt_long() style arguments.
|
||||
const Args = struct {
|
||||
|
|
@ -509,6 +509,11 @@ pub fn main() void {
|
|||
state = .browse;
|
||||
browser.loadDir(next);
|
||||
},
|
||||
.trash => {
|
||||
const next = delete.trash();
|
||||
state = .browse;
|
||||
browser.loadDir(next);
|
||||
},
|
||||
else => handleEvent(true, false)
|
||||
}
|
||||
}
|
||||
|
|
@ -524,7 +529,7 @@ pub fn handleEvent(block: bool, force_draw: bool) void {
|
|||
switch (state) {
|
||||
.scan, .refresh => scan.draw(),
|
||||
.browse => browser.draw(),
|
||||
.delete => delete.draw(),
|
||||
.delete, .trash => delete.draw(),
|
||||
.shell => unreachable,
|
||||
}
|
||||
if (ui.inited) _ = ui.c.refresh();
|
||||
|
|
@ -543,7 +548,7 @@ pub fn handleEvent(block: bool, force_draw: bool) void {
|
|||
switch (state) {
|
||||
.scan, .refresh => scan.keyInput(ch),
|
||||
.browse => browser.keyInput(ch),
|
||||
.delete => delete.keyInput(ch),
|
||||
.delete, .trash => delete.keyInput(ch),
|
||||
.shell => unreachable,
|
||||
}
|
||||
firstblock = false;
|
||||
|
|
|
|||
Loading…
Reference in a new issue