Skip to content

Commit 2add4b5

Browse files
committed
wip
1 parent 1a60160 commit 2add4b5

File tree

7 files changed

+70
-40
lines changed

7 files changed

+70
-40
lines changed

build.zig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ pub fn build(b: *std.Build) !void {
2222
const superhtml = b.addModule("superhtml", .{
2323
.root_source_file = b.path("src/root.zig"),
2424
.target = target,
25+
.optimize = optimize,
2526
});
2627
superhtml.addImport("scripty", scripty.module("scripty"));
2728
superhtml.addImport("tracy", tracy.module("tracy"));

src/cli/check.zig

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ const super = @import("superhtml");
33

44
const FileType = enum { html, super };
55

6-
pub fn run(gpa: std.mem.Allocator, args: []const []const u8) !void {
6+
pub fn run(gpa: std.mem.Allocator, args: []const []const u8) !noreturn {
77
const cmd = Command.parse(args);
88
var any_error = false;
99
switch (cmd.mode) {
@@ -64,6 +64,7 @@ pub fn run(gpa: std.mem.Allocator, args: []const []const u8) !void {
6464
if (any_error) {
6565
std.process.exit(1);
6666
}
67+
std.process.exit(0);
6768
}
6869

6970
fn checkDir(

src/cli/fmt.zig

Lines changed: 41 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -3,49 +3,49 @@ const super = @import("superhtml");
33

44
const FileType = enum { html, super };
55

6-
pub fn run(gpa: std.mem.Allocator, args: []const []const u8) !void {
6+
pub fn run(gpa: std.mem.Allocator, args: []const []const u8) !noreturn {
77
const cmd = Command.parse(args);
8-
var any_error = false;
8+
9+
var errors = false;
910
switch (cmd.mode) {
1011
.stdin => {
1112
var fr = std.fs.File.stdin().reader(&.{});
1213
var aw: std.Io.Writer.Allocating = .init(gpa);
1314
_ = try fr.interface.streamRemaining(&aw.writer);
1415
const in_bytes = try aw.toOwnedSliceSentinel(0);
1516

16-
const out_bytes = try fmtHtml(gpa, null, in_bytes, cmd.strict);
17-
18-
try std.fs.File.stdout().writeAll(out_bytes);
17+
const result = try fmtHtml(gpa, null, in_bytes, cmd.strict);
18+
try std.fs.File.stdout().writeAll(result.bytes);
19+
errors |= result.errors;
1920
},
2021
.stdin_super => {
2122
var fr = std.fs.File.stdin().reader(&.{});
2223
var aw: std.Io.Writer.Allocating = .init(gpa);
2324
_ = try fr.interface.streamRemaining(&aw.writer);
2425
const in_bytes = try aw.toOwnedSliceSentinel(0);
2526

26-
const out_bytes = try fmtSuper(gpa, null, in_bytes, cmd.strict);
27-
try std.fs.File.stdout().writeAll(out_bytes);
27+
const result = try fmtSuper(gpa, null, in_bytes, cmd.strict);
28+
try std.fs.File.stdout().writeAll(result.bytes);
29+
errors |= result.errors;
2830
},
2931
.paths => |paths| {
3032
// checkFile will reset the arena at the end of each call
3133
var arena_impl = std.heap.ArenaAllocator.init(gpa);
3234
for (paths) |path| {
33-
formatFile(
35+
errors |= formatFile(
3436
&arena_impl,
3537
cmd.check,
3638
std.fs.cwd(),
3739
path,
3840
path,
39-
&any_error,
4041
cmd.strict,
4142
) catch |err| switch (err) {
4243
error.IsDir, error.AccessDenied => {
43-
formatDir(
44+
errors |= formatDir(
4445
gpa,
4546
&arena_impl,
4647
cmd.check,
4748
path,
48-
&any_error,
4949
cmd.strict,
5050
) catch |dir_err| {
5151
std.debug.print("Error walking dir '{s}': {s}\n", .{
@@ -54,6 +54,7 @@ pub fn run(gpa: std.mem.Allocator, args: []const []const u8) !void {
5454
});
5555
std.process.exit(1);
5656
};
57+
continue;
5758
},
5859
else => {
5960
std.debug.print("Error while accessing '{s}': {s}\n", .{
@@ -66,39 +67,38 @@ pub fn run(gpa: std.mem.Allocator, args: []const []const u8) !void {
6667
},
6768
}
6869

69-
if (any_error) {
70-
std.process.exit(1);
71-
}
70+
std.process.exit(@intFromBool(errors));
7271
}
7372

7473
fn formatDir(
7574
gpa: std.mem.Allocator,
7675
arena_impl: *std.heap.ArenaAllocator,
7776
check: bool,
7877
path: []const u8,
79-
any_error: *bool,
8078
strict: bool,
81-
) !void {
79+
) !bool {
8280
var dir = try std.fs.cwd().openDir(path, .{ .iterate = true });
8381
defer dir.close();
8482
var walker = dir.walk(gpa) catch oom();
8583
defer walker.deinit();
84+
var errors = false;
8685
while (try walker.next()) |item| {
8786
switch (item.kind) {
8887
.file => {
89-
try formatFile(
88+
errors |= try formatFile(
9089
arena_impl,
9190
check,
9291
item.dir,
9392
item.basename,
9493
item.path,
95-
any_error,
9694
strict,
9795
);
9896
},
9997
else => {},
10098
}
10199
}
100+
101+
return errors;
102102
}
103103

104104
fn formatFile(
@@ -107,9 +107,8 @@ fn formatFile(
107107
base_dir: std.fs.Dir,
108108
sub_path: []const u8,
109109
full_path: []const u8,
110-
any_error: *bool,
111110
strict: bool,
112-
) !void {
111+
) !bool {
113112
defer _ = arena_impl.reset(.retain_capacity);
114113
const arena = arena_impl.allocator();
115114

@@ -132,10 +131,10 @@ fn formatFile(
132131
if (std.mem.eql(u8, ext, ".shtml")) {
133132
break :blk .super;
134133
}
135-
return;
134+
return false;
136135
};
137136

138-
const out_bytes = switch (file_type) {
137+
const result = switch (file_type) {
139138
.html => try fmtHtml(
140139
arena,
141140
full_path,
@@ -150,54 +149,64 @@ fn formatFile(
150149
),
151150
};
152151

153-
if (std.mem.eql(u8, out_bytes, in_bytes)) return;
152+
if (std.mem.eql(u8, result.bytes, in_bytes)) return result.errors;
154153

155154
var stdout_writer = std.fs.File.stdout().writer(&.{});
156155
const stdout = &stdout_writer.interface;
157156
if (check) {
158-
any_error.* = true;
159157
try stdout.print("{s}\n", .{full_path});
160-
return;
158+
return result.errors;
161159
}
162160

163161
var af = try base_dir.atomicFile(sub_path, .{ .write_buffer = &.{} });
164162
defer af.deinit();
165163

166-
try af.file_writer.interface.writeAll(out_bytes);
164+
try af.file_writer.interface.writeAll(result.bytes);
167165
try af.finish();
168166
try stdout.print("{s}\n", .{full_path});
167+
return result.errors;
169168
}
170169

170+
const Result = struct {
171+
bytes: []const u8,
172+
errors: bool,
173+
};
174+
171175
pub fn fmtHtml(
172176
arena: std.mem.Allocator,
173177
path: ?[]const u8,
174178
code: [:0]const u8,
175179
strict: bool,
176-
) ![]const u8 {
180+
) !Result {
177181
const ast = try super.html.Ast.init(arena, code, .html, strict);
178182
if (ast.errors.len > 0) {
179183
var ew = std.fs.File.stderr().writer(&.{});
180184
try ast.printErrors(code, path, &ew.interface);
181-
std.process.exit(1);
185+
if (ast.has_syntax_errors) std.process.exit(1);
182186
}
183187

184-
return std.fmt.allocPrint(arena, "{f}", .{ast.formatter(code)});
188+
return .{
189+
.bytes = try std.fmt.allocPrint(arena, "{f}", .{ast.formatter(code)}),
190+
.errors = ast.errors.len > 0,
191+
};
185192
}
186193

187194
fn fmtSuper(
188195
arena: std.mem.Allocator,
189196
path: ?[]const u8,
190197
code: [:0]const u8,
191198
strict: bool,
192-
) ![]const u8 {
199+
) !Result {
193200
const ast = try super.html.Ast.init(arena, code, .superhtml, strict);
194201
if (ast.errors.len > 0) {
195202
var ew = std.fs.File.stderr().writer(&.{});
196203
try ast.printErrors(code, path, &ew.interface);
197-
std.process.exit(1);
198204
}
199205

200-
return std.fmt.allocPrint(arena, "{f}", .{ast.formatter(code)});
206+
return .{
207+
.bytes = try std.fmt.allocPrint(arena, "{f}", .{ast.formatter(code)}),
208+
.errors = ast.errors.len > 0,
209+
};
201210
}
202211

203212
fn oom() noreturn {

src/cli/interface.zig

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ const super = @import("superhtml");
33

44
const FileType = enum { html, super };
55

6-
pub fn run(gpa: std.mem.Allocator, args: []const []const u8) !void {
6+
pub fn run(gpa: std.mem.Allocator, args: []const []const u8) !noreturn {
77
const cmd = Command.parse(args);
88
switch (cmd.mode) {
99
.stdin => {
@@ -41,6 +41,8 @@ pub fn run(gpa: std.mem.Allocator, args: []const []const u8) !void {
4141
try std.fs.File.stdout().writeAll(out_bytes);
4242
},
4343
}
44+
45+
std.process.exit(0);
4446
}
4547

4648
fn printInterfaceFromFile(

src/cli/logging.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ pub fn logFn(
2323
args: anytype,
2424
) void {
2525
switch (scope) {
26-
.root, .super_lsp, .@"html/ast" => {},
26+
.root, .super_lsp, .@"html/ast/fmt" => {},
2727
else => return,
2828
}
2929
// inline for (build_options.enabled_scopes) |es| {

src/cli/lsp.zig

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ const logic = @import("lsp/logic.zig");
1111

1212
const log = std.log.scoped(.super_lsp);
1313

14-
pub fn run(gpa: std.mem.Allocator, args: []const []const u8) !void {
14+
pub fn run(gpa: std.mem.Allocator, args: []const []const u8) !noreturn {
1515
_ = args;
1616

1717
log.debug("SuperHTML LSP started!", .{});
@@ -36,6 +36,8 @@ pub fn run(gpa: std.mem.Allocator, args: []const []const u8) !void {
3636
&handler,
3737
log.err,
3838
);
39+
40+
std.process.exit(0);
3941
}
4042

4143
pub const Handler = @This();

src/html/Ast.zig

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ pub const Node = struct {
145145
next_idx: u32 = 0,
146146

147147
kind: Kind,
148-
self_closing: bool = false, // TODO fold into element tags
148+
self_closing: bool,
149149
model: Element.Model,
150150

151151
pub fn isClosed(n: Node) bool {
@@ -485,6 +485,7 @@ pub fn init(
485485
.categories = .none,
486486
.content = .all,
487487
},
488+
.self_closing = false,
488489
});
489490

490491
var tokenizer: Tokenizer = .{ .language = language };
@@ -509,6 +510,7 @@ pub fn init(
509510
.categories = .none,
510511
.content = .none,
511512
},
513+
.self_closing = false,
512514
};
513515

514516
switch (current.direction()) {
@@ -533,6 +535,7 @@ pub fn init(
533535
.start_self,
534536
=> {
535537
const name = tag.name.slice(src);
538+
const self_closing = tag.kind == .start_self;
536539
var new: Node = node: switch (tag.kind) {
537540
else => unreachable,
538541
.start_self => {
@@ -572,6 +575,7 @@ pub fn init(
572575
.categories = .all,
573576
.content = .all,
574577
},
578+
.self_closing = self_closing,
575579
};
576580
},
577581
.html => {
@@ -598,6 +602,7 @@ pub fn init(
598602
.open = tag.span,
599603
.kind = kind,
600604
.model = model,
605+
.self_closing = self_closing,
601606
};
602607
} else if (std.mem.indexOfScalar(u8, name, '-') == null) {
603608
try errors.append(gpa, .{
@@ -614,6 +619,7 @@ pub fn init(
614619
.categories = .all,
615620
.content = .all,
616621
},
622+
.self_closing = self_closing,
617623
};
618624
},
619625
.xml => break :node .{
@@ -623,6 +629,7 @@ pub fn init(
623629
.categories = .all,
624630
.content = .all,
625631
},
632+
.self_closing = self_closing,
626633
},
627634
},
628635
};
@@ -842,6 +849,7 @@ pub fn init(
842849
},
843850
.content = .none,
844851
},
852+
.self_closing = false,
845853
};
846854

847855
switch (current.direction()) {
@@ -872,6 +880,7 @@ pub fn init(
872880
.categories = .all,
873881
.content = .none,
874882
},
883+
.self_closing = false,
875884
};
876885

877886
log.debug("comment => current ({any})", .{current.*});
@@ -915,6 +924,7 @@ pub fn init(
915924
// finalize tree
916925
while (current.kind != .root) {
917926
if (!current.isClosed()) {
927+
has_syntax_errors = true;
918928
try errors.append(gpa, .{
919929
.tag = .missing_end_tag,
920930
.main_location = current.open,
@@ -1061,7 +1071,8 @@ pub fn render(ast: Ast, src: []const u8, w: *Writer) !void {
10611071
// else
10621072
// std.ascii.isWhitespace(src[current.open.end]);
10631073

1064-
const open_was_vertical = std.ascii.isWhitespace(src[current.open.end]);
1074+
const open_was_vertical = current.open.end < src.len and
1075+
std.ascii.isWhitespace(src[current.open.end]);
10651076
if (open_was_vertical) {
10661077
try w.writeAll("\n");
10671078
for (0..indentation) |_| {
@@ -2065,10 +2076,14 @@ test "fuzz" {
20652076
var in: Reader = .fixed(input);
20662077
var out: Writer.Allocating = .init(ctx.gpa);
20672078
try generator.generate(ctx.gpa, &in, &out.writer);
2068-
std.debug.print("{s}\n\n", .{out.written()});
2079+
std.debug.print("--begin--\n{s}\n\n", .{out.written()});
20692080

20702081
const ast: Ast = try .init(ctx.gpa, out.written(), .html, false);
2071-
_ = ast;
2082+
// _ = ast;
2083+
var devnull: Writer.Discarding = .init(&.{});
2084+
if (!ast.has_syntax_errors) {
2085+
try ast.render(out.written(), &devnull.writer);
2086+
}
20722087
}
20732088
};
20742089

0 commit comments

Comments
 (0)