chore: port to new zellij API!

This commit is contained in:
LordMZTE 2022-08-03 00:05:25 +02:00
parent 06363a4237
commit f159b2f743
Signed by: LordMZTE
GPG key ID: B64802DC33A64FF6
7 changed files with 273 additions and 171 deletions

View file

@ -9,10 +9,10 @@ deps:
getty:
git:
url: "https://github.com/getty-zig/getty.git"
ref: 69b4df59511203f91d38660794d8cb7a073eb815
ref: be3726ca35bff92867b5458d2c285c80df1c04e3
root: src/lib.zig
json:
git:
url: "https://github.com/getty-zig/json.git"
ref: 9a40ce99fba1449738c9ccc63aebb9b4187de409
ref: 396e0569599a2f8fab76f0692e234e00b07f9808
root: src/lib.zig

View file

@ -11,9 +11,15 @@ pub fn sendObj(data: anytype) !void {
}
pub fn recvObj(comptime T: type) !types.OwnedDeserData(T) {
var buf: [4096]u8 = undefined;
var stdin = std.io.getStdIn();
const data = (try stdin.reader().readUntilDelimiterOrEof(&buf, '\n')) orelse unreachable;
const data = (try stdin.reader().readUntilDelimiterOrEofAlloc(
zz.allocator.?,
'\n',
std.math.maxInt(usize),
)) orelse unreachable;
defer zz.allocator.?.free(data);
return types.OwnedDeserData(T).deserialize(zz.allocator.?, data);
}
@ -61,4 +67,3 @@ pub fn execCmd(cmd: []const []const u8) !void {
try sendObj(cmd);
zapi.host_exec_cmd();
}

50
src/deser/char_db.zig Normal file
View file

@ -0,0 +1,50 @@
const std = @import("std");
const getty = @import("getty");
const types = @import("../types.zig");
const Vis = struct {
pub usingnamespace getty.de.Visitor(
@This(),
types.Char,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
visitString,
undefined,
undefined,
);
pub fn visitString(
_: @This(),
_: ?std.mem.Allocator,
comptime Deserializer: type,
input: anytype,
) Deserializer.Error!types.Char {
if (input.len != 1)
return error.InvalidLength;
return types.Char{ .c = input[0] };
}
};
pub fn is(comptime T: type) bool {
return T == types.Char;
}
pub fn Visitor(comptime _: type) type {
return Vis;
}
pub fn deserialize(
alloc: ?std.mem.Allocator,
comptime _: type,
deserializer: anytype,
visitor: anytype,
) !@TypeOf(visitor).Value {
return try deserializer.deserializeString(alloc, visitor);
}

View file

@ -13,6 +13,7 @@ const Vis = struct {
undefined,
undefined,
undefined,
undefined,
visitString,
undefined,
undefined,
@ -25,7 +26,7 @@ const Vis = struct {
input: anytype,
) Deserializer.Error!types.CharOrArrow {
if (input.len == 1) {
return types.CharOrArrow{ .Char = input[0] };
return types.CharOrArrow{ .Char = .{ .c = input[0] } };
}
return types.CharOrArrow{

View file

@ -16,6 +16,7 @@ const Vis = struct {
undefined,
undefined,
undefined,
undefined,
);
pub fn visitSeq(

View file

@ -1,150 +0,0 @@
const std = @import("std");
const getty = @import("getty");
const types = @import("../types.zig");
pub fn is(comptime T: type) bool {
return switch (@typeInfo(T)) {
.Union => true,
else => false,
};
}
pub fn Visitor(comptime T: type) type {
return struct {
pub usingnamespace getty.de.Visitor(
@This(),
T,
undefined,
undefined,
undefined,
undefined,
visitMap,
undefined,
undefined,
visitString,
undefined,
undefined,
);
pub fn visitMap(
_: @This(),
alloc: ?std.mem.Allocator,
comptime Deserializer: type,
input: anytype,
) Deserializer.Error!T {
const tag = (try input.nextKey(alloc, []const u8)) orelse
return error.InvalidLength;
var val: ?T = null;
inline for (@typeInfo(T).Union.fields) |field| {
if (val == null and std.mem.eql(u8, field.name, tag)) {
if (field.field_type == void) {
return error.InvalidType;
}
const data = try input.nextValue(alloc, field.field_type);
val = @unionInit(T, field.name, data);
}
}
if (val) |v| {
while (try input.nextKey(alloc, []const u8)) |_| {}
return v;
}
return error.UnknownVariant;
}
pub fn visitString(
_: @This(),
_: ?std.mem.Allocator,
comptime Deserializer: type,
input: anytype,
) Deserializer.Error!T {
inline for (@typeInfo(T).Union.fields) |field| {
if (std.mem.eql(u8, field.name, input))
if (field.field_type == void)
return @unionInit(T, field.name, {})
else
return error.InvalidType;
}
return error.UnknownVariant;
}
};
}
pub fn deserialize(
alloc: ?std.mem.Allocator,
comptime _: type,
deserializer: anytype,
visitor: anytype,
) !@TypeOf(visitor).Value {
// This horrifying hack is needed since just trying deserializeString
// would consume tokens needed by deserializeMap
var tokens_copy = deserializer.context.tokens;
const token = (try tokens_copy.next()) orelse
return error.UnexpectedEndOfJson;
return switch (token) {
.String => try deserializer.deserializeString(alloc, visitor),
.ObjectBegin => try deserializer.deserializeMap(alloc, visitor),
else => error.InvalidType,
};
}
test "union_db deserialize" {
const TestUnion = union(enum) {
Foo: u8,
Bar: struct { a: u8, b: u8 },
Baz: void,
};
const json_src_a =
\\ {
\\ "Foo": 42
\\ }
;
const json_src_b =
\\ {
\\ "Bar": {
\\ "a": 42,
\\ "b": 69
\\ }
\\ }
;
const json_src_c =
\\"Baz"
;
var deser_a = try types.OwnedDeserData(TestUnion).deserialize(
std.testing.allocator,
json_src_a,
);
defer deser_a.deinit();
var deser_b = try types.OwnedDeserData(TestUnion).deserialize(
std.testing.allocator,
json_src_b,
);
defer deser_b.deinit();
var deser_c = try types.OwnedDeserData(TestUnion).deserialize(
std.testing.allocator,
json_src_c,
);
defer deser_c.deinit();
try std.testing.expectEqual(TestUnion{ .Foo = 42 }, deser_a.data);
try std.testing.expectEqual(TestUnion{
.Bar = .{
.a = 42,
.b = 69,
},
}, deser_b.data);
try std.testing.expectEqual(TestUnion{ .Baz = {} }, deser_c.data);
}

View file

@ -4,9 +4,9 @@ const json = @import("json");
/// getty deserialization blocks required to properly deserialize messages
pub const dbs = .{
@import("deser/char_db.zig"),
@import("deser/char_or_arrow_db.zig"),
@import("deser/line_and_column_db.zig"),
@import("deser/union_db.zig"),
};
// required because the only way to properly free deserilized
@ -39,6 +39,21 @@ pub fn OwnedDeserData(comptime T: type) type {
};
}
/// A struct that represents a single char. It is different from `u8`, as it is
/// deserialized as a 1-letter string, instead of an integer.
pub const Char = struct {
c: u8,
};
test "deserialize Char" {
const json_src =
\\"x"
;
var deser = try OwnedDeserData(Char).deserialize(std.testing.allocator, json_src);
defer deser.deinit();
}
pub const EventType = enum {
ModeUpdate,
TabUpdate,
@ -134,7 +149,7 @@ test "deserialize Event" {
\\ "capabilities": {
\\ "arrow_fonts": false
\\ },
\\ "session_name": "tasteful-root"
\\ "session_name": "wacky-bit"
\\ }
\\}
;
@ -143,12 +158,38 @@ test "deserialize Event" {
defer deser.deinit();
}
pub const Keybind = std.meta.Tuple(&.{ Key, []Action });
pub const KeybindSet = std.meta.Tuple(&.{ InputMode, []Keybind });
test "deserialize KeybindSet" {
const json_src =
\\[
\\ "Normal",
\\ [
\\ [
\\ {
\\ "Alt": "+"
\\ },
\\ [
\\ {
\\ "Resize": "Increase"
\\ }
\\ ]
\\ ]
\\ ]
\\]
;
var deser = try OwnedDeserData(KeybindSet).deserialize(std.testing.allocator, json_src);
defer deser.deinit();
}
pub const ModeInfo = struct {
mode: InputMode,
keybinds: [][2][]const u8,
keybinds: []KeybindSet,
style: Style,
capabilities: PluginCapabilities,
session_name: ?[]const u8,
session_name: ?[]u8,
};
pub const InputMode = enum {
@ -158,6 +199,8 @@ pub const InputMode = enum {
Pane,
Tab,
Scroll,
EnterSearch,
Search,
RenameTab,
RenamePane,
Session,
@ -282,28 +325,54 @@ pub const TabInfo = struct {
};
pub const Key = union(enum) {
Backspace,
PageDown,
PageUp,
Left,
Right,
Up,
Down,
Up,
Right,
Home,
End,
PageUp,
PageDown,
BackTab,
Backspace,
Delete,
Insert,
F: u8,
Char: []u8,
Char: Char,
Alt: CharOrArrow,
Ctrl: []u8,
Ctrl: Char,
BackTab,
Null,
Esc,
};
test "deserialize Key" {
const json_src =
\\[
\\ {
\\ "Alt": "+"
\\ },
\\ "Esc",
\\ {
\\ "Alt": "Left"
\\ },
\\ {
\\ "F": 11
\\ },
\\ {
\\ "Ctrl": "\n"
\\ },
\\ {
\\ "Char": "x"
\\ }
\\]
;
var deser = try OwnedDeserData([]Key).deserialize(std.testing.allocator, json_src);
defer deser.deinit();
}
pub const CharOrArrow = union(enum) {
Char: u8,
Char: Char,
Direction: Direction,
};
@ -320,7 +389,7 @@ test "deserialize CharOrArrow" {
);
defer data_2.deinit();
try std.testing.expectEqual(CharOrArrow{ .Char = 'A' }, data_1.data);
try std.testing.expectEqual(CharOrArrow{ .Char = .{ .c = 'A' } }, data_1.data);
try std.testing.expectEqual(CharOrArrow{ .Direction = .Left }, data_2.data);
}
@ -334,9 +403,13 @@ pub const Direction = enum {
pub const Mouse = union(enum) {
ScrollUp: usize,
ScrollDown: usize,
LeftClick: LineAndColumn,
RightClick: LineAndColumn,
Hold: LineAndColumn,
Release: LineAndColumn,
};
// TODO: implement deserialization block
// TODO: Make this deserialize both as array and struct, and then remove `Position`.
pub const LineAndColumn = struct {
line: isize,
column: usize,
@ -377,3 +450,125 @@ pub const PluginIds = struct {
plugin_id: u32,
zellij_pid: u32,
};
pub const ResizeDirection = enum {
Left,
Right,
Up,
Down,
Increase,
Decrease,
};
pub const Position = struct {
line: isize,
column: usize,
};
pub const RunPluginFromYaml = struct {
_allow_exec_host_cmd: ?bool,
location: []u8,
};
pub const RunCommand = struct {
command: []u8,
args: ?[][]u8,
cwd: ?[]u8,
};
pub const RunCommandAction = struct {
command: []u8,
args: ?[][]u8,
cwd: ?[]u8,
direction: ?Direction,
};
pub const RunFromYaml = union(enum) {
plugin: RunPluginFromYaml,
command: RunCommand,
};
pub const SplitSize = union(enum) {
Percent: u8,
Fixed: usize,
};
pub const TabLayout = union(enum) {
direction: ?Direction,
pane_name: ?[]u8,
borderless: ?bool,
parts: ?[]TabLayout,
split_size: ?SplitSize,
name: ?[]u8,
focus: ?bool,
run: ?RunFromYaml,
};
pub const SearchDirection = enum {
Up,
Down,
};
pub const SearchOption = enum {
CaseSensitivity,
WholeWord,
Wrap,
};
// TODO: Write, TabNameInput, PaneNameInput and SearchInput are actually `[]u8`,
// but getty thinks they have to be a string, and not byte arrays.
pub const Action = union(enum) {
Quit,
Write: []u32,
WriteChars: []u8,
SwitchToMode: InputMode,
Resize: ResizeDirection,
FocusNextPane,
FocusPreviousPane,
SwitchFocus,
MoveFocus: Direction,
MoveFocusOrTab: Direction,
MovePane: ?Direction,
DumpScreen: []u8,
EditScrollback,
ScrollUp,
ScrollUpAt: Position,
ScrollDown,
ScrollDownAt: Position,
ScrollToBottom,
PageScrollUp,
PageScrollDown,
HalfPageScrollUp,
HalfPageScrollDown,
ToggleFocusFullscreen,
TogglePaneFrames,
ToggleActiveSyncTab,
NewPane: ?Direction,
TogglePaneEmbedOrFloating,
ToggleFloatingPanes,
CloseFocus,
PaneNameInput: []u32,
UndoRenamePane,
NewTab: ?TabLayout,
NoOp,
GoToNextTab,
GoToPreviousTab,
CloseTab,
GoToTab: u32,
ToggleTab,
TabNameInput: []u32,
UndoRenameTab,
Run: RunCommandAction,
Detach,
LeftClick: Position,
RightClick: Position,
MouseRelease: Position,
MouseHold: Position,
Copy,
Confirm,
Deny,
SkipConfirm: *Action,
SearchInput: []u32,
Search: SearchDirection,
SearchToggleOption: SearchOption,
};