chore: refactor build

Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
This commit is contained in:
Tim Culverhouse 2024-01-18 20:17:26 -06:00
parent 11b7b86913
commit d22b2a89f3
7 changed files with 161 additions and 100 deletions

View file

@ -1,102 +1,46 @@
const std = @import("std"); const std = @import("std");
// Although this function looks imperative, note that its job is to
// declaratively construct a build graph that will be executed by an external
// runner.
pub fn build(b: *std.Build) void { pub fn build(b: *std.Build) void {
// Standard target options allows the person running `zig build` to choose
// what target to build for. Here we do not override the defaults, which
// means any target is allowed, and the default is native. Other options
// for restricting supported target set are available.
const target = b.standardTargetOptions(.{}); const target = b.standardTargetOptions(.{});
// Standard optimization options allow the person running `zig build` to select
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. Here we do not
// set a preferred release mode, allowing the user to decide how to optimize.
const optimize = b.standardOptimizeOption(.{}); const optimize = b.standardOptimizeOption(.{});
const libxev = b.dependency("libxev", .{ const odditui = b.addModule("odditui", .{ .root_source_file = .{ .path = "src/main.zig" } });
.optimize = optimize,
.target = target,
});
const ziglyph = b.dependency("ziglyph", .{ const ziglyph = b.dependency("ziglyph", .{
.optimize = optimize, .optimize = optimize,
.target = target, .target = target,
}); });
odditui.addImport("ziglyph", ziglyph.module("ziglyph"));
const lib = b.addStaticLibrary(.{
.name = "odditui",
// In this case the main source file is merely a path, however, in more
// complicated build scripts, this could be a generated file.
.root_source_file = .{ .path = "src/root.zig" },
.target = target,
.optimize = optimize,
});
// This declares intent for the library to be installed into the standard
// location when the user invokes the "install" step (the default step when
// running `zig build`).
b.installArtifact(lib);
const exe = b.addExecutable(.{ const exe = b.addExecutable(.{
.name = "odditui", .name = "odditui",
.root_source_file = .{ .path = "src/main.zig" }, .root_source_file = .{ .path = "examples/main.zig" },
.target = target, .target = target,
.optimize = optimize, .optimize = optimize,
}); });
exe.root_module.addImport("ziglyph", ziglyph.module("ziglyph")); exe.root_module.addImport("odditui", odditui);
exe.root_module.addImport("xev", libxev.module("xev"));
// This declares intent for the executable to be installed into the
// standard location when the user invokes the "install" step (the default
// step when running `zig build`).
b.installArtifact(exe);
// This *creates* a Run step in the build graph, to be executed when another
// step is evaluated that depends on it. The next line below will establish
// such a dependency.
const run_cmd = b.addRunArtifact(exe); const run_cmd = b.addRunArtifact(exe);
// By making the run step depend on the install step, it will be run from the
// installation directory rather than directly from within the cache directory.
// This is not necessary, however, if the application depends on other installed
// files, this ensures they will be present and in the expected location.
run_cmd.step.dependOn(b.getInstallStep()); run_cmd.step.dependOn(b.getInstallStep());
// This allows the user to pass arguments to the application in the build
// command itself, like this: `zig build run -- arg1 arg2 etc`
if (b.args) |args| { if (b.args) |args| {
run_cmd.addArgs(args); run_cmd.addArgs(args);
} }
// This creates a build step. It will be visible in the `zig build --help` menu,
// and can be selected like this: `zig build run`
// This will evaluate the `run` step rather than the default, which is "install".
const run_step = b.step("run", "Run the app"); const run_step = b.step("run", "Run the app");
run_step.dependOn(&run_cmd.step); run_step.dependOn(&run_cmd.step);
// Creates a step for unit testing. This only builds the test executable // Creates a step for unit testing. This only builds the test executable
// but does not run it. // but does not run it.
const lib_unit_tests = b.addTest(.{ const lib_unit_tests = b.addTest(.{
.root_source_file = .{ .path = "src/root.zig" }, .root_source_file = .{ .path = "src/main.zig" },
.target = target, .target = target,
.optimize = optimize, .optimize = optimize,
}); });
const run_lib_unit_tests = b.addRunArtifact(lib_unit_tests); const run_lib_unit_tests = b.addRunArtifact(lib_unit_tests);
const exe_unit_tests = b.addTest(.{
.root_source_file = .{ .path = "src/main.zig" },
.target = target,
.optimize = optimize,
});
const run_exe_unit_tests = b.addRunArtifact(exe_unit_tests);
// Similar to creating the run step earlier, this exposes a `test` step to
// the `zig build --help` menu, providing a way for the user to request
// running the unit tests.
const test_step = b.step("test", "Run unit tests"); const test_step = b.step("test", "Run unit tests");
test_step.dependOn(&run_lib_unit_tests.step); test_step.dependOn(&run_lib_unit_tests.step);
test_step.dependOn(&run_exe_unit_tests.step);
} }

