support enums in config_gen (#1072)

* support enum types in config_gen

* fix typo
This commit is contained in:
Techatrix 2023-03-17 06:27:35 +00:00 committed by GitHub
parent 8d86d54c0d
commit 0aacb76743
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 91 additions and 30 deletions

View File

@ -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_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 | | `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` | | `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` | | `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` |
<!-- DO NOT EDIT --> <!-- DO NOT EDIT -->

View File

@ -125,7 +125,7 @@
"default": "null" "default": "null"
}, },
"global_cache_path": { "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", "type": "string",
"default": "null" "default": "null"
}, },

View File

@ -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` /// 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, 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, 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` /// 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`

View File

@ -146,7 +146,7 @@
}, },
{ {
"name": "global_cache_path", "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", "type": "?[]const u8",
"default": "null" "default": "null"
}, },

View File

@ -10,8 +10,70 @@ const ConfigOption = struct {
description: []const u8, description: []const u8,
/// zig type in string form. e.g "u32", "[]const u8", "?usize" /// zig type in string form. e.g "u32", "[]const u8", "?usize"
type: []const u8, 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 /// used in Config.zig as the default initializer
default: []const u8, 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 { const Config = struct {
@ -29,20 +91,10 @@ const Schema = struct {
const SchemaEntry = struct { const SchemaEntry = struct {
description: []const u8, description: []const u8,
type: []const u8, type: []const u8,
@"enum": ?[]const []const u8 = null,
default: []const u8, 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 { fn generateConfigFile(allocator: std.mem.Allocator, config: Config, path: []const u8) !void {
_ = allocator; _ = allocator;
@ -64,13 +116,13 @@ fn generateConfigFile(allocator: std.mem.Allocator, config: Config, path: []cons
try buff_out.writer().print( try buff_out.writer().print(
\\ \\
\\/// {s} \\/// {s}
\\{s}: {s} = {s}, \\{}: {} = {},
\\ \\
, .{ , .{
std.mem.trim(u8, option.description, &std.ascii.whitespace), std.mem.trim(u8, option.description, &std.ascii.whitespace),
std.mem.trim(u8, option.name, &std.ascii.whitespace), std.zig.fmtId(std.mem.trim(u8, option.name, &std.ascii.whitespace)),
std.mem.trim(u8, option.type, &std.ascii.whitespace), option.fmtZigType(),
std.mem.trim(u8, option.default, &std.ascii.whitespace), option.fmtDefaultValue(),
}); });
} }
@ -98,7 +150,8 @@ fn generateSchemaFile(allocator: std.mem.Allocator, config: Config, path: []cons
for (config.options) |option| { for (config.options) |option| {
properties.putAssumeCapacityNoClobber(option.name, .{ properties.putAssumeCapacityNoClobber(option.name, .{
.description = option.description, .description = option.description,
.type = try zigTypeToTypescript(option.type), .type = try option.getTypescriptType(),
.@"enum" = option.@"enum",
.default = option.default, .default = option.default,
}); });
} }
@ -116,6 +169,7 @@ fn generateSchemaFile(allocator: std.mem.Allocator, config: Config, path: []cons
.whitespace = .{ .whitespace = .{
.indent_level = 1, .indent_level = 1,
}, },
.emit_null_optional_fields = false,
}, buff_out.writer()); }, buff_out.writer());
_ = try buff_out.write("\n}\n"); _ = try buff_out.write("\n}\n");
@ -150,12 +204,12 @@ fn updateREADMEFile(allocator: std.mem.Allocator, config: Config, path: []const
for (config.options) |option| { for (config.options) |option| {
try writer.print( try writer.print(
\\| `{s}` | `{s}` | `{s}` | {s} | \\| `{s}` | `{s}` | `{}` | {s} |
\\ \\
, .{ , .{
std.mem.trim(u8, option.name, &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.type, &std.ascii.whitespace),
std.mem.trim(u8, option.default, &std.ascii.whitespace), option.fmtDefaultValue(),
std.mem.trim(u8, option.description, &std.ascii.whitespace), 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}); const snake_case_name = try std.fmt.allocPrint(allocator, "zig.zls.{s}", .{option.name});
defer allocator.free(snake_case_name); defer allocator.free(snake_case_name);
const name = try snakeCaseToCamelCase(allocator, snake_case_name); const name = try snakeCaseToCamelCase(allocator, snake_case_name);
errdefer allocator.free(name);
const default: ?std.json.Value = blk: {
if (option.@"enum" != null) break :blk .{ .String = option.default };
var parser = std.json.Parser.init(allocator, false); var parser = std.json.Parser.init(allocator, false);
defer parser.deinit(); defer parser.deinit();
var value = try parser.parse(option.default); var value = try parser.parse(option.default);
defer value.deinit(); defer value.deinit();
const default = value.root;
break :blk if (value.root != .Null) value.root else null;
};
configuration.putAssumeCapacityNoClobber(name, .{ configuration.putAssumeCapacityNoClobber(name, .{
.type = try zigTypeToTypescript(option.type), .type = try option.getTypescriptType(),
.description = option.description, .description = option.description,
.@"enum" = option.@"enum",
.format = if (std.mem.indexOf(u8, option.name, "path") != null) "path" else null, .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( 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 \\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`
\\ \\
); );
} }