srctree

Gregory Mullen parent 02382f0d 3124c70d
fixup history searching a bit

it's still a bit buggy, but it mostly works, and it's laid out a lot better-ish now.
src/history.zig added: 93, removed: 66, total 27
@@ -6,7 +6,6 @@ pub const History = @This();
alloc: ?std.mem.Allocator = null,
seen_list: ?std.ArrayList([]const u8) = null,
file: ?std.fs.File,
cnt: usize = 0,
 
fn seenAdd(self: *History, seen: []const u8) void {
if (self.seen_list) |*sl| {
@@ -75,9 +74,9 @@ fn readLinePrev(self: *History, buffer: ?*std.ArrayList(u8)) !bool {
return self.readLine(buffer);
}
 
pub fn readAt(self: *History, buffer: *std.ArrayList(u8)) bool {
pub fn readAt(self: *History, position: usize, buffer: *std.ArrayList(u8)) bool {
var hfile = self.file orelse return false;
var row = self.cnt;
var row = position;
hfile.seekFromEnd(0) catch return false;
while (row > 0) {
if (!(readLinePrev(self, null) catch false)) break;
@@ -86,9 +85,14 @@ pub fn readAt(self: *History, buffer: *std.ArrayList(u8)) bool {
return readLinePrev(self, buffer) catch false;
}
 
pub fn readAtFiltered(self: *History, buffer: *std.ArrayList(u8), search: []const u8) bool {
pub fn readAtFiltered(
self: *History,
position: usize,
search: []const u8,
buffer: *std.ArrayList(u8),
) bool {
var hfile = self.file orelse return false;
var row = self.cnt;
var row = position;
hfile.seekFromEnd(-1) catch return false;
defer self.seenReset();
while (row > 0) {
 
src/input.zig added: 93, removed: 66, total 27
@@ -233,19 +233,20 @@ pub fn nonInteractive(input: Input) errors!Event {
pub fn interactive(input: Input) errors!Event {
var buffer: [1]u8 = undefined;
 
var nbyte: usize = input.read(&buffer) catch |err| {
log.err("unable to read {}", .{err});
return error.io;
};
while (nbyte == 0) {
if (input.spin) |spin| if (spin(input.hsh)) return error.signaled;
nbyte = input.read(&buffer) catch |err| {
while (true) {
if (input.read(&buffer) catch |err| {
log.err("unable to read {}", .{err});
return error.io;
};
}
} == 0) {
if (input.spin) |spin| {
if (spin(input.hsh))
return error.signaled;
}
continue;
}
 
if (Keys.translate(buffer[0], input.stdin)) |key| {
return toChar(key);
} else |_| unreachable;
if (Keys.translate(buffer[0], input.stdin)) |key| {
return toChar(key);
} else |_| unreachable;
}
}
 
src/line.zig added: 93, removed: 66, total 27
@@ -9,17 +9,23 @@ mode: union(enum) {
external_editor: []u8,
},
history: History = undefined,
history_position: ?usize = null,
history_search: ?[]const u8 = null,
completion: Complete.CompSet,
text: []u8,
 
usr_line: [1024]u8 = undefined,
 
const Line = @This();
 
pub const Options = struct {
interactive: bool = true,
};
 
const Action = enum {
exec,
empty,
external,
};
 
pub fn init(hsh: *HSH, a: Allocator, options: Options) !Line {
return .{
.hsh = hsh,
@@ -55,18 +61,18 @@ pub fn peek(line: Line) []const u8 {
return line.tkn.raw.items;
}
 
fn core(line: *Line) !void {
fn core(line: *Line) !Action {
while (true) {
const input = switch (line.mode) {
.interactive => line.input.interactive(),
.scripted => line.input.nonInteractive(),
.external_editor => return error.PassToExternEditor,
.external_editor => return .external,
} catch |err| switch (err) {
error.io => return err,
error.signaled => {
Draw.clearCtx(&line.hsh.draw);
try Draw.render(&line.hsh.draw);
return error.SendEmpty;
return .empty;
},
error.end_of_text => return error.FIXME,
};
@@ -99,14 +105,17 @@ fn core(line: *Line) !void {
.char => |c| try line.char(c),
.control => |ctrl| {
switch (ctrl.c) {
.esc => continue,
.esc => {
// TODO reset many
continue;
},
.up => line.findHistory(.up),
.down => line.findHistory(.down),
.left => line.tkn.move(.dec),
.right => line.tkn.move(.inc),
.backspace => line.tkn.pop(),
.newline => return,
.end_of_text => return,
.newline => return .exec,
.end_of_text => return .exec,
.delete_word => _ = try line.tkn.dropWord(),
.tab => try line.complete(),
else => |els| log.warn("unknown {}\n", .{els}),
@@ -118,7 +127,7 @@ fn core(line: *Line) !void {
 
else => |el| {
log.err("uncaptured {}\n", .{el});
return;
unreachable;
},
}
}
@@ -126,20 +135,21 @@ fn core(line: *Line) !void {
 
pub fn do(line: *Line) ![]u8 {
while (true) {
line.core() catch |err| switch (err) {
error.PassToExternEditor => return try line.externEditorRead(),
error.SendEmpty => return try line.alloc.dupe(u8, ""),
error.FIXME => return try line.alloc.dupe(u8, line.tkn.raw.items),
else => return err,
return switch (try line.core()) {
.external => try line.externEditorRead(),
.empty => continue,
.exec => {
if (line.peek().len > 0) {
return try line.dupeText();
}
 
line.hsh.draw.newline();
line.hsh.draw.clear();
try Prompt.draw(line.hsh, line.peek());
try line.hsh.draw.render();
continue;
},
};
if (line.peek().len > 0) {
return line.dupeText();
} else {
line.hsh.draw.newline();
line.hsh.draw.clear();
try Prompt.draw(line.hsh, line.peek());
try line.hsh.draw.render();
}
}
}
 
@@ -183,37 +193,47 @@ fn findHistory(line: *Line, dr: enum { up, down }) void {
 
switch (dr) {
.up => {
defer history.cnt += 1;
if (history.cnt == 0) {
if (tkn.user_data == true) {
// TODO let token manage it's own brain :<
tkn.prev_exec = null;
} else if (tkn.prev_exec) |pe| {
tkn.raw = pe;
// lol, super leaks
tkn.prev_exec = null;
tkn.idx = tkn.raw.items.len;
return;
if (line.history_position) |pos| {
_ = history.readAtFiltered(pos, line.history_search.?, tkn.lineReplaceHistory());
line.history_position.? = pos + 1;
} else {
line.history_position = 0;
if (tkn.raw.items.len == 0) {
if (tkn.prev_exec) |prvexe| {
tkn.raw = prvexe;
tkn.idx = tkn.raw.items.len;
tkn.prev_exec = null;
return;
}
line.history_search = line.alloc.dupe(u8, "") catch @panic("OOM");
} else if (line.history_search == null) {
if (tkn.user_data == true) {
log.warn("clobbered userdata\n", .{});
}
line.history_search = line.alloc.dupe(u8, line.tkn.raw.items) catch @panic("OOM");
}
_ = history.readAtFiltered(0, line.history_search.?, tkn.lineReplaceHistory());
}
_ = history.readAtFiltered(tkn.lineReplaceHistory(), &line.usr_line);
line.tkn.move(.end);
return;
},
.down => {
if (history.cnt > 1) {
history.cnt -= 1;
tkn.reset();
} else {
history.cnt -|= 1;
tkn.reset();
tkn.consumes(&line.usr_line) catch unreachable;
//in.hist_orig = in.hist_data[0..0];
 
return;
if (line.history_position) |pos| {
if (pos == 0) {
tkn.reset();
log.warn("todo restore userdata\n", .{});
tkn.reset();
line.history_position = null;
tkn.move(.end);
} else {
line.history_position.? -|= 1;
_ = history.readAtFiltered(pos, line.history_search.?, tkn.lineReplaceHistory());
//tkn.reset();
//tkn.consumes(&line.usr_line) catch unreachable;
tkn.move(.end);
}
}
_ = history.readAtFiltered(tkn.lineReplaceHistory(), &line.usr_line);
tkn.move(.end);
 
return;
},
}
@@ -248,6 +268,7 @@ fn complete(line: *Line) !void {
' ' => {
try line.tkn.maybeCommit(null);
cmplt.raze();
try line.tkn.consumec(' ');
continue :sw .{ .done = {} };
},
'/' => |chr| {
@@ -357,6 +378,7 @@ fn complete(line: *Line) !void {
continue :sw .{ .typing = chr };
},
.done => {
line.hsh.draw.clearCtx();
return;
},
}