diff --git a/build.zig b/build.zig index 5d7e313..4be36d0 100644 --- a/build.zig +++ b/build.zig @@ -343,8 +343,8 @@ const RunIntegrationTest = struct { return build_example; } - pub fn make(step: *std.Build.Step, prog_node: std.Progress.Node) anyerror!void { - _ = prog_node; + pub fn make(step: *std.Build.Step, options: std.Build.Step.MakeOptions) anyerror!void { + _ = options; const self: *Self = @fieldParentPtr("step", step); const b = self.step.owner; @@ -465,19 +465,15 @@ const AddObjectArchive = struct { // // If we call `linkLibrary` instead of this code, then the build will // fail with a linker failure complaining we have duplicate symbols. - for (destination.root_module.depending_steps.keys()) |compile| { - compile.step.dependOn(&source.step); - } + + _ = source.getEmittedBin(); // Indicate there is a dependency on the outputted binary. destination.root_module.include_dirs.append(b.allocator, .{ .other_step = source }) catch @panic("OOM"); - for (destination.root_module.depending_steps.keys()) |compile| { - source.getEmittedIncludeTree().addStepDependencies(&compile.step); - } return self; } - pub fn make(step: *std.Build.Step, prog_node: std.Progress.Node) anyerror!void { - _ = prog_node; + pub fn make(step: *std.Build.Step, options: std.Build.Step.MakeOptions) anyerror!void { + _ = options; const self: *Self = @fieldParentPtr("step", step); self.addObjects() catch |err| { return step.fail("Unable to add objects from {s}: {s}", .{ @@ -558,7 +554,7 @@ const GenerateGrammars = struct { generate_grammars.module.addImport( "tree_sitter", - generate_grammars.tree_sitter.module("tree_sitter"), + generate_grammars.tree_sitter.module("tree-sitter"), ); for (grammars, 0..) |grammar, index| { @@ -591,12 +587,12 @@ const GenerateGrammars = struct { root_module.addObject(object); } - root_module.addImport("tree_sitter", self.tree_sitter.module("tree_sitter")); + root_module.addImport("tree_sitter", self.tree_sitter.module("tree-sitter")); root_module.addImport("generated_grammars", self.module); } - pub fn make(step: *std.Build.Step, prog_node: std.Progress.Node) anyerror!void { - _ = prog_node; + pub fn make(step: *std.Build.Step, options: std.Build.Step.MakeOptions) anyerror!void { + _ = options; const self: *GenerateGrammars = @fieldParentPtr("step", step); self.writeModule() catch |err| { return step.fail("Unable to write {s}: {s}", .{ @@ -729,7 +725,7 @@ const Deps = struct { _ = AddObjectArchive.create(step, self.target, self.libcmark_gfm.artifact("cmark-gfm-extensions")); _ = AddObjectArchive.create(step, self.target, self.tree_sitter_core.artifact("tree-sitter")); step.root_module.addImport("mime", self.mime.module("mime")); - self.tree_sitter_grammars.link(&step.root_module); + self.tree_sitter_grammars.link(step.root_module); } }; @@ -752,11 +748,11 @@ fn formatTargetForRoc(b: *std.Build, target: std.Build.ResolvedTarget) []const u // Run `zig ar --help` to see the archive formats ar supports. fn formatTargetForAr(b: *std.Build, target: std.Build.ResolvedTarget) []const u8 { - return if (target.result.isGnu()) + return if (target.result.isGnuLibC()) "--format=gnu" - else if (target.result.isMusl()) + else if (target.result.isMuslLibC()) "--format=gnu" // This seems wrong, but nobody complained so :shrug:. - else if (target.result.isDarwin()) + else if (target.result.isDarwinLibC()) "--format=darwin" else { const triple = target.result.linuxTriple(b.allocator) catch @panic("OOM"); diff --git a/build.zig.zon b/build.zig.zon index b0327e7..73e78ea 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -1,23 +1,56 @@ .{ - .name = "jay", + // This is the default name used by packages depending on this one. For + // example, when a user runs `zig fetch --save `, this field is used + // as the key in the `dependencies` table. Although the user can choose a + // different name, most users will stick with this provided value. + // + // It is redundant to include "zig" in this name because it is already + // within the Zig package namespace. + .name = .jay, + + // This is a [Semantic Version](https://semver.org/). + // In a future version of Zig it will be used for package deduplication. .version = "0.0.0", - .minimum_zig_version = "0.13.0", + + // Together with name, this represents a globally unique package + // identifier. This field is generated by the Zig toolchain when the + // package is first created, and then *never changes*. This allows + // unambiguous detection of one package being an updated version of + // another. + // + // When forking a Zig project, this id should be regenerated (delete the + // field and run `zig build`) if the upstream project is still maintained. + // Otherwise, the fork is *hostile*, attempting to take control over the + // original project's identity. Thus it is recommended to leave the comment + // on the following line intact, so that it shows up in code reviews that + // modify the field. + .fingerprint = 0xef3e049a37930c09, // Changing this has security and trust implications. + + // Tracks the earliest Zig version that the package considers to be a + // supported use case. + .minimum_zig_version = "0.14.1", + + // This field is optional. + // Each dependency must either provide a `url` and `hash`, or a `path`. + // `zig build --fetch` can be used to fetch all dependencies of a package, recursively. + // Once all dependencies are fetched, `zig build` no longer requires + // internet connectivity. .dependencies = .{ .@"libcmark-gfm" = .{ - .url = "https://github.com/abhinav/libcmark-gfm.zig/archive/0.1.0.tar.gz", - .hash = "1220b8a2a0e06f9adbe77b64be7482f5814383e647ced9a332f100044881af5e23a7", + .url = "https://github.com/jwoudenberg/libcmark-gfm.zig/archive/e9f404c22433a2920e153d7acffd2a3f295e7a1d.tar.gz", + .hash = "12202c3b6f9578f15bfefd19d3eda430832797b2d721a17e05faaf2b340a72647d7e", }, .mime = .{ - .url = "https://github.com/andrewrk/mime/archive/refs/tags/2.0.1.tar.gz", - .hash = "12209083b0c43d0f68a26a48a7b26ad9f93b22c9cff710c78ddfebb47b89cfb9c7a4", + .url = "https://github.com/andrewrk/mime/archive/refs/tags/3.0.0.tar.gz", + .hash = "mime-3.0.0-zwmL-6wgAADuFwn7gr-_DAQDGJdIim94aDIPa6qO-6GT", }, .tree_sitter_core = .{ - .url = "https://github.com/tree-sitter/tree-sitter/archive/refs/tags/v0.24.6.tar.gz", - .hash = "1220f44691132e06e4575ab7fed7737c05da86e3f8130ffa59751ce6eaba1b1d73ef", + .url = "https://github.com/tree-sitter/tree-sitter/archive/ac13c86675c3ad131270dc135d1effac01ae09f9.tar.gz", + .hash = "tree_sitter-0.26.0-Tw2sR4m8CwAW_Ztr_DGPW-k3ld5RtyWl0Ay4mB4cFU3g", }, .tree_sitter = .{ - .url = "https://github.com/tree-sitter/zig-tree-sitter/archive/refs/tags/v0.24.1.tar.gz", - .hash = "12206c44990aab41e534a0d8d597f856a46cd39b9fb26ad77708f9d37751ea730c50", + .url = "https://github.com/tree-sitter/zig-tree-sitter/archive/b4b72c903e69998fc88e27e154a5e3cc9166551b.tar.gz", + .hash = "tree_sitter-0.25.0-8heIf51vAQConvVIgvm-9mVIbqh7yabZYqPXfOpS3YoG", }, .@"tree-sitter-elm" = .{ .url = "https://github.com/elm-tooling/tree-sitter-elm/archive/refs/tags/v5.7.0.tar.gz", diff --git a/flake.lock b/flake.lock index d5b19f4..dede246 100644 --- a/flake.lock +++ b/flake.lock @@ -34,38 +34,13 @@ "type": "github" } }, - "nixgl": { - "inputs": { - "flake-utils": [ - "roc", - "flake-utils" - ], - "nixpkgs": [ - "roc", - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1713543440, - "narHash": "sha256-lnzZQYG0+EXl/6NkGpyIz+FEOc/DSEG57AP1VsdeNrM=", - "owner": "guibou", - "repo": "nixGL", - "rev": "310f8e49a149e4c9ea52f1adf70cdc768ec53f8a", - "type": "github" - }, - "original": { - "owner": "guibou", - "repo": "nixGL", - "type": "github" - } - }, "nixpkgs": { "locked": { - "lastModified": 1737469691, - "narHash": "sha256-nmKOgAU48S41dTPIXAq0AHZSehWUn6ZPrUKijHAMmIk=", + "lastModified": 1748929857, + "narHash": "sha256-lcZQ8RhsmhsK8u7LIFsJhsLh/pzR9yZ8yqpTzyGdj+Q=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "9e4d5190a9482a1fb9d18adf0bdb83c6e506eaab", + "rev": "c2a03962b8e24e669fb37b7df10e7c79531ff1a4", "type": "github" }, "original": { @@ -95,16 +70,15 @@ "inputs": { "flake-compat": "flake-compat", "flake-utils": "flake-utils", - "nixgl": "nixgl", "nixpkgs": "nixpkgs_2", "rust-overlay": "rust-overlay" }, "locked": { - "lastModified": 1738131757, - "narHash": "sha256-cXWFnT2SlNvc8gRAhlUNakVGWii3VWZsvNijMRpX7XA=", + "lastModified": 1740189990, + "narHash": "sha256-UU9ngaSnlDQBPdII2mKIfLE8ix0HpSkfytM7iI7r44o=", "owner": "roc-lang", "repo": "roc", - "rev": "689c58f35e0a39ca59feba549f7fcf375562a7a6", + "rev": "5d6895908bcd2fd4c94633ab7b338ae3cdcbf8db", "type": "github" }, "original": { diff --git a/host/fanotify.zig b/host/fanotify.zig index 086a9a8..ba1c1c9 100644 --- a/host/fanotify.zig +++ b/host/fanotify.zig @@ -1,10 +1,9 @@ -// The code in this module is adapted from the std.os.linux module in the +// The code in this module is adapted from the std.posix module in the // Zig standard library, from commit 53a232e51d193ffc816347bda64921e869e6f32a // -// The master branch contains some conveniences for working with fanotify that -// haven't landed in the latest stable release, 0.13.0 at time of writing. Once -// 0.14 lands I'll switch to that and delete this module. -// The license for Zig project is included below. +// I'm having trouble calling these functions from std.posix. directly, +// getting a compiler error. Until I figure out a better fix, below are +// adapted versions of the functions I need. // The MIT License (Expat) // @@ -29,12 +28,10 @@ // THE SOFTWARE. const std = @import("std"); -const builtin = @import("builtin"); -const native_arch = builtin.cpu.arch; -const native_endian = native_arch.endian(); +const fanotify = std.os.linux.fanotify; pub fn fanotify_init(flags: fanotify.InitFlags, event_f_flags: u32) !i32 { - const rc = std.os.linux.fanotify_init(@as(u32, @bitCast(flags)), event_f_flags); + const rc = std.os.linux.fanotify_init(flags, event_f_flags); switch (std.posix.errno(rc)) { .SUCCESS => return @intCast(rc), .INVAL => return error.UnsupportedFlags, @@ -70,7 +67,7 @@ pub fn fanotify_markZ( ) !void { const rc = std.os.linux.fanotify_mark( fanotify_fd, - @as(u32, @bitCast(flags)), + flags, @bitCast(mask), dirfd, pathname, @@ -93,171 +90,21 @@ pub fn fanotify_markZ( } } -pub const fanotify = struct { - pub const InitFlags = packed struct(u32) { - CLOEXEC: bool = false, - NONBLOCK: bool = false, - CLASS: enum(u2) { - NOTIF = 0, - CONTENT = 1, - PRE_CONTENT = 2, - } = .NOTIF, - UNLIMITED_QUEUE: bool = false, - UNLIMITED_MARKS: bool = false, - ENABLE_AUDIT: bool = false, - REPORT_PIDFD: bool = false, - REPORT_TID: bool = false, - REPORT_FID: bool = false, - REPORT_DIR_FID: bool = false, - REPORT_NAME: bool = false, - REPORT_TARGET_FID: bool = false, - _: u19 = 0, - }; - - pub const MarkFlags = packed struct(u32) { - ADD: bool = false, - REMOVE: bool = false, - DONT_FOLLOW: bool = false, - ONLYDIR: bool = false, - MOUNT: bool = false, - /// Mutually exclusive with `IGNORE` - IGNORED_MASK: bool = false, - IGNORED_SURV_MODIFY: bool = false, - FLUSH: bool = false, - FILESYSTEM: bool = false, - EVICTABLE: bool = false, - /// Mutually exclusive with `IGNORED_MASK` - IGNORE: bool = false, - _: u21 = 0, - }; - - pub const MarkMask = packed struct(u64) { - /// File was accessed - ACCESS: bool = false, - /// File was modified - MODIFY: bool = false, - /// Metadata changed - ATTRIB: bool = false, - /// Writtable file closed - CLOSE_WRITE: bool = false, - /// Unwrittable file closed - CLOSE_NOWRITE: bool = false, - /// File was opened - OPEN: bool = false, - /// File was moved from X - MOVED_FROM: bool = false, - /// File was moved to Y - MOVED_TO: bool = false, - - /// Subfile was created - CREATE: bool = false, - /// Subfile was deleted - DELETE: bool = false, - /// Self was deleted - DELETE_SELF: bool = false, - /// Self was moved - MOVE_SELF: bool = false, - /// File was opened for exec - OPEN_EXEC: bool = false, - reserved13: u1 = 0, - /// Event queued overflowed - Q_OVERFLOW: bool = false, - /// Filesystem error - FS_ERROR: bool = false, - - /// File open in perm check - OPEN_PERM: bool = false, - /// File accessed in perm check - ACCESS_PERM: bool = false, - /// File open/exec in perm check - OPEN_EXEC_PERM: bool = false, - reserved19: u8 = 0, - /// Interested in child events - EVENT_ON_CHILD: bool = false, - /// File was renamed - RENAME: bool = false, - reserved30: u1 = 0, - /// Event occurred against dir - ONDIR: bool = false, - reserved31: u33 = 0, - }; - - pub const event_metadata = extern struct { - event_len: u32, - vers: u8, - reserved: u8, - metadata_len: u16, - mask: MarkMask align(8), - fd: i32, - pid: i32, - - pub const VERSION = 3; - }; - - pub const response = extern struct { - fd: i32, - response: u32, - }; - - /// Unique file identifier info record. - /// - /// This structure is used for records of types `EVENT_INFO_TYPE.FID`. - /// `EVENT_INFO_TYPE.DFID` and `EVENT_INFO_TYPE.DFID_NAME`. - /// - /// For `EVENT_INFO_TYPE.DFID_NAME` there is additionally a null terminated - /// name immediately after the file handle. - pub const event_info_fid = extern struct { - hdr: event_info_header, - fsid: kernel_fsid_t, - /// Following is an opaque struct file_handle that can be passed as - /// an argument to open_by_handle_at(2). - handle: [0]u8, - }; - - /// Variable length info record following event metadata. - pub const event_info_header = extern struct { - info_type: EVENT_INFO_TYPE, - pad: u8, - len: u16, - }; - - pub const EVENT_INFO_TYPE = enum(u8) { - FID = 1, - DFID_NAME = 2, - DFID = 3, - PIDFD = 4, - ERROR = 5, - OLD_DFID_NAME = 10, - OLD_DFID = 11, - NEW_DFID_NAME = 12, - NEW_DFID = 13, - }; -}; - -pub const file_handle = extern struct { - handle_bytes: u32, - handle_type: i32, - f_handle: [0]u8, -}; - -pub const kernel_fsid_t = fsid_t; -pub const fsid_t = [2]i32; - pub fn name_to_handle_at( dirfd: std.posix.fd_t, pathname: []const u8, - handle: *file_handle, + handle: *std.os.linux.file_handle, mount_id: *i32, flags: u32, ) !void { - const pathname_c = try toPosixPath(pathname); + const pathname_c = try std.posix.toPosixPath(pathname); return name_to_handle_atZ(dirfd, &pathname_c, handle, mount_id, flags); } pub fn name_to_handle_atZ( dirfd: std.posix.fd_t, pathname_z: [*:0]const u8, - handle: *file_handle, + handle: *std.os.linux.file_handle, mount_id: *i32, flags: u32, ) !void { @@ -276,7 +123,7 @@ pub fn name_to_handle_atZ( pub fn linux_name_to_handle_at( dirfd: std.posix.fd_t, pathname: [*:0]const u8, - handle: *file_handle, + handle: *std.os.linux.file_handle, mount_id: *i32, flags: u32, ) usize { @@ -289,16 +136,3 @@ pub fn linux_name_to_handle_at( flags, ); } - -// Used to convert a slice to a null terminated slice on the stack. -pub fn toPosixPath(file_path: []const u8) error{NameTooLong}![std.posix.PATH_MAX - 1:0]u8 { - if (std.debug.runtime_safety) std.debug.assert(std.mem.indexOfScalar(u8, file_path, 0) == null); - var path_with_null: [std.posix.PATH_MAX - 1:0]u8 = undefined; - // >= rather than > to make room for the null byte - if (file_path.len >= std.posix.PATH_MAX) return error.NameTooLong; - @memcpy(path_with_null[0..file_path.len], file_path); - path_with_null[file_path.len] = 0; - return path_with_null; -} - -pub const HANDLE_FID = std.os.linux.AT.REMOVEDIR; diff --git a/host/highlight.zig b/host/highlight.zig index 622f11f..a7d0f07 100644 --- a/host/highlight.zig +++ b/host/highlight.zig @@ -38,7 +38,7 @@ pub fn highlight( try parser.setLanguage(ts_lang); // TODO: switch to parser.parseInput to take input in a streaming fashion. - const tree = try parser.parseBuffer(input, null, null); + const tree = parser.parseString(input, null) orelse return error.TreeSitterParseFailure; defer tree.destroy(); const node = tree.rootNode(); @@ -78,7 +78,7 @@ pub fn highlight( if (range.start_byte < offset) continue; try writer.writeAll(input[offset..range.start_byte]); try writer.writeAll(" { - var buf: [std.fs.MAX_PATH_BYTES]u8 = undefined; + var buf: [std.fs.max_path_bytes]u8 = undefined; const cwd = try std.posix.getcwd(&buf); const argv0 = try std.fs.path.relative(gpa, cwd, parsed.show_help.argv0); defer gpa.free(argv0); @@ -58,7 +58,7 @@ fn run() !void { , .{ argv0, argv0, argv0 }); }, .mistake_no_output_path_passed => { - var buf: [std.fs.MAX_PATH_BYTES]u8 = undefined; + var buf: [std.fs.max_path_bytes]u8 = undefined; const cwd = try std.posix.getcwd(&buf); const argv0 = try std.fs.path.relative( gpa, @@ -79,7 +79,7 @@ fn run() !void { std.process.exit(1); }, .mistake_unknown_argument => { - var buf: [std.fs.MAX_PATH_BYTES]u8 = undefined; + var buf: [std.fs.max_path_bytes]u8 = undefined; const cwd = try std.posix.getcwd(&buf); const arg = parsed.mistake_unknown_argument.arg; const argv0 = try std.fs.path.relative( @@ -135,7 +135,7 @@ fn run_dev(gpa: std.mem.Allocator, argv0: []const u8) !void { var envMap = try EnvMap.init(gpa); defer envMap.deinit(); - var buf: [std.fs.MAX_PATH_BYTES]u8 = undefined; + var buf: [std.fs.max_path_bytes]u8 = undefined; const cwd_path = try std.posix.getcwd(&buf); const roc_main_abs = try std.fs.path.resolve(gpa, &.{ cwd_path, argv0 }); defer gpa.free(roc_main_abs); @@ -245,7 +245,7 @@ fn cacheDir( // In the hypothetical situation someone runs multiple instances of jay // in parallel, they should not to clobber each other's output directories. // We create a subdirectory for each. - var buf: [std.fs.MAX_PATH_BYTES]u8 = undefined; + var buf: [std.fs.max_path_bytes]u8 = undefined; const project_dir_hash = std.hash.Wyhash.hash(0, roc_main_abs); const project_dir_name = try std.fmt.bufPrint(&buf, "{}", .{project_dir_hash}); return jay_cache_dir.makeOpenPath(project_dir_name, .{}); @@ -354,7 +354,7 @@ pub fn handleChange( ); }, .path_changed => |entry| { - var buf: [std.fs.MAX_PATH_BYTES]u8 = undefined; + var buf: [std.fs.max_path_bytes]u8 = undefined; const path_bytes = if (entry.dir.bytes().len == 0) entry.file_name else diff --git a/host/platform.zig b/host/platform.zig index c309e20..54c9549 100644 --- a/host/platform.zig +++ b/host/platform.zig @@ -226,7 +226,7 @@ pub const RocPlatform = struct { while (roc_rule_iterator.next()) |platform_rule| { switch (platform_rule.processing) { .none, .xml, .markdown => { - const rule = .{ + const rule = Site.Rule{ .patterns = try rocListMapToOwnedSlice( RocStr, Str, @@ -569,19 +569,19 @@ fn roc_shm_open(name: [*:0]const u8, oflag: c_int, mode: c_uint) callconv(.C) c_ return std.c.shm_open(name, oflag, mode); } -fn roc_mmap(addr: ?*align(std.mem.page_size) anyopaque, length: usize, prot: c_uint, flags: std.c.MAP, fd: c_int, offset: c_int) callconv(.C) *anyopaque { +fn roc_mmap(addr: ?*align(std.heap.page_size_min) anyopaque, length: usize, prot: c_uint, flags: std.c.MAP, fd: c_int, offset: c_int) callconv(.C) *anyopaque { return std.c.mmap(addr, length, prot, flags, fd, offset); } comptime { if (builtin.os.tag == .macos or builtin.os.tag == .linux) { - @export(roc_getppid, .{ .name = "roc_getppid", .linkage = .strong }); - @export(roc_mmap, .{ .name = "roc_mmap", .linkage = .strong }); - @export(roc_shm_open, .{ .name = "roc_shm_open", .linkage = .strong }); + @export(&roc_getppid, .{ .name = "roc_getppid", .linkage = .strong }); + @export(&roc_mmap, .{ .name = "roc_mmap", .linkage = .strong }); + @export(&roc_shm_open, .{ .name = "roc_shm_open", .linkage = .strong }); } if (builtin.os.tag == .windows) { - @export(roc_getppid_windows_stub, .{ .name = "roc_getppid", .linkage = .strong }); + @export(&roc_getppid_windows_stub, .{ .name = "roc_getppid", .linkage = .strong }); } } diff --git a/host/roc/str.zig b/host/roc/str.zig index 172e27b..145e21f 100644 --- a/host/roc/str.zig +++ b/host/roc/str.zig @@ -598,477 +598,6 @@ fn strFromFloatHelp(comptime T: type, float: T) RocStr { return RocStr.init(&buf, result.len); } -// Str.split -pub fn strSplit(string: RocStr, delimiter: RocStr) callconv(.C) RocList { - const segment_count = countSegments(string, delimiter); - const list = RocList.allocate(@alignOf(RocStr), segment_count, @sizeOf(RocStr), true); - - if (list.bytes) |bytes| { - const strings = @as([*]RocStr, @ptrCast(@alignCast(bytes))); - strSplitHelp(strings, string, delimiter); - } - - return list; -} - -fn initFromSmallStr(slice_bytes: [*]u8, len: usize, _: usize) RocStr { - return RocStr.init(slice_bytes, len); -} - -// The alloc_ptr must already be shifted to be ready for storing in a seamless slice. -fn initFromBigStr(slice_bytes: [*]u8, len: usize, alloc_ptr: usize) RocStr { - // Here we can make seamless slices instead of copying to a new small str. - return RocStr{ - .bytes = slice_bytes, - .length = len | SEAMLESS_SLICE_BIT, - .capacity_or_alloc_ptr = alloc_ptr, - }; -} - -fn strSplitHelp(array: [*]RocStr, string: RocStr, delimiter: RocStr) void { - if (delimiter.len() == 0) { - string.incref(1); - array[0] = string; - return; - } - - var it = std.mem.split(u8, string.asSlice(), delimiter.asSlice()); - - var i: usize = 0; - var offset: usize = 0; - - while (it.next()) |zig_slice| { - const roc_slice = substringUnsafe(string, offset, zig_slice.len); - array[i] = roc_slice; - - i += 1; - offset += zig_slice.len + delimiter.len(); - } - - // Correct refcount for all of the splits made. - string.incref(i); // i == array.len() -} - -test "strSplitHelp: empty delimiter" { - // Str.split "abc" "" == ["abc"] - const str_arr = "abc"; - const str = RocStr.init(str_arr, str_arr.len); - - const delimiter_arr = ""; - const delimiter = RocStr.init(delimiter_arr, delimiter_arr.len); - - var array: [1]RocStr = undefined; - const array_ptr: [*]RocStr = &array; - - strSplitHelp(array_ptr, str, delimiter); - - const expected = [1]RocStr{ - str, - }; - - defer { - for (array) |roc_str| { - roc_str.decref(); - } - - for (expected) |roc_str| { - roc_str.decref(); - } - - str.decref(); - delimiter.decref(); - } - - try expectEqual(array.len, expected.len); - try expect(array[0].eq(expected[0])); -} - -test "strSplitHelp: no delimiter" { - // Str.split "abc" "!" == ["abc"] - const str_arr = "abc"; - const str = RocStr.init(str_arr, str_arr.len); - - const delimiter_arr = "!"; - const delimiter = RocStr.init(delimiter_arr, delimiter_arr.len); - - var array: [1]RocStr = undefined; - const array_ptr: [*]RocStr = &array; - - strSplitHelp(array_ptr, str, delimiter); - - const expected = [1]RocStr{ - str, - }; - - defer { - for (array) |roc_str| { - roc_str.decref(); - } - - for (expected) |roc_str| { - roc_str.decref(); - } - - str.decref(); - delimiter.decref(); - } - - try expectEqual(array.len, expected.len); - try expect(array[0].eq(expected[0])); -} - -test "strSplitHelp: empty start" { - const str_arr = "/a"; - const str = RocStr.init(str_arr, str_arr.len); - - const delimiter_arr = "/"; - const delimiter = RocStr.init(delimiter_arr, delimiter_arr.len); - - const array_len: usize = 2; - var array: [array_len]RocStr = [_]RocStr{ - undefined, - undefined, - }; - const array_ptr: [*]RocStr = &array; - - strSplitHelp(array_ptr, str, delimiter); - - const one = RocStr.init("a", 1); - - const expected = [2]RocStr{ - RocStr.empty(), one, - }; - - defer { - for (array) |rocStr| { - rocStr.decref(); - } - - for (expected) |rocStr| { - rocStr.decref(); - } - - str.decref(); - delimiter.decref(); - } - - try expectEqual(array.len, expected.len); - try expect(array[0].eq(expected[0])); - try expect(array[1].eq(expected[1])); -} - -test "strSplitHelp: empty end" { - const str_arr = "1---- ---- ---- ---- ----2---- ---- ---- ---- ----"; - const str = RocStr.init(str_arr, str_arr.len); - - const delimiter_arr = "---- ---- ---- ---- ----"; - const delimiter = RocStr.init(delimiter_arr, delimiter_arr.len); - - const array_len: usize = 3; - var array: [array_len]RocStr = [_]RocStr{ - undefined, - undefined, - undefined, - }; - const array_ptr: [*]RocStr = &array; - - strSplitHelp(array_ptr, str, delimiter); - - const one = RocStr.init("1", 1); - const two = RocStr.init("2", 1); - - const expected = [3]RocStr{ - one, two, RocStr.empty(), - }; - - defer { - for (array) |rocStr| { - rocStr.decref(); - } - - for (expected) |rocStr| { - rocStr.decref(); - } - - str.decref(); - delimiter.decref(); - } - - try expectEqual(array.len, expected.len); - try expect(array[0].eq(expected[0])); - try expect(array[1].eq(expected[1])); - try expect(array[2].eq(expected[2])); -} - -test "strSplitHelp: string equals delimiter" { - const str_delimiter_arr = "/"; - const str_delimiter = RocStr.init(str_delimiter_arr, str_delimiter_arr.len); - - const array_len: usize = 2; - var array: [array_len]RocStr = [_]RocStr{ - undefined, - undefined, - }; - const array_ptr: [*]RocStr = &array; - - strSplitHelp(array_ptr, str_delimiter, str_delimiter); - - const expected = [2]RocStr{ RocStr.empty(), RocStr.empty() }; - - defer { - for (array) |rocStr| { - rocStr.decref(); - } - - for (expected) |rocStr| { - rocStr.decref(); - } - - str_delimiter.decref(); - } - - try expectEqual(array.len, expected.len); - try expect(array[0].eq(expected[0])); - try expect(array[1].eq(expected[1])); -} - -test "strSplitHelp: delimiter on sides" { - const str_arr = "tttghittt"; - const str = RocStr.init(str_arr, str_arr.len); - - const delimiter_arr = "ttt"; - const delimiter = RocStr.init(delimiter_arr, delimiter_arr.len); - - const array_len: usize = 3; - var array: [array_len]RocStr = [_]RocStr{ - undefined, - undefined, - undefined, - }; - const array_ptr: [*]RocStr = &array; - strSplitHelp(array_ptr, str, delimiter); - - const ghi_arr = "ghi"; - const ghi = RocStr.init(ghi_arr, ghi_arr.len); - - const expected = [3]RocStr{ - RocStr.empty(), ghi, RocStr.empty(), - }; - - defer { - for (array) |rocStr| { - rocStr.decref(); - } - - for (expected) |rocStr| { - rocStr.decref(); - } - - str.decref(); - delimiter.decref(); - } - - try expectEqual(array.len, expected.len); - try expect(array[0].eq(expected[0])); - try expect(array[1].eq(expected[1])); - try expect(array[2].eq(expected[2])); -} - -test "strSplitHelp: three pieces" { - // Str.split "a!b!c" "!" == ["a", "b", "c"] - const str_arr = "a!b!c"; - const str = RocStr.init(str_arr, str_arr.len); - - const delimiter_arr = "!"; - const delimiter = RocStr.init(delimiter_arr, delimiter_arr.len); - - const array_len: usize = 3; - var array: [array_len]RocStr = undefined; - const array_ptr: [*]RocStr = &array; - - strSplitHelp(array_ptr, str, delimiter); - - const a = RocStr.init("a", 1); - const b = RocStr.init("b", 1); - const c = RocStr.init("c", 1); - - const expected_array = [array_len]RocStr{ - a, b, c, - }; - - defer { - for (array) |roc_str| { - roc_str.decref(); - } - - for (expected_array) |roc_str| { - roc_str.decref(); - } - - str.decref(); - delimiter.decref(); - } - - try expectEqual(expected_array.len, array.len); - try expect(array[0].eq(expected_array[0])); - try expect(array[1].eq(expected_array[1])); - try expect(array[2].eq(expected_array[2])); -} - -test "strSplitHelp: overlapping delimiter 1" { - // Str.split "aaa" "aa" == ["", "a"] - const str_arr = "aaa"; - const str = RocStr.init(str_arr, str_arr.len); - - const delimiter_arr = "aa"; - const delimiter = RocStr.init(delimiter_arr, delimiter_arr.len); - - var array: [2]RocStr = undefined; - const array_ptr: [*]RocStr = &array; - - strSplitHelp(array_ptr, str, delimiter); - - const expected = [2]RocStr{ - RocStr.empty(), - RocStr.init("a", 1), - }; - - // strings are all small so we ignore freeing the memory - - try expectEqual(array.len, expected.len); - try expect(array[0].eq(expected[0])); - try expect(array[1].eq(expected[1])); -} - -test "strSplitHelp: overlapping delimiter 2" { - // Str.split "aaa" "aa" == ["", "a"] - const str_arr = "aaaa"; - const str = RocStr.init(str_arr, str_arr.len); - - const delimiter_arr = "aa"; - const delimiter = RocStr.init(delimiter_arr, delimiter_arr.len); - - var array: [3]RocStr = undefined; - const array_ptr: [*]RocStr = &array; - - strSplitHelp(array_ptr, str, delimiter); - - const expected = [3]RocStr{ - RocStr.empty(), - RocStr.empty(), - RocStr.empty(), - }; - - // strings are all small so we ignore freeing the memory - - try expectEqual(array.len, expected.len); - try expect(array[0].eq(expected[0])); - try expect(array[1].eq(expected[1])); - try expect(array[2].eq(expected[2])); -} - -// This is used for `Str.split : Str, Str -> Array Str -// It is used to count how many segments the input `_str` -// needs to be broken into, so that we can allocate a array -// of that size. It always returns at least 1. -pub fn countSegments(string: RocStr, delimiter: RocStr) callconv(.C) usize { - if (delimiter.isEmpty()) { - return 1; - } - - var it = std.mem.split(u8, string.asSlice(), delimiter.asSlice()); - var count: usize = 0; - - while (it.next()) |_| : (count += 1) {} - - return count; -} - -test "countSegments: long delimiter" { - // Str.split "str" "delimiter" == ["str"] - // 1 segment - const str_arr = "str"; - const str = RocStr.init(str_arr, str_arr.len); - - const delimiter_arr = "delimiter"; - const delimiter = RocStr.init(delimiter_arr, delimiter_arr.len); - - defer { - str.decref(); - delimiter.decref(); - } - - const segments_count = countSegments(str, delimiter); - try expectEqual(segments_count, 1); -} - -test "countSegments: delimiter at start" { - // Str.split "hello there" "hello" == ["", " there"] - // 2 segments - const str_arr = "hello there"; - const str = RocStr.init(str_arr, str_arr.len); - - const delimiter_arr = "hello"; - const delimiter = RocStr.init(delimiter_arr, delimiter_arr.len); - - defer { - str.decref(); - delimiter.decref(); - } - - const segments_count = countSegments(str, delimiter); - - try expectEqual(segments_count, 2); -} - -test "countSegments: delimiter interspered" { - // Str.split "a!b!c" "!" == ["a", "b", "c"] - // 3 segments - const str_arr = "a!b!c"; - const str = RocStr.init(str_arr, str_arr.len); - - const delimiter_arr = "!"; - const delimiter = RocStr.init(delimiter_arr, delimiter_arr.len); - - defer { - str.decref(); - delimiter.decref(); - } - - const segments_count = countSegments(str, delimiter); - - try expectEqual(segments_count, 3); -} - -test "countSegments: string equals delimiter" { - // Str.split "/" "/" == ["", ""] - // 2 segments - const str_delimiter_arr = "/"; - const str_delimiter = RocStr.init(str_delimiter_arr, str_delimiter_arr.len); - - defer { - str_delimiter.decref(); - } - - const segments_count = countSegments(str_delimiter, str_delimiter); - - try expectEqual(segments_count, 2); -} - -test "countSegments: overlapping delimiter 1" { - // Str.split "aaa" "aa" == ["", "a"] - const segments_count = countSegments(RocStr.init("aaa", 3), RocStr.init("aa", 2)); - - try expectEqual(segments_count, 2); -} - -test "countSegments: overlapping delimiter 2" { - // Str.split "aaa" "aa" == ["", "a"] - const segments_count = countSegments(RocStr.init("aaaa", 4), RocStr.init("aa", 2)); - - try expectEqual(segments_count, 3); -} - pub fn countUtf8Bytes(string: RocStr) callconv(.C) u64 { return @intCast(string.len()); } @@ -1795,55 +1324,6 @@ test "isWhitespace" { try expect(!isWhitespace('x')); } -pub fn strTrim(input_string: RocStr) callconv(.C) RocStr { - var string = input_string; - - if (string.isEmpty()) { - string.decref(); - return RocStr.empty(); - } - - const bytes_ptr = string.asU8ptrMut(); - - const leading_bytes = countLeadingWhitespaceBytes(string); - const original_len = string.len(); - - if (original_len == leading_bytes) { - string.decref(); - return RocStr.empty(); - } - - const trailing_bytes = countTrailingWhitespaceBytes(string); - const new_len = original_len - leading_bytes - trailing_bytes; - - if (string.isSmallStr()) { - // Just create another small string of the correct bytes. - // No need to decref because it is a small string. - return RocStr.init(string.asU8ptr() + leading_bytes, new_len); - } else if (leading_bytes == 0 and string.isUnique()) { - // Big and unique with no leading bytes to remove. - // Just take ownership and shrink the length. - var new_string = string; - new_string.length = new_len; - - return new_string; - } else if (string.isSeamlessSlice()) { - // Already a seamless slice, just update the range. - return RocStr{ - .bytes = bytes_ptr + leading_bytes, - .length = new_len | SEAMLESS_SLICE_BIT, - .capacity_or_alloc_ptr = string.capacity_or_alloc_ptr, - }; - } else { - // Not unique or removing leading bytes, just make a slice. - return RocStr{ - .bytes = bytes_ptr + leading_bytes, - .length = new_len | SEAMLESS_SLICE_BIT, - .capacity_or_alloc_ptr = @intFromPtr(bytes_ptr) >> 1, - }; - } -} - pub fn strTrimStart(input_string: RocStr) callconv(.C) RocStr { var string = input_string; @@ -1892,54 +1372,6 @@ pub fn strTrimStart(input_string: RocStr) callconv(.C) RocStr { } } -pub fn strTrimEnd(input_string: RocStr) callconv(.C) RocStr { - var string = input_string; - - if (string.isEmpty()) { - string.decref(); - return RocStr.empty(); - } - - const bytes_ptr = string.asU8ptrMut(); - - const trailing_bytes = countTrailingWhitespaceBytes(string); - const original_len = string.len(); - - if (original_len == trailing_bytes) { - string.decref(); - return RocStr.empty(); - } - - const new_len = original_len - trailing_bytes; - - if (string.isSmallStr()) { - // Just create another small string of the correct bytes. - // No need to decref because it is a small string. - return RocStr.init(string.asU8ptr(), new_len); - } else if (string.isUnique()) { - // Big and unique with no leading bytes to remove. - // Just take ownership and shrink the length. - var new_string = string; - new_string.length = new_len; - - return new_string; - } else if (string.isSeamlessSlice()) { - // Already a seamless slice, just update the range. - return RocStr{ - .bytes = bytes_ptr, - .length = new_len | SEAMLESS_SLICE_BIT, - .capacity_or_alloc_ptr = string.capacity_or_alloc_ptr, - }; - } else { - // Not unique, just make a slice. - return RocStr{ - .bytes = bytes_ptr, - .length = new_len | SEAMLESS_SLICE_BIT, - .capacity_or_alloc_ptr = @intFromPtr(bytes_ptr) >> 1, - }; - } -} - fn countLeadingWhitespaceBytes(string: RocStr) usize { var byte_count: usize = 0; @@ -1956,22 +1388,6 @@ fn countLeadingWhitespaceBytes(string: RocStr) usize { return byte_count; } -fn countTrailingWhitespaceBytes(string: RocStr) usize { - var byte_count: usize = 0; - - const bytes = string.asU8ptr()[0..string.len()]; - var iter = ReverseUtf8View.initUnchecked(bytes).iterator(); - while (iter.nextCodepoint()) |codepoint| { - if (isWhitespace(codepoint)) { - byte_count += unicode.utf8CodepointSequenceLength(codepoint) catch break; - } else { - break; - } - } - - return byte_count; -} - fn rcNone(_: ?[*]u8) callconv(.C) void {} fn decStr(ptr: ?[*]u8) callconv(.C) void { @@ -1979,61 +1395,6 @@ fn decStr(ptr: ?[*]u8) callconv(.C) void { str_ptr.decref(); } -/// A backwards version of Utf8View from std.unicode -const ReverseUtf8View = struct { - bytes: []const u8, - - pub fn initUnchecked(s: []const u8) ReverseUtf8View { - return ReverseUtf8View{ .bytes = s }; - } - - pub fn iterator(s: ReverseUtf8View) ReverseUtf8Iterator { - return ReverseUtf8Iterator{ - .bytes = s.bytes, - .i = if (s.bytes.len > 0) s.bytes.len - 1 else null, - }; - } -}; - -/// A backwards version of Utf8Iterator from std.unicode -const ReverseUtf8Iterator = struct { - bytes: []const u8, - // NOTE null signifies complete/empty - i: ?usize, - - pub fn nextCodepointSlice(it: *ReverseUtf8Iterator) ?[]const u8 { - if (it.i) |index| { - var i = index; - - // NOTE this relies on the string being valid utf8 to not run off the end - while (!utf8BeginByte(it.bytes[i])) { - i -= 1; - } - - const cp_len = unicode.utf8ByteSequenceLength(it.bytes[i]) catch unreachable; - const slice = it.bytes[i .. i + cp_len]; - - it.i = if (i == 0) null else i - 1; - - return slice; - } else { - return null; - } - } - - pub fn nextCodepoint(it: *ReverseUtf8Iterator) ?u21 { - const slice = it.nextCodepointSlice() orelse return null; - - return switch (slice.len) { - 1 => @as(u21, slice[0]), - 2 => unicode.utf8Decode2(slice) catch unreachable, - 3 => unicode.utf8Decode3(slice) catch unreachable, - 4 => unicode.utf8Decode4(slice) catch unreachable, - else => unreachable, - }; - } -}; - fn utf8BeginByte(byte: u8) bool { return switch (byte) { 0b1000_0000...0b1011_1111 => false, @@ -2041,97 +1402,6 @@ fn utf8BeginByte(byte: u8) bool { }; } -test "strTrim: empty" { - const trimmedEmpty = strTrim(RocStr.empty()); - try expect(trimmedEmpty.eq(RocStr.empty())); -} - -test "strTrim: null byte" { - const bytes = [_]u8{0}; - const original = RocStr.init(&bytes, 1); - - try expectEqual(@as(usize, 1), original.len()); - try expectEqual(@as(usize, SMALL_STR_MAX_LENGTH), original.getCapacity()); - - const original_with_capacity = reserve(original, 40); - defer original_with_capacity.decref(); - - try expectEqual(@as(usize, 1), original_with_capacity.len()); - try expectEqual(@as(usize, 64), original_with_capacity.getCapacity()); - - const trimmed = strTrim(original.clone()); - defer trimmed.decref(); - - try expect(original.eq(trimmed)); -} - -test "strTrim: blank" { - const original_bytes = " "; - const original = RocStr.init(original_bytes, original_bytes.len); - - const trimmed = strTrim(original); - defer trimmed.decref(); - - try expect(trimmed.eq(RocStr.empty())); -} - -test "strTrim: large to large" { - const original_bytes = " hello even more giant world "; - const original = RocStr.init(original_bytes, original_bytes.len); - - try expect(!original.isSmallStr()); - - const expected_bytes = "hello even more giant world"; - const expected = RocStr.init(expected_bytes, expected_bytes.len); - defer expected.decref(); - - try expect(!expected.isSmallStr()); - - const trimmed = strTrim(original); - defer trimmed.decref(); - - try expect(trimmed.eq(expected)); -} - -test "strTrim: large to small sized slice" { - const original_bytes = " hello "; - const original = RocStr.init(original_bytes, original_bytes.len); - - try expect(!original.isSmallStr()); - - const expected_bytes = "hello"; - const expected = RocStr.init(expected_bytes, expected_bytes.len); - defer expected.decref(); - - try expect(expected.isSmallStr()); - - try expect(original.isUnique()); - const trimmed = strTrim(original); - defer trimmed.decref(); - - try expect(trimmed.eq(expected)); - try expect(!trimmed.isSmallStr()); -} - -test "strTrim: small to small" { - const original_bytes = " hello "; - const original = RocStr.init(original_bytes, original_bytes.len); - defer original.decref(); - - try expect(original.isSmallStr()); - - const expected_bytes = "hello"; - const expected = RocStr.init(expected_bytes, expected_bytes.len); - defer expected.decref(); - - try expect(expected.isSmallStr()); - - const trimmed = strTrim(original); - - try expect(trimmed.eq(expected)); - try expect(trimmed.isSmallStr()); -} - test "strTrimStart: empty" { const trimmedEmpty = strTrimStart(RocStr.empty()); try expect(trimmedEmpty.eq(RocStr.empty())); @@ -2204,99 +1474,6 @@ test "strTrimStart: small to small" { try expect(trimmed.isSmallStr()); } -test "strTrimEnd: empty" { - const trimmedEmpty = strTrimEnd(RocStr.empty()); - try expect(trimmedEmpty.eq(RocStr.empty())); -} - -test "strTrimEnd: blank" { - const original_bytes = " "; - const original = RocStr.init(original_bytes, original_bytes.len); - defer original.decref(); - - const trimmed = strTrimEnd(original); - - try expect(trimmed.eq(RocStr.empty())); -} - -test "strTrimEnd: large to large" { - const original_bytes = " hello even more giant world "; - const original = RocStr.init(original_bytes, original_bytes.len); - defer original.decref(); - - try expect(!original.isSmallStr()); - - const expected_bytes = " hello even more giant world"; - const expected = RocStr.init(expected_bytes, expected_bytes.len); - defer expected.decref(); - - try expect(!expected.isSmallStr()); - - const trimmed = strTrimEnd(original); - - try expect(trimmed.eq(expected)); -} - -test "strTrimEnd: large to small" { - // `original` will be consumed by the concat; do not free explicitly - const original_bytes = " hello "; - const original = RocStr.init(original_bytes, original_bytes.len); - - try expect(!original.isSmallStr()); - - const expected_bytes = " hello"; - const expected = RocStr.init(expected_bytes, expected_bytes.len); - defer expected.decref(); - - try expect(expected.isSmallStr()); - - const trimmed = strTrimEnd(original); - defer trimmed.decref(); - - try expect(trimmed.eq(expected)); - try expect(!trimmed.isSmallStr()); -} - -test "strTrimEnd: small to small" { - const original_bytes = " hello "; - const original = RocStr.init(original_bytes, original_bytes.len); - defer original.decref(); - - try expect(original.isSmallStr()); - - const expected_bytes = " hello"; - const expected = RocStr.init(expected_bytes, expected_bytes.len); - defer expected.decref(); - - try expect(expected.isSmallStr()); - - const trimmed = strTrimEnd(original); - - try expect(trimmed.eq(expected)); - try expect(trimmed.isSmallStr()); -} - -test "ReverseUtf8View: hello world" { - const original_bytes = "hello world"; - const expected_bytes = "dlrow olleh"; - - var i: usize = 0; - var iter = ReverseUtf8View.initUnchecked(original_bytes).iterator(); - while (iter.nextCodepoint()) |codepoint| { - try expect(expected_bytes[i] == codepoint); - i += 1; - } -} - -test "ReverseUtf8View: empty" { - const original_bytes = ""; - - var iter = ReverseUtf8View.initUnchecked(original_bytes).iterator(); - while (iter.nextCodepoint()) |_| { - try expect(false); - } -} - test "capacity: small string" { const data_bytes = "foobar"; var data = RocStr.init(data_bytes, data_bytes.len); diff --git a/host/scan.zig b/host/scan.zig index 13ef85d..c2109b6 100644 --- a/host/scan.zig +++ b/host/scan.zig @@ -133,7 +133,7 @@ pub fn Scanner(Filter: type) type { const path = if (current.sub_path.bytes().len == 0) iter_entry.name else blk: { - var buf: [std.fs.MAX_PATH_BYTES]u8 = undefined; + var buf: [std.fs.max_path_bytes]u8 = undefined; break :blk try std.fmt.bufPrint( &buf, "{s}/{s}", diff --git a/host/site.zig b/host/site.zig index eaa091b..fe6b1bd 100644 --- a/host/site.zig +++ b/host/site.zig @@ -167,7 +167,7 @@ pub const Site = struct { error.Unexpected, => return err, }; - const stat = std.fs.File.Stat.fromSystem(posix_stat); + const stat = std.fs.File.Stat.fromPosix(posix_stat); if (is_dir) break :file_exists; return if (is_new) self.initPage(source_path, stat) @@ -397,7 +397,7 @@ pub const Site = struct { const output_path = switch (page.processing) { .xml, .none => source_path, .markdown => blk: { - var buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined; + var buffer: [std.fs.max_path_bytes]u8 = undefined; const output_path_bytes = try self.outputPathForMarkdownFile(&buffer, source_path); break :blk try self.strs.intern(output_path_bytes); }, @@ -526,7 +526,7 @@ pub const Site = struct { if (pattern.index() == Str.init_index) { const pattern_index = self.list_patterns.count(); _ = pattern.replaceIndex(pattern_index); - var list_pattern = .{ + var list_pattern = ListPattern{ .pattern = pattern, .page_uses = BitSet{}, }; diff --git a/host/tests.zig b/host/tests.zig index 503c147..73e8fa2 100644 --- a/host/tests.zig +++ b/host/tests.zig @@ -549,7 +549,7 @@ test "add a symlink to a directory => jay treats it as a regular directory" { var site = test_run_loop.test_site.site; const watcher = test_run_loop.watcher; - var buf: [std.fs.MAX_PATH_BYTES]u8 = undefined; + var buf: [std.fs.max_path_bytes]u8 = undefined; const link_target = try std.fmt.bufPrint(&buf, "../{s}", .{tmpdir.sub_path}); try site.source_root.symLink(link_target, "linked", .{ .is_directory = true }); @@ -582,7 +582,7 @@ test "add a symlink to a file => jay shows an error" { var site = test_run_loop.test_site.site; const watcher = test_run_loop.watcher; - var buf: [std.fs.MAX_PATH_BYTES]u8 = undefined; + var buf: [std.fs.max_path_bytes]u8 = undefined; const link_target = try std.fmt.bufPrint(&buf, "../{s}/file.md", .{tmpdir.sub_path}); try site.source_root.symLink(link_target, "file.md", .{ .is_directory = false }); diff --git a/host/watch-linux.zig b/host/watch-linux.zig index b16517f..fa92ae6 100644 --- a/host/watch-linux.zig +++ b/host/watch-linux.zig @@ -110,7 +110,7 @@ pub const Watcher = struct { ); } - const M = fanotify.fanotify.event_metadata; + const M = std.os.linux.fanotify.event_metadata; fn next(self: *Self) !?Change { var meta: [*]align(1) M = @ptrCast(@as([*]u8, @ptrCast(&self.events_buf)) + self.offset); @@ -131,7 +131,7 @@ pub const Watcher = struct { const mask = meta[0].mask; if (mask.Q_OVERFLOW) return .{ .changes_missed = void{} }; - const fid: *align(1) fanotify.fanotify.event_info_fid = @ptrCast(meta + 1); + const fid: *align(1) std.os.linux.fanotify.event_info_fid = @ptrCast(meta + 1); switch (fid.hdr.info_type) { .DFID_NAME => {}, else => |t| { @@ -144,7 +144,7 @@ pub const Watcher = struct { // watched directory in which the change happened. It's directly // followed by a null-terminated byte representing the filename // in that directory modified. - const file_handle: *align(1) fanotify.file_handle = @ptrCast(&fid.handle); + const file_handle: *align(1) std.os.linux.file_handle = @ptrCast(&fid.handle); const dir = self.dirs.get(.{ .handle = file_handle }) orelse { return error.ReceivedEventForUnwatchedDir; }; @@ -161,7 +161,7 @@ pub const Watcher = struct { return null; } - const fan_mask: fanotify.fanotify.MarkMask = .{ + const fan_mask: std.os.linux.fanotify.MarkMask = .{ .ATTRIB = true, .CLOSE_WRITE = true, .CREATE = true, @@ -307,7 +307,7 @@ test "file watching produces expected events" { } }); // Deleting a file from a directory after unwatching it triggers no change. - var path_buf: [std.fs.MAX_PATH_BYTES]u8 = undefined; + var path_buf: [std.fs.max_path_bytes]u8 = undefined; const abs_path = try mid.realpath("low", &path_buf); try watcher.unwatchDir(try strs.intern(abs_path)); try low.deleteFile("test.txt"); @@ -350,9 +350,9 @@ fn expectChange( ); const entries = switch (expected) { - .changes_missed => return, - .path_changed => .{ expected.path_changed, actual.path_changed }, - }; + .changes_missed => return, + .path_changed => .{ expected.path_changed, actual.path_changed }, + }; try std.testing.expectEqualStrings(entries[0].dir.bytes(), entries[1].dir.bytes()); try std.testing.expectEqualStrings(entries[0].file_name, entries[1].file_name); } @@ -386,21 +386,21 @@ fn id(path: []const u8) []const u8 { // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. const FileHandle = struct { - handle: *align(1) fanotify.file_handle, + handle: *align(1) std.os.linux.file_handle, const Hash = std.hash.Wyhash; fn forDir(gpa: std.mem.Allocator, root_dir: std.fs.Dir, path: []const u8) !FileHandle { - var file_handle_buffer: [@sizeOf(fanotify.file_handle) + 128]u8 align(@alignOf(fanotify.file_handle)) = undefined; + var file_handle_buffer: [@sizeOf(std.os.linux.file_handle) + 128]u8 align(@alignOf(std.os.linux.file_handle)) = undefined; var mount_id: i32 = undefined; - var buf: [std.fs.MAX_PATH_BYTES]u8 = undefined; + var buf: [std.fs.max_path_bytes]u8 = undefined; const adjusted_path = if (path.len == 0) "./" else std.fmt.bufPrint(&buf, "{s}/", .{path}) catch return error.NameTooLong; - const stack_ptr: *fanotify.file_handle = @ptrCast(&file_handle_buffer); - stack_ptr.handle_bytes = file_handle_buffer.len - @sizeOf(fanotify.file_handle); - try fanotify.name_to_handle_at(root_dir.fd, adjusted_path, stack_ptr, &mount_id, fanotify.HANDLE_FID); + const stack_ptr: *std.os.linux.file_handle = @ptrCast(&file_handle_buffer); + stack_ptr.handle_bytes = file_handle_buffer.len - @sizeOf(std.os.linux.file_handle); + try fanotify.name_to_handle_at(root_dir.fd, adjusted_path, stack_ptr, &mount_id, std.os.linux.AT.HANDLE_FID); const stack_lfh: FileHandle = .{ .handle = stack_ptr }; return stack_lfh.clone(gpa); } @@ -409,10 +409,10 @@ const FileHandle = struct { const bytes = lfh.slice(); const new_ptr = try gpa.alignedAlloc( u8, - @alignOf(fanotify.file_handle), - @sizeOf(fanotify.file_handle) + bytes.len, + @alignOf(std.os.linux.file_handle), + @sizeOf(std.os.linux.file_handle) + bytes.len, ); - const new_header: *fanotify.file_handle = @ptrCast(new_ptr); + const new_header: *std.os.linux.file_handle = @ptrCast(new_ptr); new_header.* = lfh.handle.*; const new: FileHandle = .{ .handle = new_header }; @memcpy(new.slice(), lfh.slice()); @@ -421,9 +421,9 @@ const FileHandle = struct { fn destroy(lfh: FileHandle, gpa: std.mem.Allocator) void { const ptr: [*]u8 = @ptrCast(lfh.handle); - const allocated_slice = ptr[0 .. @sizeOf(fanotify.file_handle) + lfh.handle.handle_bytes]; + const allocated_slice = ptr[0 .. @sizeOf(std.os.linux.file_handle) + lfh.handle.handle_bytes]; return gpa.free(@as( - []align(@alignOf(fanotify.file_handle)) u8, + []align(@alignOf(std.os.linux.file_handle)) u8, @alignCast(allocated_slice), )); } diff --git a/host/watch-macos.zig b/host/watch-macos.zig index f843525..029cecf 100644 --- a/host/watch-macos.zig +++ b/host/watch-macos.zig @@ -23,7 +23,7 @@ pub const Watcher = struct { changed_paths: std.fifo.LinearFifo(PathChange, .Dynamic), changed_paths_mutex: std.Thread.Mutex, changed_paths_semaphore: std.Thread.Semaphore, - buf: [std.fs.MAX_PATH_BYTES]u8, + buf: [std.fs.max_path_bytes]u8, handle: *anyopaque, stream: *anyopaque, FSEventStreamStop: *FSEventStreamStopType, @@ -115,7 +115,7 @@ pub const Watcher = struct { // https://developer.apple.com/documentation/corefoundation/cfstringbuiltinencodings/utf8 const utf8 = 134217984; - var buf: [std.fs.MAX_PATH_BYTES]u8 = undefined; + var buf: [std.fs.max_path_bytes]u8 = undefined; _ = try std.fmt.bufPrint(&buf, "{s}\x00", .{root_path}); const root_path_cfstring = CFStringCreateWithCString( null, diff --git a/host/xml.zig b/host/xml.zig index c3ce874..107eec9 100644 --- a/host/xml.zig +++ b/host/xml.zig @@ -47,7 +47,7 @@ pub fn parse( const name_end = std.mem.indexOfAnyPos(u8, document, index + 1, " \t\n\r>") orelse return error.CantFindCloseTagNameEnd; const name = document[2 + index .. name_end]; const tag_end = std.mem.indexOfScalarPos(u8, document, name_end, '>') orelse return error.CantFindCloseTagEnd; - var tag = stack.popOrNull() orelse return error.FoundCloseTagsWhenNoTagsWereOpen; + var tag = stack.pop() orelse return error.FoundCloseTagsWhenNoTagsWereOpen; if (!std.mem.eql(u8, tag.name, name)) return error.MismatchedCloseAndOpenTags; if (index_of(tag_names, name)) |tag_index| {