+1
CHANGELOG.md
+1
CHANGELOG.md
+6
-4
PROJECT_BOARD.md
+6
-4
PROJECT_BOARD.md
···
11
11
- [x] File/Folder movement.
12
12
- [x] Copy files.
13
13
- [x] Copy folders.
14
-
- [ ] Keybind to unzip archives.
15
14
- [x] Keybind to hard delete items (bypass trash).
16
15
- [x] Ability to unbind keys.
17
16
···
19
18
- [x] Better error logging.
20
19
There are many places errors could be caught, logged, and handled instead
21
20
of crashing.
21
+
22
+
### Bugs
23
+
- [x] Command history is skipping items on scroll.
24
+
25
+
## Backlog
22
26
- [ ] Improve image reading.
23
27
Current reading can be slow which pauses users movement if they are simply
24
28
scrolling past.
25
-
26
-
### Bugs
27
-
- [ ] Command history is skipping items on scroll.
29
+
- [ ] Keybind to unzip archives.
+1
-4
src/app.zig
+1
-4
src/app.zig
···
149
149
self.alloc.free(yanked.entry.name);
150
150
}
151
151
152
-
self.command_history.resetSelected();
153
-
while (self.command_history.next()) |command| {
154
-
self.alloc.free(command);
155
-
}
152
+
self.command_history.deinit(self.alloc);
156
153
157
154
self.help_menu.deinit();
158
155
self.directories.deinit();
+43
-23
src/commands.zig
+43
-23
src/commands.zig
···
6
6
pub const CommandHistory = struct {
7
7
const history_len = 10;
8
8
9
-
selected: usize = 0,
10
-
len: usize = 0,
11
9
history: [history_len][]const u8 = undefined,
10
+
count: usize = 0,
11
+
///Points to the oldest entry.
12
+
start: usize = 0,
13
+
cursor: ?usize = null,
12
14
13
-
pub fn push(self: *CommandHistory, command: []const u8) ?[]const u8 {
14
-
var deleted: ?[]const u8 = null;
15
-
if (self.len == history_len) {
16
-
deleted = self.history[0];
17
-
for (0..self.len - 1) |i| {
18
-
self.history[i] = self.history[i + 1];
19
-
}
15
+
pub fn deinit(self: *CommandHistory, allocator: std.mem.Allocator) void {
16
+
for (self.history[0..self.count]) |entry| {
17
+
allocator.free(entry);
18
+
}
19
+
}
20
+
21
+
pub fn add(self: *CommandHistory, cmd: []const u8, allocator: std.mem.Allocator) error{OutOfMemory}!void {
22
+
const index = (self.start + self.count) % history_len;
23
+
24
+
if (self.count < history_len) {
25
+
self.count += 1;
20
26
} else {
21
-
self.len += 1;
27
+
// Overwriting the oldest entry.
28
+
allocator.free(self.history[self.start]);
29
+
self.start = (self.start + 1) % history_len;
22
30
}
23
31
24
-
self.history[self.len - 1] = command;
25
-
self.selected = self.len;
32
+
self.history[index] = try allocator.dupe(u8, cmd);
33
+
self.cursor = null;
34
+
}
26
35
27
-
return deleted;
36
+
pub fn previous(self: *CommandHistory) ?[]const u8 {
37
+
if (self.count == 0) return null;
38
+
39
+
if (self.cursor == null) {
40
+
self.cursor = self.count - 1;
41
+
} else if (self.cursor.? > 0) {
42
+
self.cursor.? -= 1;
43
+
}
44
+
45
+
return self.getAtCursor();
28
46
}
29
47
30
48
pub fn next(self: *CommandHistory) ?[]const u8 {
31
-
if (self.selected == 0) return null;
32
-
self.selected -= 1;
33
-
return self.history[self.selected];
34
-
}
49
+
if (self.count == 0 or self.cursor == null) return null;
50
+
51
+
if (self.cursor.? < self.count - 1) {
52
+
self.cursor.? += 1;
53
+
return self.getAtCursor();
54
+
}
35
55
36
-
pub fn previous(self: *CommandHistory) ?[]const u8 {
37
-
if (self.selected + 1 == self.len) return null;
38
-
self.selected += 1;
39
-
return self.history[self.selected];
56
+
self.cursor = null;
57
+
return null;
40
58
}
41
59
42
-
pub fn resetSelected(self: *CommandHistory) void {
43
-
self.selected = self.len;
60
+
fn getAtCursor(self: *CommandHistory) ?[]const u8 {
61
+
if (self.cursor == null) return null;
62
+
const index = (self.start + self.cursor.?) % history_len;
63
+
return self.history[index];
44
64
}
45
65
};
46
66
+9
-7
src/event_handlers.zig
+9
-7
src/event_handlers.zig
···
104
104
try app.repopulateDirectory("");
105
105
app.text_input.clearAndFree();
106
106
},
107
-
.command => app.command_history.resetSelected(),
107
+
.command => app.command_history.cursor = null,
108
108
else => {},
109
109
}
110
110
···
127
127
128
128
// Push command to history if it's not empty.
129
129
if (!std.mem.eql(u8, std.mem.trim(u8, command, " "), ":")) {
130
-
if (app.command_history.push(try app.alloc.dupe(u8, command))) |deleted| {
131
-
app.alloc.free(deleted);
132
-
}
130
+
app.command_history.add(command, app.alloc) catch |err| {
131
+
const message = try std.fmt.allocPrint(app.alloc, "Failed to add command to history - {}.", .{err});
132
+
defer app.alloc.free(message);
133
+
if (app.file_logger) |file_logger| file_logger.write(message, .err) catch {};
134
+
};
133
135
}
134
136
135
137
supported: {
···
167
169
try app.text_input.insertSliceAtCursor(":UnsupportedCommand");
168
170
}
169
171
170
-
app.command_history.resetSelected();
172
+
app.command_history.cursor = null;
171
173
},
172
174
else => {},
173
175
}
···
179
181
Key.right => app.text_input.cursorRight(),
180
182
Key.up => {
181
183
if (app.state == .command) {
182
-
if (app.command_history.next()) |command| {
184
+
if (app.command_history.previous()) |command| {
183
185
app.text_input.clearAndFree();
184
186
app.text_input.insertSliceAtCursor(command) catch |err| {
185
187
const message = try std.fmt.allocPrint(app.alloc, "Failed to get previous command history - {}.", .{err});
···
193
195
Key.down => {
194
196
if (app.state == .command) {
195
197
app.text_input.clearAndFree();
196
-
if (app.command_history.previous()) |command| {
198
+
if (app.command_history.next()) |command| {
197
199
app.text_input.insertSliceAtCursor(command) catch |err| {
198
200
const message = try std.fmt.allocPrint(app.alloc, "Failed to get next command history - {}.", .{err});
199
201
defer app.alloc.free(message);