diff --git a/lib/init/build.zig b/lib/init/build.zig index 9be615ac31d0..135ecb6aa71d 100644 --- a/lib/init/build.zig +++ b/lib/init/build.zig @@ -42,14 +42,14 @@ pub fn build(b: *std.Build) void { // Modules can depend on one another using the `std.Build.Module.addImport` function. // This is what allows Zig source code to use `@import("foo")` where 'foo' is not a // file path. In this case, we set up `exe_mod` to import `lib_mod`. - exe_mod.addImport("$_lib", lib_mod); + exe_mod.addImport("$root_lib", lib_mod); // Now, we will create a static library based on the module we created above. // This creates a `std.Build.Step.Compile`, which is the build step responsible // for actually invoking the compiler. const lib = b.addLibrary(.{ .linkage = .static, - .name = "$", + .name = "$root", .root_module = lib_mod, }); @@ -61,7 +61,7 @@ pub fn build(b: *std.Build) void { // This creates another `std.Build.Step.Compile`, but this one builds an executable // rather than a static library. const exe = b.addExecutable(.{ - .name = "$", + .name = "$root", .root_module = exe_mod, }); diff --git a/lib/init/build.zig.zon b/lib/init/build.zig.zon index cb7229042fc8..c391fa9e419d 100644 --- a/lib/init/build.zig.zon +++ b/lib/init/build.zig.zon @@ -6,7 +6,7 @@ // // It is redundant to include "zig" in this name because it is already // within the Zig package namespace. - .name = "$", + .name = "$root", // This is a [Semantic Version](https://semver.org/). // In a future version of Zig it will be used for package deduplication. @@ -15,7 +15,7 @@ // This field is optional. // This is currently advisory only; Zig does not yet do anything // with this value. - //.minimum_zig_version = "0.11.0", + .minimum_zig_version = "$version", // This field is optional. // Each dependency must either provide a `url` and `hash`, or a `path`. diff --git a/lib/init/src/main.zig b/lib/init/src/main.zig index caf8f4f37a96..89bf5da4d103 100644 --- a/lib/init/src/main.zig +++ b/lib/init/src/main.zig @@ -1,6 +1,9 @@ //! By convention, main.zig is where your main function lives in the case that //! you are building an executable. If you are making a library, the convention //! is to delete this file and start with root.zig instead. +const std = @import("std"); +/// This imports the separate module containing `root.zig`. Take a look in `build.zig` for details. +const lib = @import("$root_lib"); pub fn main() !void { // Prints to stderr (it's a shortcut based on `std.io.getStdErr()`) @@ -38,8 +41,3 @@ test "fuzz example" { }; try std.testing.fuzz(global.testOne, .{}); } - -const std = @import("std"); - -/// This imports the separate module containing `root.zig`. Take a look in `build.zig` for details. -const lib = @import("$_lib"); diff --git a/src/main.zig b/src/main.zig index a00261cc3083..84fcb1d664e7 100644 --- a/src/main.zig +++ b/src/main.zig @@ -4739,8 +4739,14 @@ fn cmdInit(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { }; var ok_count: usize = 0; + // default replacements for templates + const replacements = &[_]Replacement{ + .{ .variable = "$root", .replacement = cwd_basename }, + .{ .variable = "$version", .replacement = build_options.version }, + }; + for (template_paths) |template_path| { - if (templates.write(arena, fs.cwd(), cwd_basename, template_path)) |_| { + if (templates.write(arena, fs.cwd(), template_path, replacements)) |_| { std.log.info("created {s}", .{template_path}); ok_count += 1; } else |err| switch (err) { @@ -7410,7 +7416,12 @@ fn loadManifest( var templates = findTemplates(gpa, arena); defer templates.deinit(); - templates.write(arena, options.dir, options.root_name, Package.Manifest.basename) catch |e| { + const replacements = &[_]Replacement{ + .{ .variable = "$root", .replacement = options.root_name }, + .{ .variable = "$version", .replacement = build_options.version }, + }; + + templates.write(arena, options.dir, Package.Manifest.basename, replacements) catch |e| { fatal("unable to write {s}: {s}", .{ Package.Manifest.basename, @errorName(e), }); @@ -7450,6 +7461,13 @@ fn loadManifest( return .{ manifest, ast }; } +/// replace variables for Zig templates +/// $root -> "project_name" +const Replacement = struct { + variable: []const u8, + replacement: []const u8, +}; + const Templates = struct { zig_lib_directory: Cache.Directory, dir: fs.Dir, @@ -7466,8 +7484,8 @@ const Templates = struct { templates: *Templates, arena: Allocator, out_dir: fs.Dir, - root_name: []const u8, template_path: []const u8, + replacements: ?[]const Replacement, ) !void { if (fs.path.dirname(template_path)) |dirname| { out_dir.makePath(dirname) catch |err| { @@ -7479,14 +7497,52 @@ const Templates = struct { const contents = templates.dir.readFileAlloc(arena, template_path, max_bytes) catch |err| { fatal("unable to read template file '{s}': {s}", .{ template_path, @errorName(err) }); }; + templates.buffer.clearRetainingCapacity(); try templates.buffer.ensureUnusedCapacity(contents.len); - for (contents) |c| { - if (c == '$') { - try templates.buffer.appendSlice(root_name); - } else { - try templates.buffer.append(c); + + var iterator = mem.splitScalar(u8, contents, '\n'); + + // replace variables like $root and $version with the project name + // and zig compiler version respectively + while (iterator.next()) |line| { + var i: usize = 0; + while (i < line.len) : (i += 1) { + const c = line[i]; + + if (replacements) |replace_items| { + if (c == '$') { + var found: bool = false; + + for (replace_items) |replacement| { + if (replacement.variable.len < 2) { + return error.InvalidVariable; + } + + if (line.len - i < replacement.variable.len) { + continue; + } + + // found a match, break out + if (mem.eql(u8, replacement.variable, line[i .. i + replacement.variable.len])) { + try templates.buffer.appendSlice(replacement.replacement); + i += replacement.variable.len - 1; + found = true; + break; + } + } + + if (!found) try templates.buffer.append(c); + } else { + // if we make it out here, no replacement was found, and we write out the literal '$' + try templates.buffer.append(c); + } + } else { + try templates.buffer.append(c); + } } + + try templates.buffer.append('\n'); } return out_dir.writeFile(.{