srctree

Gregory Mullen parent 022e29e0 6f5c5838
start reactivating tab completion again

src/input.zig added: 185, removed: 166, total 19
@@ -38,19 +38,34 @@ pub const Control = enum {
end_of_text,
external_editor,
reset_term,
};
 
pub fn fromKey(k: Keys.Key) Control {
return switch (k) {
.esc => .esc,
.up => .up,
.down => .down,
.left => .left,
.right => .right,
.home => .home,
.end => .end,
.pgdn => .pgdn,
.pgup => .pgup,
else => unreachable,
pub const CtrlMod = struct {
c: Control,
mod: Keys.Mods = .{},
 
pub fn fromChr(comptime c: u8) CtrlMod {
return .{ .c = switch (c) {
0x7F => .backspace,
else => comptime unreachable,
} };
}
 
pub fn fromKey(k: Keys.Key, mods: Keys.Mods) CtrlMod {
return .{
.c = switch (k) {
.esc => .esc,
.up => .up,
.down => .down,
.left => .left,
.right => .right,
.home => .home,
.end => .end,
.pgdn => .pgdn,
.pgup => .pgup,
else => unreachable,
},
.mod = mods,
};
}
};
@@ -64,7 +79,7 @@ const errors = error{
pub const Event = union(enum) {
action: Action,
char: u8,
control: Control,
control: CtrlMod,
mouse: Keys.Mouse,
};
 
@@ -163,9 +178,9 @@ fn event(km: Keys.KeyMod) Event {
.pgup,
.pgdn,
=> |r| {
return .{ .control = Control.fromKey(r) };
return .{ .control = CtrlMod.fromKey(r, km.mods) };
},
.delete => return .{ .control = .delete },
.delete => return .{ .control = CtrlMod.fromKey(.delete, .{}) },
else => {
log.err("unknown control key {}\n", .{k});
return .{ .action = .none };
@@ -181,10 +196,10 @@ fn utf8(key: Keys.ASCII) u8 {
 
fn ascii(key: Keys.ASCII) Event {
switch (key) {
0x00...0x1F => return .{ .control = ctrlCode(key) },
0x00...0x1F => return .{ .control = .{ .c = ctrlCode(key) } },
// Normal printable ascii
' '...'~' => |b| return .{ .char = b },
0x7F => return .{ .control = .backspace },
0x7F => return .{ .control = CtrlMod.fromChr(0x7F) },
0x80...0xFF => return .{ .char = utf8(key) },
}
return .{ .control = .none };
@@ -201,7 +216,7 @@ fn toChar(k: Keys.Event) errors!Event {
}
}
 
pub fn nonInteractive(input: *Input) errors!Event {
pub fn nonInteractive(input: Input) errors!Event {
var buffer: [1]u8 = undefined;
 
const nbyte: usize = input.read(&buffer) catch |err| {
 
src/keys.zig added: 185, removed: 166, total 19
@@ -29,6 +29,25 @@ pub const Key = enum(u8) {
};
// zig fmt: on
 
pub const Mods = struct {
shift: bool = false,
alt: bool = false,
ctrl: bool = false,
meta: bool = false,
 
pub fn any(m: *@This()) bool {
return m.shift or m.alt or m.ctrl or m.meta;
}
 
pub fn make(bits: u8) @This() {
return .{
.shift = (bits & 1) != 0,
.alt = (bits & 2) != 0,
.ctrl = (bits & 4) != 0,
.meta = (bits & 8) != 0,
};
}
};
pub const ASCII = u8;
 
pub const KeyMod = struct {
@@ -37,26 +56,6 @@ pub const KeyMod = struct {
key: Key,
},
mods: Mods = .{},
 
pub const Mods = struct {
shift: bool = false,
alt: bool = false,
ctrl: bool = false,
meta: bool = false,
 
pub fn any(m: *@This()) bool {
return m.shift or m.alt or m.ctrl or m.meta;
}
 
pub fn make(bits: u8) @This() {
return .{
.shift = (bits & 1) != 0,
.alt = (bits & 2) != 0,
.ctrl = (bits & 4) != 0,
.meta = (bits & 8) != 0,
};
}
};
};
 
pub const Mouse = enum {
@@ -110,7 +109,7 @@ pub fn esc(io: i32) Error!Event {
.evt = .{
.ascii = buffer[0],
},
.mods = KeyMod.Mods.make(2),
.mods = Mods.make(2),
} };
},
}
@@ -180,7 +179,7 @@ fn csi_xterm(buffer: []const u8) Error!Event {
return .{
.keysm = .{
.evt = .{ .key = key },
.mods = KeyMod.Mods.make(mod_bits),
.mods = Mods.make(mod_bits),
},
};
},
@@ -189,7 +188,7 @@ fn csi_xterm(buffer: []const u8) Error!Event {
return Event{
.keysm = .{
.evt = .{ .ascii = 0x09 },
.mods = KeyMod.Mods.make(1),
.mods = Mods.make(1),
},
};
},
 
src/line.zig added: 185, removed: 166, total 19
@@ -1,22 +1,5 @@
const std = @import("std");
const Allocator = std.mem.Allocator;
const log = @import("log");
 
const fs = @import("fs.zig");
const HSH = @import("hsh.zig").HSH;
const Complete = @import("completion.zig");
const History = @import("history.zig");
const Input = @import("input.zig");
const Keys = @import("keys.zig");
const Prompt = @import("prompt.zig");
 
const printAfter = Draw.printAfter;
const Draw = @import("draw.zig");
 
const Line = @This();
 
const Tokenizer = @import("tokenizer.zig");
 
const Mode = enum {
TYPING,
COMPLETING,
@@ -122,7 +105,7 @@ fn core(line: *Line) !void {
switch (input) {
.char => |c| try line.char(c),
.control => |ctrl| {
switch (ctrl) {
switch (ctrl.c) {
.esc => continue,
.up => line.findHistory(.up),
.down => line.findHistory(.down),
@@ -132,7 +115,7 @@ fn core(line: *Line) !void {
.newline => return,
.end_of_text => return,
.delete_word => _ = try line.tkn.dropWord(),
.tab => {}, //try line.complete(),
.tab => try line.complete(),
else => |els| log.warn("unknown {}\n", .{els}),
}
line.hsh.draw.clear();
@@ -245,16 +228,17 @@ fn doComplete(hsh: *HSH, tkn: *Tokenizer, comp: *Complete.CompSet) !Mode {
return .COMPENDING;
} else {
comp.raze();
try Draw.drawAfter(&hsh.draw, Draw.LexTree{
.lex = Draw.Lexeme{ .char = "[ found ]", .style = .{ .attr = .bold, .fg = .green } },
});
try Draw.drawAfter(&hsh.draw, &[_]Draw.Lexeme{.{
.char = "[ found ]",
.style = .{ .attr = .bold, .fg = .green },
}});
return .TYPING;
}
}
 
if (comp.countFiltered() == 0) {
try Draw.drawAfter(&hsh.draw, Draw.LexTree{
.lex = Draw.Lexeme{ .char = "[ nothing found ]", .style = .{ .attr = .bold, .fg = .red } },
try Draw.drawAfter(&hsh.draw, &[_]Draw.Lexeme{
Draw.Lexeme{ .char = "[ nothing found ]", .style = .{ .attr = .bold, .fg = .red } },
});
if (comp.count() == 0) {
comp.raze();
@@ -273,113 +257,134 @@ fn doComplete(hsh: *HSH, tkn: *Tokenizer, comp: *Complete.CompSet) !Mode {
return .COMPLETING;
}
 
fn completing(in: *Input, hsh: *HSH, tkn: *Tokenizer, ks: Keys.KeyMod, comp: *Complete.CompSet) !Input.Event {
if (in.mode == .TYPING) {
try Complete.complete(comp, hsh, tkn);
in.mode = .COMPLETING;
return in.completing(hsh, tkn, ks, comp);
}
const CompState = union(enum) {
typing: Input.Event,
pending: void,
read: void,
redraw: void,
done: void,
};
 
switch (ks.evt) {
.ascii => |c| {
switch (c) {
0x09 => {
// tab \t
if (ks.mods.shift) {
comp.revr();
comp.revr();
}
in.mode = try doComplete(hsh, tkn, comp);
return .Redraw;
},
0x0A => {
// newline \n
if (in.mode == .COMPENDING) {
in.mode = .TYPING;
return .Exec;
}
if (comp.count() > 0) {
try tkn.maybeReplace(comp.current());
try tkn.maybeCommit(comp.current());
in.mode = .COMPENDING;
}
return .Redraw;
},
0x7f => { // backspace
if (in.mode == .COMPENDING) {
in.mode = .TYPING;
return .Redraw;
}
comp.searchPop() catch {
in.mode = .TYPING;
comp.raze();
tkn.raw_maybe = null;
return .Redraw;
};
in.mode = try doComplete(hsh, tkn, comp);
try tkn.maybeDrop();
try tkn.maybeAdd(comp.search.items);
return .Redraw;
},
' ' => {
in.mode = .TYPING;
return .Redraw;
},
'/' => |chr| {
// IFF this is an existing directory,
// completion should continue
if (comp.count() > 1) {
if (comp.current().kind) |kind| {
if (kind == .file_system and kind.file_system == .dir) {
try tkn.consumec(chr);
fn complete(line: *Line) !void {
sw: switch (CompState{ .typing = Input.Event{ .char = 0x09 } }) {
.pending => {},
.typing => |ks| {
switch (ks) {
.char => |c| {
switch (c) {
0x09 => {}, // unreachable?
0x0A => {
// TODO don't return if navigating around
continue :sw .{ .done = {} };
//if (line.completion.count() > 0) {
// try line.tkn.maybeReplace(line.completion.current());
// try line.tkn.maybeCommit(line.completion.current());
// continue :sw .{ .pending = {} };
//}
//continue :sw .{ .redraw = {} };
},
0x7f => { // backspace
line.completion.?.searchPop() catch {
line.completion.?.raze();
line.tkn.raw_maybe = null;
continue :sw .{ .done = {} };
};
//line.mode = try doComplete(line.hsh, line.tkn, line.completion);
try line.tkn.maybeDrop();
try line.tkn.maybeAdd(line.completion.?.search.items);
continue :sw .{ .redraw = {} };
},
' ' => continue :sw .{ .redraw = {} },
'/' => |chr| {
// IFF this is an existing directory,
// completion should continue
if (line.completion.?.count() > 1) {
if (line.completion.?.current().kind) |kind| {
if (kind == .file_system and kind.file_system == .dir) {
try line.tkn.consumec(chr);
}
}
}
}
continue :sw .{ .redraw = {} };
},
else => {
//if (line.mode == .COMPENDING) line.mode = .COMPLETING;
//try line.completion.?.searchChar(c);
//line.mode = try doComplete(line.hsh, line.tkn, line.completion);
//if (line.mode == .COMPLETING) {
// try line.tkn.maybeDrop();
// try line.tkn.maybeAdd(line.completion.search.items);
//}
continue :sw .{ .redraw = {} };
},
}
in.mode = .TYPING;
return .Redraw;
},
else => {
if (in.mode == .COMPENDING) in.mode = .COMPLETING;
try comp.searchChar(c);
in.mode = try doComplete(hsh, tkn, comp);
if (in.mode == .COMPLETING) {
try tkn.maybeDrop();
try tkn.maybeAdd(comp.search.items);
.control => |k| {
switch (k.c) {
.tab => {
if (k.mod.shift) {
line.completion.?.revr();
line.completion.?.revr();
}
_ = try doComplete(line.hsh, &line.tkn, &line.completion.?);
continue :sw .{ .redraw = {} };
},
.esc => {
try line.tkn.maybeDrop();
if (line.completion.?.original) |o| {
try line.tkn.maybeAdd(o.str);
try line.tkn.maybeCommit(null);
}
line.completion.?.raze();
continue :sw .{ .redraw = {} };
},
.up, .down, .left, .right => {
// TODO implement arrows
continue :sw .{ .redraw = {} };
},
.home, .end => |h_e| {
try line.tkn.maybeCommit(null);
line.tkn.idx = if (h_e == .home) 0 else line.tkn.raw.items.len;
continue :sw .{ .redraw = {} };
},
else => {
log.err("unexpected key [{}]\n", .{ks});
try line.tkn.maybeCommit(null);
},
}
return .Redraw;
},
.mouse => {},
.action => {},
}
},
.key => |k| {
switch (k) {
.Esc => {
in.mode = .TYPING;
try tkn.maybeDrop();
if (comp.original) |o| {
try tkn.maybeAdd(o.str);
try tkn.maybeCommit(null);
}
comp.raze();
return .Redraw;
},
.Up, .Down, .Left, .Right => {
// TODO implement arrows
return .Redraw;
},
.Home, .End => |h_e| {
in.mode = .TYPING;
try tkn.maybeCommit(null);
tkn.cPos(if (h_e == .Home) .home else .end);
return .Redraw;
},
else => {
log.err("unexpected key [{}]\n", .{ks});
in.mode = .TYPING;
try tkn.maybeCommit(null);
},
}
.redraw => {
line.hsh.draw.clear();
try Prompt.draw(line.hsh, line.peek());
try line.hsh.draw.render();
continue :sw .{ .read = {} };
},
.read => {
continue :sw .{ .typing = try line.input.interactive() };
},
.done => {
return;
},
}
log.err("end of completing... oops\n [{}]\n", .{ks});
unreachable;
}
 
const std = @import("std");
const Allocator = std.mem.Allocator;
const log = @import("log");
 
const Tokenizer = @import("tokenizer.zig");
const fs = @import("fs.zig");
const HSH = @import("hsh.zig").HSH;
const Complete = @import("completion.zig");
const History = @import("history.zig");
const Input = @import("input.zig");
const Keys = @import("keys.zig");
const Prompt = @import("prompt.zig");
 
const Draw = @import("draw.zig");
const printAfter = Draw.printAfter;