Add generic session panel stack
This commit is contained in:
+93
-11
@@ -30,6 +30,10 @@ fn commandResponse(allocator: std.mem.Allocator, session: *session_mod.Session,
|
||||
if (std.mem.eql(u8, command, "move_right")) return dispatchAndRespond(allocator, session, .move_right);
|
||||
if (std.mem.eql(u8, command, "delete_backward")) return dispatchAndRespond(allocator, session, .delete_backward);
|
||||
if (std.mem.startsWith(u8, command, "insert ")) return dispatchAndRespond(allocator, session, .{ .insert = command[7..] });
|
||||
if (std.mem.startsWith(u8, command, "panel_open ")) return panelRespond(allocator, session, .{ .open = command[11..] });
|
||||
if (std.mem.eql(u8, command, "panel_close")) return panelRespond(allocator, session, .close);
|
||||
if (std.mem.eql(u8, command, "panel_next")) return panelRespond(allocator, session, .next);
|
||||
if (std.mem.eql(u8, command, "panel_prev")) return panelRespond(allocator, session, .previous);
|
||||
if (std.mem.startsWith(u8, command, "pair ")) {
|
||||
const pair = pairByName(command[5..]) orelse return allocator.dupe(u8, "err unknown pair\n");
|
||||
return dispatchAndRespond(allocator, session, .{ .insert_pair = pair });
|
||||
@@ -56,14 +60,50 @@ fn dispatchAndRespond(allocator: std.mem.Allocator, session: *session_mod.Sessio
|
||||
return stateResponse(allocator, session);
|
||||
}
|
||||
|
||||
const PanelCommand = union(enum) {
|
||||
open: []const u8,
|
||||
close,
|
||||
next,
|
||||
previous,
|
||||
};
|
||||
|
||||
fn panelRespond(allocator: std.mem.Allocator, session: *session_mod.Session, command: PanelCommand) ![]u8 {
|
||||
switch (command) {
|
||||
.open => |title| session.openPanel(title) catch |err| switch (err) {
|
||||
error.InvalidPanelTitle => return allocator.dupe(u8, "err invalid panel title\n"),
|
||||
else => return err,
|
||||
},
|
||||
.close => session.closePanel() catch |err| switch (err) {
|
||||
error.NoPanelOpen => return allocator.dupe(u8, "err no panel open\n"),
|
||||
else => return err,
|
||||
},
|
||||
.next => session.nextPanel() catch |err| switch (err) {
|
||||
error.NoPanelOpen => return allocator.dupe(u8, "err no panel open\n"),
|
||||
else => return err,
|
||||
},
|
||||
.previous => session.previousPanel() catch |err| switch (err) {
|
||||
error.NoPanelOpen => return allocator.dupe(u8, "err no panel open\n"),
|
||||
else => return err,
|
||||
},
|
||||
}
|
||||
return stateResponse(allocator, session);
|
||||
}
|
||||
|
||||
fn stateResponse(allocator: std.mem.Allocator, session: *session_mod.Session) ![]u8 {
|
||||
const snap = session.snapshot() catch |err| switch (err) {
|
||||
error.NoBufferOpen => return allocator.dupe(u8, "err no buffer open\n"),
|
||||
};
|
||||
const snap = try session.snapshot();
|
||||
const panel_path = try session.panelPathAlloc(allocator);
|
||||
defer allocator.free(panel_path);
|
||||
return std.fmt.allocPrint(
|
||||
allocator,
|
||||
"ok state cursor_byte={d} cursor_cell={d} bytes_len={d}\n",
|
||||
.{ snap.cursor_byte, snap.cursor_cell, snap.bytes.len },
|
||||
"ok state cursor_byte={d} cursor_cell={d} bytes_len={d} panel_depth={d} active_panel={s} panel_path={s}\n",
|
||||
.{
|
||||
snap.cursor_byte,
|
||||
snap.cursor_cell,
|
||||
snap.bytes.len,
|
||||
snap.panel_depth,
|
||||
if (snap.active_panel_title) |title| title else "-",
|
||||
panel_path,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -73,15 +113,15 @@ test "regular: protocol opens bytes, reports state, and dispatches commands" {
|
||||
|
||||
const open = try handleLine(std.testing.allocator, &session, "open café\n");
|
||||
defer std.testing.allocator.free(open);
|
||||
try std.testing.expectEqualStrings("ok state cursor_byte=0 cursor_cell=0 bytes_len=5\n", open);
|
||||
try std.testing.expectEqualStrings("ok state cursor_byte=0 cursor_cell=0 bytes_len=5 panel_depth=0 active_panel=- panel_path=-\n", open);
|
||||
|
||||
const moved = try handleLine(std.testing.allocator, &session, "command move_right\n");
|
||||
defer std.testing.allocator.free(moved);
|
||||
try std.testing.expectEqualStrings("ok state cursor_byte=1 cursor_cell=1 bytes_len=5\n", moved);
|
||||
try std.testing.expectEqualStrings("ok state cursor_byte=1 cursor_cell=1 bytes_len=5 panel_depth=0 active_panel=- panel_path=-\n", moved);
|
||||
|
||||
const inserted = try handleLine(std.testing.allocator, &session, "command insert 🔥\n");
|
||||
defer std.testing.allocator.free(inserted);
|
||||
try std.testing.expectEqualStrings("ok state cursor_byte=5 cursor_cell=3 bytes_len=9\n", inserted);
|
||||
try std.testing.expectEqualStrings("ok state cursor_byte=5 cursor_cell=3 bytes_len=9 panel_depth=0 active_panel=- panel_path=-\n", inserted);
|
||||
}
|
||||
|
||||
test "regular: protocol delete command removes a whole UTF-8 codepoint" {
|
||||
@@ -97,7 +137,7 @@ test "regular: protocol delete command removes a whole UTF-8 codepoint" {
|
||||
response = try handleLine(std.testing.allocator, &session, "command delete_backward\n");
|
||||
defer std.testing.allocator.free(response);
|
||||
|
||||
try std.testing.expectEqualStrings("ok state cursor_byte=1 cursor_cell=1 bytes_len=1\n", response);
|
||||
try std.testing.expectEqualStrings("ok state cursor_byte=1 cursor_cell=1 bytes_len=1 panel_depth=0 active_panel=- panel_path=-\n", response);
|
||||
}
|
||||
|
||||
test "adversarial: protocol rejects unknown requests and commands" {
|
||||
@@ -120,7 +160,7 @@ test "adversarial: protocol reports no buffer and invalid utf8 without corruptin
|
||||
|
||||
const no_buffer = try handleLine(std.testing.allocator, &session, "state\n");
|
||||
defer std.testing.allocator.free(no_buffer);
|
||||
try std.testing.expectEqualStrings("err no buffer open\n", no_buffer);
|
||||
try std.testing.expectEqualStrings("ok state cursor_byte=0 cursor_cell=0 bytes_len=0 panel_depth=0 active_panel=- panel_path=-\n", no_buffer);
|
||||
|
||||
try session.openFixture("safe");
|
||||
const before = try session.snapshot();
|
||||
@@ -149,7 +189,7 @@ test "regular: protocol pair commands insert delimiters with cursor between them
|
||||
response = try handleLine(std.testing.allocator, &session, "command pair parens\n");
|
||||
defer std.testing.allocator.free(response);
|
||||
|
||||
try std.testing.expectEqualStrings("ok state cursor_byte=5 cursor_cell=5 bytes_len=6\n", response);
|
||||
try std.testing.expectEqualStrings("ok state cursor_byte=5 cursor_cell=5 bytes_len=6 panel_depth=0 active_panel=- panel_path=-\n", response);
|
||||
try std.testing.expectEqualStrings("call()", (try session.snapshot()).bytes);
|
||||
}
|
||||
|
||||
@@ -163,3 +203,45 @@ test "adversarial: protocol rejects unknown pair names" {
|
||||
try std.testing.expectEqualStrings("err unknown pair\n", response);
|
||||
try std.testing.expectEqualStrings("abc", (try session.snapshot()).bytes);
|
||||
}
|
||||
|
||||
test "regular: protocol opens switches and closes generic panels" {
|
||||
var session = session_mod.Session.init(std.testing.allocator);
|
||||
defer session.deinit();
|
||||
|
||||
{
|
||||
const response = try handleLine(std.testing.allocator, &session, "command panel_open files\n");
|
||||
defer std.testing.allocator.free(response);
|
||||
try std.testing.expectEqualStrings("ok state cursor_byte=0 cursor_cell=0 bytes_len=0 panel_depth=1 active_panel=files panel_path=[files]\n", response);
|
||||
}
|
||||
{
|
||||
const response = try handleLine(std.testing.allocator, &session, "command panel_open diagnostics\n");
|
||||
defer std.testing.allocator.free(response);
|
||||
try std.testing.expectEqualStrings("ok state cursor_byte=0 cursor_cell=0 bytes_len=0 panel_depth=2 active_panel=diagnostics panel_path=files>[diagnostics]\n", response);
|
||||
}
|
||||
{
|
||||
const response = try handleLine(std.testing.allocator, &session, "command panel_prev\n");
|
||||
defer std.testing.allocator.free(response);
|
||||
try std.testing.expectEqualStrings("ok state cursor_byte=0 cursor_cell=0 bytes_len=0 panel_depth=2 active_panel=files panel_path=[files]>diagnostics\n", response);
|
||||
}
|
||||
{
|
||||
const response = try handleLine(std.testing.allocator, &session, "command panel_close\n");
|
||||
defer std.testing.allocator.free(response);
|
||||
try std.testing.expectEqualStrings("ok state cursor_byte=0 cursor_cell=0 bytes_len=0 panel_depth=1 active_panel=diagnostics panel_path=[diagnostics]\n", response);
|
||||
}
|
||||
}
|
||||
|
||||
test "adversarial: protocol rejects invalid panel titles and empty panel actions" {
|
||||
var session = session_mod.Session.init(std.testing.allocator);
|
||||
defer session.deinit();
|
||||
|
||||
{
|
||||
const response = try handleLine(std.testing.allocator, &session, "command panel_open bad title\n");
|
||||
defer std.testing.allocator.free(response);
|
||||
try std.testing.expectEqualStrings("err invalid panel title\n", response);
|
||||
}
|
||||
{
|
||||
const response = try handleLine(std.testing.allocator, &session, "command panel_close\n");
|
||||
defer std.testing.allocator.free(response);
|
||||
try std.testing.expectEqualStrings("err no panel open\n", response);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user