+4
-1
CHANGELOG.md
+4
-1
CHANGELOG.md
···
1
# Changelog
2
3
## v0.9.8 (2025-04-04)
4
- fix: Ensure complete Git branch is displayed.
5
- refactor: Audit try usage to improve system resiliance.
6
- refactor: Removed need for enum based notifications.
7
8
## v0.9.7 (2025-04-01)
9
-
- feat: Added ability to copy folders.
10
This is done by (y)anking the file, then (p)asting in the desired directory.
11
This action can be (u)ndone and behind the scenes is a deletion.
12
- fix: Allow the cursor to be moved left and right.
···
1
# Changelog
2
3
+
## v0.9.9 (2025-04-06)
4
+
- feat: Added ability to copy folders.
5
+
6
## v0.9.8 (2025-04-04)
7
- fix: Ensure complete Git branch is displayed.
8
- refactor: Audit try usage to improve system resiliance.
9
- refactor: Removed need for enum based notifications.
10
11
## v0.9.7 (2025-04-01)
12
+
- feat: Added ability to copy files.
13
This is done by (y)anking the file, then (p)asting in the desired directory.
14
This action can be (u)ndone and behind the scenes is a deletion.
15
- fix: Allow the cursor to be moved left and right.
+2
-2
PROJECT_BOARD.md
+2
-2
PROJECT_BOARD.md
+1
-1
build.zig
+1
-1
build.zig
+1
-1
build.zig.zon
+1
-1
build.zig.zon
+106
-23
src/events.zig
+106
-23
src/events.zig
···
174
}) orelse break :lbl null;
175
176
switch (entry.kind) {
177
-
.file => {
178
break :lbl .{
179
.dir = try app.alloc.dupe(u8, app.directories.fullPath(".") catch {
180
message = try std.fmt.allocPrint(
···
206
}
207
}
208
209
-
pub fn paste(app: *App) error{OutOfMemory}!void {
210
var message: ?[]const u8 = null;
211
defer if (message) |msg| app.alloc.free(msg);
212
···
220
};
221
222
switch (yanked.entry.kind) {
223
-
.file => {
224
var source_dir = std.fs.openDirAbsolute(yanked.dir, .{ .iterate = true }) catch {
225
message = try std.fmt.allocPrint(app.alloc, "Failed to copy '{s}' - unable to open directory '{s}'.", .{ yanked.entry.name, yanked.dir });
226
app.notification.write(message.?, .err) catch {};
···
250
},
251
};
252
253
-
// Append action to undo history.
254
-
var new_path_abs_buf: [std.fs.max_path_bytes]u8 = undefined;
255
-
const new_path_abs = app.directories.dir.realpath(new_path_res.path, &new_path_abs_buf) catch {
256
-
message = try std.fmt.allocPrint(
257
-
app.alloc,
258
-
"Failed to push copy action for '{s}' to undo history - unable to retrieve absolute directory path for '{s}'. This action will not be able to be undone via the `undo` keybind.",
259
-
.{ new_path_res.path, yanked.entry.name },
260
-
);
261
-
app.notification.write(message.?, .err) catch {};
262
-
if (app.file_logger) |file_logger| file_logger.write(message.?, .err) catch {};
263
-
return;
264
-
};
265
-
266
-
if (app.actions.push(.{
267
-
.paste = try app.alloc.dupe(u8, new_path_abs),
268
-
})) |prev_elem| {
269
-
app.alloc.free(prev_elem.delete.prev_path);
270
-
app.alloc.free(prev_elem.delete.new_path);
271
-
}
272
-
273
message = try std.fmt.allocPrint(app.alloc, "Copied '{s}'.", .{yanked.entry.name});
274
app.notification.write(message.?, .info) catch {};
275
},
···
278
app.notification.write(message.?, .warn) catch {};
279
return;
280
},
281
}
282
283
try app.repopulateDirectory("");
···
174
}) orelse break :lbl null;
175
176
switch (entry.kind) {
177
+
.file, .directory, .sym_link => {
178
break :lbl .{
179
.dir = try app.alloc.dupe(u8, app.directories.fullPath(".") catch {
180
message = try std.fmt.allocPrint(
···
206
}
207
}
208
209
+
pub fn paste(app: *App) error{ OutOfMemory, NoSpaceLeft }!void {
210
var message: ?[]const u8 = null;
211
defer if (message) |msg| app.alloc.free(msg);
212
···
220
};
221
222
switch (yanked.entry.kind) {
223
+
.directory => {
224
+
var source_dir = std.fs.openDirAbsolute(yanked.dir, .{ .iterate = true }) catch {
225
+
message = try std.fmt.allocPrint(app.alloc, "Failed to copy '{s}' - unable to open directory '{s}'.", .{ yanked.entry.name, yanked.dir });
226
+
app.notification.write(message.?, .err) catch {};
227
+
if (app.file_logger) |file_logger| file_logger.write(message.?, .err) catch {};
228
+
return;
229
+
};
230
+
defer source_dir.close();
231
+
232
+
var selected_dir = source_dir.openDir(yanked.entry.name, .{ .iterate = true }) catch {
233
+
message = try std.fmt.allocPrint(app.alloc, "Failed to copy '{s}' - unable to open directory '{s}'.", .{ yanked.entry.name, yanked.entry.name });
234
+
app.notification.write(message.?, .err) catch {};
235
+
if (app.file_logger) |file_logger| file_logger.write(message.?, .err) catch {};
236
+
return;
237
+
};
238
+
defer selected_dir.close();
239
+
240
+
var walker = selected_dir.walk(app.alloc) catch |err| {
241
+
message = try std.fmt.allocPrint(app.alloc, "Failed to copy '{s}' - unable to walk directory tree due to {}.", .{ yanked.entry.name, err });
242
+
app.notification.write(message.?, .err) catch {};
243
+
if (app.file_logger) |file_logger| file_logger.write(message.?, .err) catch {};
244
+
return;
245
+
};
246
+
defer walker.deinit();
247
+
248
+
// Make initial dir.
249
+
app.directories.dir.makeDir(new_path_res.path) catch |err| {
250
+
message = try std.fmt.allocPrint(app.alloc, "Failed to copy '{s}' - unable to create new directory due to {}.", .{ yanked.entry.name, err });
251
+
app.notification.write(message.?, .err) catch {};
252
+
if (app.file_logger) |file_logger| file_logger.write(message.?, .err) catch {};
253
+
return;
254
+
};
255
+
256
+
var errored = false;
257
+
var inner_path_buf: [std.fs.max_path_bytes]u8 = undefined;
258
+
while (walker.next() catch |err| {
259
+
message = try std.fmt.allocPrint(app.alloc, "Failed to copy one or more files - {}. A partial copy may have taken place.", .{err});
260
+
app.notification.write(message.?, .err) catch {};
261
+
if (app.file_logger) |file_logger| file_logger.write(message.?, .err) catch {};
262
+
return;
263
+
}) |entry| {
264
+
const path = try std.fmt.bufPrint(&inner_path_buf, "{s}{s}{s}", .{ new_path_res.path, std.fs.path.sep_str, entry.path });
265
+
switch (entry.kind) {
266
+
.directory => {
267
+
app.directories.dir.makeDir(path) catch {
268
+
message = try std.fmt.allocPrint(app.alloc, "Failed to copy '{s}' - unable to create containing directory '{s}'.", .{ entry.basename, path });
269
+
app.notification.write(message.?, .err) catch {};
270
+
if (app.file_logger) |file_logger| file_logger.write(message.?, .err) catch {};
271
+
errored = true;
272
+
};
273
+
},
274
+
.file, .sym_link => {
275
+
entry.dir.copyFile(entry.basename, app.directories.dir, path, .{}) catch |err| switch (err) {
276
+
error.FileNotFound => {
277
+
message = try std.fmt.allocPrint(app.alloc, "Failed to copy '{s}' - the original file was deleted or moved.", .{entry.path});
278
+
app.notification.write(message.?, .err) catch {};
279
+
if (app.file_logger) |file_logger| file_logger.write(message.?, .err) catch {};
280
+
errored = true;
281
+
},
282
+
else => {
283
+
message = try std.fmt.allocPrint(app.alloc, "Failed to copy '{s}' - {}.", .{ entry.path, err });
284
+
app.notification.write(message.?, .err) catch {};
285
+
if (app.file_logger) |file_logger| file_logger.write(message.?, .err) catch {};
286
+
errored = true;
287
+
},
288
+
};
289
+
},
290
+
else => {
291
+
message = try std.fmt.allocPrint(app.alloc, "Failed to copy '{s}' - unsupported file type '{}'.", .{ entry.path, entry.kind });
292
+
app.notification.write(message.?, .err) catch {};
293
+
if (app.file_logger) |file_logger| file_logger.write(message.?, .err) catch {};
294
+
errored = true;
295
+
},
296
+
}
297
+
}
298
+
299
+
if (errored) {
300
+
app.notification.write("Failed to copy some items, check the log file for more details.", .err) catch {};
301
+
} else {
302
+
message = try std.fmt.allocPrint(app.alloc, "Copied '{s}'.", .{yanked.entry.name});
303
+
app.notification.write(message.?, .info) catch {};
304
+
}
305
+
},
306
+
.file, .sym_link => {
307
var source_dir = std.fs.openDirAbsolute(yanked.dir, .{ .iterate = true }) catch {
308
message = try std.fmt.allocPrint(app.alloc, "Failed to copy '{s}' - unable to open directory '{s}'.", .{ yanked.entry.name, yanked.dir });
309
app.notification.write(message.?, .err) catch {};
···
333
},
334
};
335
336
message = try std.fmt.allocPrint(app.alloc, "Copied '{s}'.", .{yanked.entry.name});
337
app.notification.write(message.?, .info) catch {};
338
},
···
341
app.notification.write(message.?, .warn) catch {};
342
return;
343
},
344
+
}
345
+
346
+
// Append action to undo history.
347
+
var new_path_abs_buf: [std.fs.max_path_bytes]u8 = undefined;
348
+
const new_path_abs = app.directories.dir.realpath(new_path_res.path, &new_path_abs_buf) catch {
349
+
message = try std.fmt.allocPrint(
350
+
app.alloc,
351
+
"Failed to push copy action for '{s}' to undo history - unable to retrieve absolute directory path for '{s}'. This action will not be able to be undone via the `undo` keybind.",
352
+
.{ new_path_res.path, yanked.entry.name },
353
+
);
354
+
app.notification.write(message.?, .err) catch {};
355
+
if (app.file_logger) |file_logger| file_logger.write(message.?, .err) catch {};
356
+
return;
357
+
};
358
+
359
+
if (app.actions.push(.{
360
+
.paste = try app.alloc.dupe(u8, new_path_abs),
361
+
})) |prev_elem| {
362
+
app.alloc.free(prev_elem.delete.prev_path);
363
+
app.alloc.free(prev_elem.delete.new_path);
364
}
365
366
try app.repopulateDirectory("");