an experimental irc client
1const std = @import("std");
2const app = @import("app.zig");
3const completer = @import("completer.zig");
4const vaxis = @import("vaxis");
5pub const irc = @import("irc.zig");
6pub const lua = @import("lua.zig");
7const ziglua = @import("ziglua");
8
9pub const App = app.App;
10pub const Completer = completer.Completer;
11pub const WriteQueue = vaxis.Queue(WriteEvent, 32);
12
13pub const Bind = struct {
14 key: vaxis.Key,
15 command: Command,
16};
17
18pub const Config = struct {
19 markread_on_focus: bool = false,
20
21 pub fn Fields() type {
22 const config_fields = std.meta.fieldNames(Config);
23 var fields: [config_fields.len]std.builtin.Type.EnumField = undefined;
24
25 for (config_fields, 0..) |f, i| {
26 fields[i] = .{
27 .name = f,
28 .value = i,
29 };
30 }
31
32 return @Type(.{
33 .@"enum" = .{
34 .decls = &.{},
35 .tag_type = u16,
36 .fields = &fields,
37 .is_exhaustive = true,
38 },
39 });
40 }
41
42 pub fn fieldToLuaType(field: []const u8) ziglua.LuaType {
43 const fields = std.meta.fields(Config);
44 inline for (fields) |f| {
45 if (std.mem.eql(u8, field, f.name)) {
46 switch (@typeInfo(f.type)) {
47 .bool => return .boolean,
48 .int, .comptime_int => return .number,
49 .pointer => |ptr_info| {
50 switch (ptr_info.size) {
51 .slice => {
52 if (ptr_info.child == u8) return .string;
53 },
54 else => {},
55 }
56 },
57 else => return .nil,
58 }
59 }
60 }
61 return .nil;
62 }
63};
64
65pub const Command = union(enum) {
66 /// a raw irc command. Sent verbatim
67 quote,
68 join,
69 list,
70 me,
71 msg,
72 query,
73 @"next-channel",
74 @"prev-channel",
75 quit,
76 who,
77 names,
78 part,
79 close,
80 redraw,
81 version,
82 lua_function: i32,
83
84 pub var user_commands: std.StringHashMap(i32) = undefined;
85
86 /// only contains void commands
87 const map = std.StaticStringMap(Command).initComptime(.{
88 .{ "quote", .quote },
89 .{ "join", .join },
90 .{ "list", .list },
91 .{ "me", .me },
92 .{ "msg", .msg },
93 .{ "query", .query },
94 .{ "next-channel", .@"next-channel" },
95 .{ "prev-channel", .@"prev-channel" },
96 .{ "quit", .quit },
97 .{ "who", .who },
98 .{ "names", .names },
99 .{ "part", .part },
100 .{ "close", .close },
101 .{ "redraw", .redraw },
102 .{ "version", .version },
103 });
104
105 pub fn fromString(str: []const u8) ?Command {
106 return map.get(str);
107 }
108
109 /// if we should append a space when completing
110 pub fn appendSpace(self: Command) bool {
111 return switch (self) {
112 .quote,
113 .join,
114 .me,
115 .msg,
116 .part,
117 .close,
118 => true,
119 else => false,
120 };
121 }
122};
123
124/// An event our write thread will handle
125pub const WriteEvent = union(enum) {
126 write: struct {
127 client: *irc.Client,
128 msg: []const u8,
129 },
130 join,
131};