chore: port to new zellij API!
This commit is contained in:
parent
06363a4237
commit
f159b2f743
4
gyro.zzz
4
gyro.zzz
|
@ -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
|
||||
|
|
11
src/api.zig
11
src/api.zig
|
@ -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
50
src/deser/char_db.zig
Normal 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);
|
||||
}
|
|
@ -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{
|
||||
|
|
|
@ -16,6 +16,7 @@ const Vis = struct {
|
|||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
);
|
||||
|
||||
pub fn visitSeq(
|
||||
|
|
|
@ -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);
|
||||
}
|
225
src/types.zig
225
src/types.zig
|
@ -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,
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue