Skip to content

Commit

Permalink
support enums in config_gen (#1072)
Browse files Browse the repository at this point in the history
* support enum types in config_gen

* fix typo
  • Loading branch information
Techatrix authored Mar 17, 2023
1 parent 8d86d54 commit 0aacb76
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 30 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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` |
<!-- DO NOT EDIT -->

Expand Down
2 changes: 1 addition & 1 deletion schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
},
Expand Down
2 changes: 1 addition & 1 deletion src/Config.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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`
Expand Down
2 changes: 1 addition & 1 deletion src/config_gen/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
},
Expand Down
113 changes: 87 additions & 26 deletions src/config_gen/config_gen.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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;

Expand All @@ -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(),
});
}

Expand Down Expand Up @@ -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,
});
}
Expand All @@ -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");
Expand Down Expand Up @@ -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),
});
}
Expand Down Expand Up @@ -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,
});
}

Expand Down Expand Up @@ -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`
\\
);
}

0 comments on commit 0aacb76

Please sign in to comment.