29
examples/main.zig Normal file
View file

@ -0,0 +1,29 @@
const std = @import("std");
const odditui = @import("odditui");
const log = std.log.scoped(.main);
pub fn main() !void {
var app: odditui.App(Event) = try odditui.App(Event).init(.{});
defer app.deinit();
try app.start();
defer app.stop();
outer: while (true) {
const event = app.nextEvent();
switch (event) {
.key_press => |key| {
if (key.codepoint == 'c' and key.mods.ctrl) {
break :outer;
}
},
else => {},
}
log.debug("event: {}", .{event});
}
}
const Event = union(enum) {
key_press: odditui.Key,
mouse: u8,
};

93
src/Key.zig Normal file
View file

@ -0,0 +1,93 @@
const Key = @This();
pub const Modifiers = packed struct(u8) {
shift: bool = false,
alt: bool = false,
ctrl: bool = false,
super: bool = false,
hyper: bool = false,
meta: bool = false,
caps_lock: bool = false,
num_lock: bool = false,
};
/// the unicode codepoint of the key event. This can be greater than the maximum
/// allowable unicode codepoint for special keys
codepoint: u21,
/// the text generated from the key event, if any
text: ?[]const u8 = null,
/// the shifted codepoint of this key event. This will only be present if the
/// Shift modifier was used to generate the event
shifted_codepoint: ?u21 = null,
/// the key that would have been pressed on a standard keyboard layout. This is
/// useful for shortcut matching
base_layout_codepoint: ?u21 = null,
mods: Modifiers = .{},
// a few special keys that we encode as their actual ascii value
pub const enter: u21 = 0x0D;
pub const tab: u21 = 0x09;
pub const escape: u21 = 0x1B;
pub const space: u21 = 0x20;
pub const backspace: u21 = 0x7F;
// kitty encodes these keys directly in the private use area. We reuse those
// mappings
pub const caps_lock: u21 = 57358;
pub const scroll_lock: u21 = 57359;
pub const num_lock: u21 = 57360;
pub const print_screen: u21 = 57361;
pub const pause: u21 = 57362;
pub const menu: u21 = 57363;
pub const f13: u21 = 57376;
pub const f14: u21 = 57377;
pub const f15: u21 = 57378;
pub const @"f16": u21 = 57379;
pub const f17: u21 = 57380;
pub const f18: u21 = 57381;
pub const f19: u21 = 57382;
pub const f20: u21 = 57383;
pub const f21: u21 = 57384;
pub const f22: u21 = 57385;
pub const f23: u21 = 57386;
pub const f24: u21 = 57387;
pub const f25: u21 = 57388;
pub const f26: u21 = 57389;
pub const f27: u21 = 57390;
pub const f28: u21 = 57391;
pub const f29: u21 = 57392;
pub const f30: u21 = 57393;
pub const f31: u21 = 57394;
pub const @"f32": u21 = 57395;
pub const f33: u21 = 57396;
pub const f34: u21 = 57397;
pub const f35: u21 = 57398;
pub const kp_0: u21 = 57399;
pub const kp_1: u21 = 57400;
pub const kp_2: u21 = 57401;
pub const kp_3: u21 = 57402;
pub const kp_4: u21 = 57403;
pub const kp_5: u21 = 57404;
pub const kp_6: u21 = 57405;
pub const kp_7: u21 = 57406;
pub const kp_8: u21 = 57407;
pub const kp_9: u21 = 57408;
// TODO: Finish the kitty keys
const MAX_UNICODE: u21 = 1_114_112;
pub const f1: u21 = MAX_UNICODE + 1;
pub const f2: u21 = MAX_UNICODE + 2;
pub const f3: u21 = MAX_UNICODE + 3;
pub const f4: u21 = MAX_UNICODE + 4;
pub const f5: u21 = MAX_UNICODE + 5;
pub const f6: u21 = MAX_UNICODE + 6;
pub const f7: u21 = MAX_UNICODE + 7;
pub const f8: u21 = MAX_UNICODE + 8;
pub const f9: u21 = MAX_UNICODE + 9;
pub const f10: u21 = MAX_UNICODE + 10;
pub const f11: u21 = MAX_UNICODE + 11;
pub const f12: u21 = MAX_UNICODE + 12;

