From c2561d87ef891c33f5e5d904bc025733971341e4 Mon Sep 17 00:00:00 2001 From: CJ van den Berg Date: Wed, 1 Apr 2026 09:48:12 +0200 Subject: [PATCH] docs: add basic code samples --- README.md | 29 ++++++++++++++++++++ examples/simple-default.zig | 33 +++++++++++++++++++++++ examples/simple-polling.zig | 53 +++++++++++++++++++++++++++++++++++++ examples/simple-variant.zig | 45 +++++++++++++++++++++++++++++++ 4 files changed, 160 insertions(+) create mode 100644 examples/simple-default.zig create mode 100644 examples/simple-polling.zig create mode 100644 examples/simple-variant.zig diff --git a/README.md b/README.md index de75e26..8ee6bd6 100644 --- a/README.md +++ b/README.md @@ -125,6 +125,35 @@ const nightwatch = @import("nightwatch"); You now have programmatic access to the tracking engine. +### Example + +```zig +const nightwatch = @import("nightwatch"); +const std = @import("std"); + +const H = struct { + handler: nightwatch.Default.Handler, + + const vtable = nightwatch.Default.Handler.VTable{ .change = change, .rename = rename }; + + fn change(_: *nightwatch.Default.Handler, path: []const u8, event: nightwatch.EventType, _: nightwatch.ObjectType) error{HandlerFailed}!void { + std.debug.print("{s} {s}\n", .{ @tagName(event), path }); + } + + fn rename(_: *nightwatch.Default.Handler, src: []const u8, dst: []const u8, _: nightwatch.ObjectType) error{HandlerFailed}!void { + std.debug.print("rename {s} -> {s}\n", .{ src, dst }); + } +}; + +var h = H{ .handler = .{ .vtable = &H.vtable } }; +var watcher = try nightwatch.Default.init(allocator, &h.handler); +defer watcher.deinit(); +try watcher.watch("/path/to/dir"); +// watcher delivers events on a background thread until deinit() +``` + +See the [`examples/`](examples/) directory for complete, buildable programs. + --- # CLI Usage diff --git a/examples/simple-default.zig b/examples/simple-default.zig new file mode 100644 index 0000000..a04bf87 --- /dev/null +++ b/examples/simple-default.zig @@ -0,0 +1,33 @@ +//! Minimal nightwatch example: watch the current directory with the +//! platform default backend and print every event to stderr. +//! +//! Build and run (from this directory): +//! +//! zig build-exe --dep nightwatch -Msimple-default=simple-default.zig -Mnightwatch=../src/nightwatch.zig +//! ./simple-default + +const nightwatch = @import("nightwatch"); +const std = @import("std"); + +const H = struct { + handler: nightwatch.Default.Handler, + + const vtable = nightwatch.Default.Handler.VTable{ .change = change, .rename = rename }; + + fn change(_: *nightwatch.Default.Handler, path: []const u8, event: nightwatch.EventType, _: nightwatch.ObjectType) error{HandlerFailed}!void { + std.debug.print("{s} {s}\n", .{ @tagName(event), path }); + } + + fn rename(_: *nightwatch.Default.Handler, src: []const u8, dst: []const u8, _: nightwatch.ObjectType) error{HandlerFailed}!void { + std.debug.print("rename {s} -> {s}\n", .{ src, dst }); + } +}; + +pub fn main() !void { + const allocator = std.heap.page_allocator; + var h = H{ .handler = .{ .vtable = &H.vtable } }; + var watcher = try nightwatch.Default.init(allocator, &h.handler); + defer watcher.deinit(); + try watcher.watch("."); + std.Thread.sleep(std.time.ns_per_s * 60); +} diff --git a/examples/simple-polling.zig b/examples/simple-polling.zig new file mode 100644 index 0000000..d797b53 --- /dev/null +++ b/examples/simple-polling.zig @@ -0,0 +1,53 @@ +//! Minimal nightwatch example: watch the current directory with the Linux +//! inotify polling backend and print every event to stderr. +//! +//! Build and run (from this directory): +//! +//! zig build-exe --dep nightwatch -Msimple-polling=simple-polling.zig -Mnightwatch=../src/nightwatch.zig +//! ./simple-polling + +const nightwatch = @import("nightwatch"); +const std = @import("std"); + +// The .polling variant is Linux-only (inotify). Unlike the threaded backends, +// it does not spawn an internal thread; instead the caller drives event +// delivery by polling poll_fd() for readability and calling handle_read_ready() +// whenever data is available. The handler vtable requires an extra +// wait_readable callback that the backend calls to notify the handler that it +// should re-arm the fd in its polling loop before the next handle_read_ready(). +const Watcher = nightwatch.Create(.polling); + +const H = struct { + handler: Watcher.Handler, + + const vtable = Watcher.Handler.VTable{ .change = change, .rename = rename, .wait_readable = wait_readable }; + + fn change(_: *Watcher.Handler, path: []const u8, event: nightwatch.EventType, _: nightwatch.ObjectType) error{HandlerFailed}!void { + std.debug.print("{s} {s}\n", .{ @tagName(event), path }); + } + + fn rename(_: *Watcher.Handler, src: []const u8, dst: []const u8, _: nightwatch.ObjectType) error{HandlerFailed}!void { + std.debug.print("rename {s} -> {s}\n", .{ src, dst }); + } + + // Called by the backend at arm time and after each handle_read_ready(). + // Return .will_notify (currently the only option) to signal that the + // caller's loop will drive delivery. + fn wait_readable(_: *Watcher.Handler) error{HandlerFailed}!Watcher.Handler.ReadableStatus { + return .will_notify; + } +}; + +pub fn main() !void { + const allocator = std.heap.page_allocator; + var h = H{ .handler = .{ .vtable = &H.vtable } }; + var watcher = try Watcher.init(allocator, &h.handler); + defer watcher.deinit(); + try watcher.watch("."); + + var pfd = [_]std.posix.pollfd{.{ .fd = watcher.poll_fd(), .events = std.posix.POLL.IN, .revents = 0 }}; + while (true) { + _ = try std.posix.poll(&pfd, -1); + try watcher.handle_read_ready(); + } +} diff --git a/examples/simple-variant.zig b/examples/simple-variant.zig new file mode 100644 index 0000000..8c76002 --- /dev/null +++ b/examples/simple-variant.zig @@ -0,0 +1,45 @@ +//! Minimal nightwatch example: watch the current directory with an +//! explicitly selected backend variant and print every event to stderr. +//! +//! Build and run (from this directory): +//! +//! zig build-exe --dep nightwatch -Msimple-variant=simple-variant.zig -Mnightwatch=../src/nightwatch.zig +//! ./simple-variant + +const nightwatch = @import("nightwatch"); +const std = @import("std"); + +// Select a backend variant explicitly by passing a nightwatch.Variant value to +// nightwatch.Create(). The available variants depend on the target platform: +// +// Linux: .threaded (default), .polling +// macOS (kqueue): .kqueue (default), .kqueuedir +// macOS (FSEvents): .fsevents (default), .kqueue, .kqueuedir +// FreeBSD/OpenBSD/etc.: .kqueue (default), .kqueuedir +// Windows: .windows +// +// Replace nightwatch.default_variant below with any variant from the list above. +const Watcher = nightwatch.Create(nightwatch.default_variant); + +const H = struct { + handler: Watcher.Handler, + + const vtable = Watcher.Handler.VTable{ .change = change, .rename = rename }; + + fn change(_: *Watcher.Handler, path: []const u8, event: nightwatch.EventType, _: nightwatch.ObjectType) error{HandlerFailed}!void { + std.debug.print("{s} {s}\n", .{ @tagName(event), path }); + } + + fn rename(_: *Watcher.Handler, src: []const u8, dst: []const u8, _: nightwatch.ObjectType) error{HandlerFailed}!void { + std.debug.print("rename {s} -> {s}\n", .{ src, dst }); + } +}; + +pub fn main() !void { + const allocator = std.heap.page_allocator; + var h = H{ .handler = .{ .vtable = &H.vtable } }; + var watcher = try Watcher.init(allocator, &h.handler); + defer watcher.deinit(); + try watcher.watch("."); + std.Thread.sleep(std.time.ns_per_s * 60); +}