diff --git a/README.md b/README.md index a84209a..4025995 100644 --- a/README.md +++ b/README.md @@ -86,7 +86,7 @@ The following options are currently available. | `zig_lib_path` | `?[]const u8` | `null` | Zig library path, e.g. `/path/to/zig/lib/zig`, used to analyze std library imports | | `zig_exe_path` | `?[]const u8` | `null` | Zig executable path, e.g. `/path/to/zig/zig`, used to run the custom build runner. If `null`, zig is looked up in `PATH`. Will be used to infer the zig standard library path if none is provided | | `build_runner_path` | `?[]const u8` | `null` | Path to the `build_runner.zig` file provided by zls. null is equivalent to `${executable_directory}/build_runner.zig` | -| `global_cache_path` | `?[]const u8` | `null` | Path to a directory that will be used as zig's cache. null is equivalent to `${KnownFloders.Cache}/zls` | +| `global_cache_path` | `?[]const u8` | `null` | Path to a directory that will be used as zig's cache. null is equivalent to `${KnownFolders.Cache}/zls` | | `build_runner_global_cache_path` | `?[]const u8` | `null` | Path to a directory that will be used as the global cache path when executing a projects build.zig. null is equivalent to the path shown by `zig env` | diff --git a/schema.json b/schema.json index 2728d41..9c1e5e1 100644 --- a/schema.json +++ b/schema.json @@ -125,7 +125,7 @@ "default": "null" }, "global_cache_path": { - "description": "Path to a directory that will be used as zig's cache. null is equivalent to `${KnownFloders.Cache}/zls`", + "description": "Path to a directory that will be used as zig's cache. null is equivalent to `${KnownFolders.Cache}/zls`", "type": "string", "default": "null" }, diff --git a/src/Config.zig b/src/Config.zig index 773a3b2..3c95972 100644 --- a/src/Config.zig +++ b/src/Config.zig @@ -76,7 +76,7 @@ zig_exe_path: ?[]const u8 = null, /// Path to the `build_runner.zig` file provided by zls. null is equivalent to `${executable_directory}/build_runner.zig` build_runner_path: ?[]const u8 = null, -/// Path to a directory that will be used as zig's cache. null is equivalent to `${KnownFloders.Cache}/zls` +/// Path to a directory that will be used as zig's cache. null is equivalent to `${KnownFolders.Cache}/zls` global_cache_path: ?[]const u8 = null, /// Path to a directory that will be used as the global cache path when executing a projects build.zig. null is equivalent to the path shown by `zig env` diff --git a/src/config_gen/config.json b/src/config_gen/config.json index 6c3d5de..1ca86d9 100644 --- a/src/config_gen/config.json +++ b/src/config_gen/config.json @@ -146,7 +146,7 @@ }, { "name": "global_cache_path", - "description": "Path to a directory that will be used as zig's cache. null is equivalent to `${KnownFloders.Cache}/zls`", + "description": "Path to a directory that will be used as zig's cache. null is equivalent to `${KnownFolders.Cache}/zls`", "type": "?[]const u8", "default": "null" }, diff --git a/src/config_gen/config_gen.zig b/src/config_gen/config_gen.zig index 6d990f2..5a911ed 100644 --- a/src/config_gen/config_gen.zig +++ b/src/config_gen/config_gen.zig @@ -10,8 +10,70 @@ const ConfigOption = struct { description: []const u8, /// zig type in string form. e.g "u32", "[]const u8", "?usize" type: []const u8, + /// if the zig type should be an enum, this should contain + /// a list of enum values and `type` + /// If this is set, the value `type` should to be `enum` + @"enum": ?[]const []const u8 = null, /// used in Config.zig as the default initializer default: []const u8, + + fn getTypescriptType(self: ConfigOption) error{UnsupportedType}![]const u8 { + return if (std.mem.eql(u8, self.type, "?[]const u8")) + "string" + else if (std.mem.eql(u8, self.type, "bool")) + "boolean" + else if (std.mem.eql(u8, self.type, "usize")) + "integer" + else if (std.mem.eql(u8, self.type, "enum")) + "string" + else + error.UnsupportedType; + } + + fn formatZigType( + config: ConfigOption, + comptime fmt: []const u8, + options: std.fmt.FormatOptions, + writer: anytype, + ) !void { + _ = options; + if (fmt.len != 0) return std.fmt.invalidFmtError(fmt, ConfigOption); + if (config.@"enum") |enum_members| { + try writer.writeAll("enum {"); + if (enum_members.len > 1) try writer.writeByte(' '); + for (enum_members, 0..) |member_name, i| { + if (i != 0) try writer.writeAll(", "); + try writer.writeAll(member_name); + } + if (enum_members.len > 1) try writer.writeByte(' '); + try writer.writeByte('}'); + return; + } + try writer.writeAll(config.type); + } + + fn fmtZigType(self: ConfigOption) std.fmt.Formatter(formatZigType) { + return .{ .data = self }; + } + + fn formatDefaultValue( + config: ConfigOption, + comptime fmt: []const u8, + options: std.fmt.FormatOptions, + writer: anytype, + ) !void { + _ = options; + if (fmt.len != 0) return std.fmt.invalidFmtError(fmt, ConfigOption); + if (config.@"enum" != null) { + try writer.writeByte('.'); + } + const default = std.mem.trim(u8, config.default, &std.ascii.whitespace); + try writer.writeAll(default); + } + + fn fmtDefaultValue(self: ConfigOption) std.fmt.Formatter(formatDefaultValue) { + return .{ .data = self }; + } }; const Config = struct { @@ -29,20 +91,10 @@ const Schema = struct { const SchemaEntry = struct { description: []const u8, type: []const u8, + @"enum": ?[]const []const u8 = null, default: []const u8, }; -fn zigTypeToTypescript(ty: []const u8) ![]const u8 { - return if (std.mem.eql(u8, ty, "?[]const u8")) - "string" - else if (std.mem.eql(u8, ty, "bool")) - "boolean" - else if (std.mem.eql(u8, ty, "usize")) - "integer" - else - error.UnsupportedType; -} - fn generateConfigFile(allocator: std.mem.Allocator, config: Config, path: []const u8) !void { _ = allocator; @@ -64,13 +116,13 @@ fn generateConfigFile(allocator: std.mem.Allocator, config: Config, path: []cons try buff_out.writer().print( \\ \\/// {s} - \\{s}: {s} = {s}, + \\{}: {} = {}, \\ , .{ std.mem.trim(u8, option.description, &std.ascii.whitespace), - std.mem.trim(u8, option.name, &std.ascii.whitespace), - std.mem.trim(u8, option.type, &std.ascii.whitespace), - std.mem.trim(u8, option.default, &std.ascii.whitespace), + std.zig.fmtId(std.mem.trim(u8, option.name, &std.ascii.whitespace)), + option.fmtZigType(), + option.fmtDefaultValue(), }); } @@ -98,7 +150,8 @@ fn generateSchemaFile(allocator: std.mem.Allocator, config: Config, path: []cons for (config.options) |option| { properties.putAssumeCapacityNoClobber(option.name, .{ .description = option.description, - .type = try zigTypeToTypescript(option.type), + .type = try option.getTypescriptType(), + .@"enum" = option.@"enum", .default = option.default, }); } @@ -116,6 +169,7 @@ fn generateSchemaFile(allocator: std.mem.Allocator, config: Config, path: []cons .whitespace = .{ .indent_level = 1, }, + .emit_null_optional_fields = false, }, buff_out.writer()); _ = try buff_out.write("\n}\n"); @@ -150,12 +204,12 @@ fn updateREADMEFile(allocator: std.mem.Allocator, config: Config, path: []const for (config.options) |option| { try writer.print( - \\| `{s}` | `{s}` | `{s}` | {s} | + \\| `{s}` | `{s}` | `{}` | {s} | \\ , .{ std.mem.trim(u8, option.name, &std.ascii.whitespace), std.mem.trim(u8, option.type, &std.ascii.whitespace), - std.mem.trim(u8, option.default, &std.ascii.whitespace), + option.fmtDefaultValue(), std.mem.trim(u8, option.description, &std.ascii.whitespace), }); } @@ -209,19 +263,26 @@ fn generateVSCodeConfigFile(allocator: std.mem.Allocator, config: Config, path: const snake_case_name = try std.fmt.allocPrint(allocator, "zig.zls.{s}", .{option.name}); defer allocator.free(snake_case_name); const name = try snakeCaseToCamelCase(allocator, snake_case_name); + errdefer allocator.free(name); - var parser = std.json.Parser.init(allocator, false); - defer parser.deinit(); + const default: ?std.json.Value = blk: { + if (option.@"enum" != null) break :blk .{ .String = option.default }; - var value = try parser.parse(option.default); - defer value.deinit(); - const default = value.root; + var parser = std.json.Parser.init(allocator, false); + defer parser.deinit(); + + var value = try parser.parse(option.default); + defer value.deinit(); + + break :blk if (value.root != .Null) value.root else null; + }; configuration.putAssumeCapacityNoClobber(name, .{ - .type = try zigTypeToTypescript(option.type), + .type = try option.getTypescriptType(), .description = option.description, + .@"enum" = option.@"enum", .format = if (std.mem.indexOf(u8, option.name, "path") != null) "path" else null, - .default = if (default == .Null) null else default, + .default = default, }); } @@ -1023,7 +1084,7 @@ pub fn main() !void { try stderr.writeAll( \\Changing configuration options may also require editing the `package.json` from zls-vscode at https://github.com/zigtools/zls-vscode/blob/master/package.json - \\You can use `zig build gen -Dvscode-config-path=/path/to/output/file.json` to generate the new configuration properties which you can then copy into `package.json` + \\You can use `zig build gen -- --vscode-config-path /path/to/output/file.json` to generate the new configuration properties which you can then copy into `package.json` \\ ); }