View file

@ -1,6 +1,8 @@
const std = @import("std"); const std = @import("std");
const os = std.os; const os = std.os;
const App = @import("odditui.zig").App; const odditui = @import("main.zig");
const App = odditui.App;
const Key = odditui.Key;
const log = std.log.scoped(.tty); const log = std.log.scoped(.tty);
@ -95,7 +97,29 @@ pub fn run(
const b = buf[i]; const b = buf[i];
switch (state) { switch (state) {
.ground => { .ground => {
app.postEvent(.{ .key = b }); switch (b) {
0x00 => { // ctrl+@
const event = Key{
.codepoint = '@',
.mods = .{ .ctrl = true },
};
app.postEvent(.{ .key_press = event });
},
0x01...0x1A => { // ctrl+[a-z]
const event = Key{
.codepoint = b + 0x60, // turn it lowercase
.mods = .{ .ctrl = true },
};
app.postEvent(.{ .key_press = event });
},
0x20...0x7E => { // ascii
const event = Key{
.codepoint = @intCast(b),
};
app.postEvent(.{ .key_press = event });
},
else => {},
}
}, },
else => {}, else => {},
} }

View file

@ -2,6 +2,7 @@ const std = @import("std");
const queue = @import("queue.zig"); const queue = @import("queue.zig");
const Tty = @import("Tty.zig"); const Tty = @import("Tty.zig");
const Key = @import("Key.zig");
/// App is the entrypoint for an odditui application. The provided type T should /// App is the entrypoint for an odditui application. The provided type T should
/// be a tagged union which contains all of the events the application will /// be a tagged union which contains all of the events the application will

View file

@ -1,29 +1,9 @@
const std = @import("std"); pub const App = @import("app.zig").App;
const Tty = @import("tty/Tty.zig"); pub const Key = @import("Key.zig");
const odditui = @import("odditui.zig");
const log = std.log.scoped(.main); test {
pub fn main() !void { _ = @import("Key.zig");
var app: odditui.App(Event) = try odditui.App(Event).init(.{}); _ = @import("Tty.zig");
_ = @import("app.zig");
try app.start();
while (true) {
const event = app.nextEvent();
log.debug("event: {}", .{event});
}
app.stop();
}
const Event = union(enum) {
key: u8,
mouse: u8,
};
fn eventCallback(_: Event) void {}
test "simple test" {
_ = @import("odditui.zig");
_ = @import("queue.zig"); _ = @import("queue.zig");
} }

View file

@ -1,10 +0,0 @@
const std = @import("std");
const testing = std.testing;
export fn add(a: i32, b: i32) i32 {
return a + b;
}
test "basic add functionality" {
try testing.expect(add(3, 7) == 10);
}