Skip to content

Commit 459e614

Browse files
committed
introduce attribute and nesting validation + lsp features
This commit introduces an entirely new system that validates attributes and element nesting, alongside all the major features expected by a language server. Note that all new validation is not compatible with templating languages, support for that will be explored in the near future, but for now this is strictly for vanilla html (validation is disabled entirely for SuperHTML templates at the moment as well). All of this code is considered experimental so if you build superhtml from this commit, be warned that you will probably encounter bugs, but beta testing is appreciated at this stage. If you want to report a bug, please take a good read at the Issue templates, as I'm asking submitters to provide a reference to the HTML spec section that the bug pertains to, in order to minimize the amount of bad issues that complain about correct -- but maybe lesser known -- errors. On the front of the language server, we now provide: - diagnostics for all kinds of errors - autocomplete for element names, attribute names, and attribute values - symbol rename on element names to change both tags at once - linked edits to achieve the same as above (when supported by the editor, see #74) - duplicate class name warnings - find all references for class names - descriptions for all elements, attributes and attribute values of enumerated attributes (i.e. attributes whose values are options in a list). The autoformatter uses now a new formatting layout where the first attribute is kept on the same line as the element name. Additionally, the autoformatter now uses tabs for indentation and spaces for alignment. This is also experimental and might be reverted in the future.
1 parent 7debd59 commit 459e614

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

132 files changed

+20787
-784
lines changed

.github/ISSUE_TEMPLATE/config.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
contact_links:
2+
- name: WHATWG Living HTML Specification
3+
about: "If you are reporting a problem relative to HTML diagnostics you will need to provide a referece to the WHATWG Living HTML specification that points out the discrepancy".
4+
url: https://html.spec.whatwg.org/multipage/

.github/ISSUE_TEMPLATE/crash.yml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
name: Crash / Hang Report
2+
description: Report SuperHTML crashing or hanging.
3+
labels: ["crash/hang"]
4+
body:
5+
- type: input
6+
id: version
7+
attributes:
8+
label: SuperHTML Version
9+
description: "The output of `superhtml version` (or the VSCode extension version)"
10+
placeholder: "v0.5.3-dev.59+0336596"
11+
validations:
12+
required: true
13+
- type: input
14+
id: platform
15+
attributes:
16+
label: OS and Editor (if any)
17+
description: "Which OS and which editor (if reporting a LSP crash/hang) are you using?"
18+
placeholder: "Linux, helix"
19+
validations:
20+
required: true
21+
- type: markdown
22+
id: repro
23+
attributes:
24+
label: Steps to Reproduce and Observed Behavior
25+
description: What exactly can someone else do, in order to observe the problem that you observed? Include error messages, if any.
26+
validations:
27+
required: true
28+
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
name: Missing or Wrong HTML diagnostic
2+
description: Report an error with how SuperHTML validates HTML.
3+
labels: ["diagnostic"]
4+
body:
5+
- type: input
6+
id: version
7+
attributes:
8+
label: SuperHTML Version
9+
description: "The output of `superhtml version` (or the VSCode extension version)"
10+
placeholder: "v0.5.3-dev.59+0336596"
11+
validations:
12+
required: true
13+
- type: markdown
14+
id: repro
15+
attributes:
16+
label: Steps to Reproduce and Observed Behavior
17+
description: What exactly can someone else do, in order to observe the problem that you observed? Include error messages, if any.
18+
validations:
19+
required: true
20+
- type: markdown
21+
id: expected
22+
attributes:
23+
label: Expected Output according to the HTML spec
24+
description: "NOTE: failing to provide a quote from the WHATWG HTML living specification that shows the discrepancy might cause your issue to be closed without any explanation."
25+
validations:
26+
required: true

build.zig

Lines changed: 0 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -64,14 +64,6 @@ pub fn build(b: *std.Build) !void {
6464
if (version == .tag) {
6565
setupReleaseStep(b, options, superhtml, folders, lsp);
6666
}
67-
68-
if (b.option(
69-
bool,
70-
"fuzz",
71-
"Generate an executable for AFL++ (persistent mode) plus extra tooling",
72-
) orelse false) {
73-
setupFuzzStep(b, target, superhtml);
74-
}
7567
}
7668

7769
fn setupCheckStep(
@@ -137,61 +129,6 @@ fn setupTestStep(
137129
test_step.dependOn(&run_fuzz_tests.step);
138130
}
139131

140-
fn setupFuzzStep(
141-
b: *std.Build,
142-
target: std.Build.ResolvedTarget,
143-
superhtml: *std.Build.Module,
144-
) void {
145-
const afl = b.lazyImport(@This(), "afl_kit") orelse return;
146-
const afl_obj = b.addObject(.{
147-
.name = "superfuzz-afl",
148-
.root_module = b.createModule(.{
149-
.root_source_file = b.path("src/fuzz/afl.zig"),
150-
.target = target,
151-
.optimize = .ReleaseSafe,
152-
}),
153-
});
154-
155-
afl_obj.root_module.addImport("superhtml", superhtml);
156-
afl_obj.root_module.stack_check = false; // not linking with compiler-rt
157-
afl_obj.root_module.link_libc = true; // afl runtime depends on libc
158-
159-
const afl_fuzz = afl.addInstrumentedExe(
160-
b,
161-
target,
162-
.ReleaseSafe,
163-
null,
164-
false,
165-
afl_obj,
166-
) orelse return;
167-
b.getInstallStep().dependOn(&b.addInstallFile(afl_fuzz, "superfuzz-afl").step);
168-
// b.installArtifact(afl_fuzz);
169-
170-
const super_fuzz = b.addExecutable(.{
171-
.name = "superfuzz",
172-
.root_module = b.createModule(.{
173-
.root_source_file = b.path("src/fuzz.zig"),
174-
.target = target,
175-
.optimize = .ReleaseSafe,
176-
}),
177-
});
178-
179-
super_fuzz.root_module.addImport("superhtml", superhtml);
180-
b.installArtifact(super_fuzz);
181-
182-
const supergen = b.addExecutable(.{
183-
.name = "supergen",
184-
.root_module = b.createModule(.{
185-
.root_source_file = b.path("src/fuzz/astgen.zig"),
186-
.target = target,
187-
.optimize = .Debug,
188-
}),
189-
});
190-
191-
supergen.root_module.addImport("superhtml", superhtml);
192-
b.installArtifact(supergen);
193-
}
194-
195132
fn setupCliTool(
196133
b: *std.Build,
197134
target: std.Build.ResolvedTarget,

build.zig.zon

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,8 @@
22
.name = .superhtml,
33
.version = "0.4.0",
44
.fingerprint = 0xc5e9aede3c1db363,
5-
.minimum_zig_version = "0.15.0",
5+
.minimum_zig_version = "0.15.1",
66
.dependencies = .{
7-
.afl_kit = .{
8-
.url = "git+https://github.com/kristoff-it/zig-afl-kit#8ef04d1db48650345dca68da1e1b8f2615125c40",
9-
.hash = "afl_kit-0.1.0-NdJ3cvscAACLEvjZTB017IAks_Uq5ux1qpA-klDe384Y",
10-
.lazy = true,
11-
},
127
.known_folders = .{
138
.url = "git+https://github.com/ziglibs/known-folders#ab5cf5feb936fa3b72c95d3ad0c0c67791937ba1",
149
.hash = "known_folders-0.0.0-Fy-PJtTTAADUOhGKM0sxzG4eMkNQxRvx9e5dfHVyaeA3",

editors/vscode/.vscode/test.html

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<!DOCTYPE html>
2+
3+
<html>
4+
<title></title>
5+
<div />
6+
<p>
7+
8+
foo
9+
</p>
10+
<foo></foo>
11+
</div>
12+
</span>
13+
14+
</html>

editors/vscode/src/extension.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import {
33
startServer
44
} from '@vscode/wasm-wasi-lsp';
55
import { ProcessOptions, Stdio, Wasm } from '@vscode/wasm-wasi/v1';
6-
import { ExtensionContext, Uri, window, workspace } from 'vscode';
6+
import { ConfigurationTarget, ExtensionContext, Uri, window, workspace } from 'vscode';
77
import {
88
LanguageClient,
99
LanguageClientOptions,
@@ -12,6 +12,9 @@ import {
1212

1313
let client: LanguageClient;
1414
export async function activate(context: ExtensionContext) {
15+
await workspace.getConfiguration()
16+
.update('html.suggest.html5', false, ConfigurationTarget.Global);
17+
1518
const wasm: Wasm = await Wasm.load();
1619

1720
const channel = window.createOutputChannel('SuperHTML Language Server');

src/Ast.zig

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -281,13 +281,7 @@ pub fn init(
281281
const html_node_idx = cur.idx;
282282
const depth = cur.depth;
283283

284-
switch (html_node.kind) {
285-
.element,
286-
.element_void,
287-
.element_self_closing,
288-
=> {},
289-
else => continue,
290-
}
284+
if (!html_node.kind.isElement()) continue;
291285

292286
defer seen_non_comment_elems = true;
293287

src/cli.zig

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,27 +30,32 @@ pub fn panic(
3030
ret_addr: ?usize,
3131
) noreturn {
3232
if (lsp_mode) {
33-
std.log.err("{s}\n\n{?f}", .{ msg, trace });
33+
std.log.err("\n{s}\n\n{?f}", .{ msg, trace });
3434
} else {
35-
std.debug.print("{s}\n\n{?f}", .{ msg, trace });
35+
std.debug.print("\n{s}\n\n{?f}", .{ msg, trace });
3636
}
3737
blk: {
3838
const out: std.fs.File = if (!lsp_mode) std.fs.File.stderr() else logging.log_file orelse break :blk;
39-
var writer = out.writer(&.{});
39+
var writer = out.writerStreaming(&.{});
4040
const w = &writer.interface;
41+
w.print("\n{s}\n\n{?f}", .{ msg, trace }) catch {};
4142
if (builtin.strip_debug_info) {
42-
w.print("Unable to dump stack trace: debug info stripped\n", .{}) catch return;
43+
w.print("Unable to dump stack trace: debug info stripped\n", .{}) catch {};
4344
break :blk;
4445
}
4546
const debug_info = std.debug.getSelfDebugInfo() catch |err| {
46-
w.print("Unable to dump stack trace: Unable to open debug info: {s}\n", .{@errorName(err)}) catch break :blk;
47+
w.print(
48+
"Unable to dump stack trace: Unable to open debug info: {s}\n",
49+
.{@errorName(err)},
50+
) catch {};
4751
break :blk;
4852
};
4953
std.debug.writeCurrentStackTrace(w, debug_info, .no_color, ret_addr) catch |err| {
50-
w.print("Unable to dump stack trace: {t}\n", .{err}) catch break :blk;
54+
w.print("Unable to dump stack trace: {t}\n", .{err}) catch {};
5155
break :blk;
5256
};
5357
}
58+
5459
if (builtin.mode == .Debug) @breakpoint();
5560
std.process.exit(1);
5661
}

src/cli/logging.zig

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,15 @@ pub fn logFn(
2222
comptime format: []const u8,
2323
args: anytype,
2424
) void {
25-
if (build_options.enabled_scopes.len > 0) {
26-
inline for (build_options.enabled_scopes) |es| {
27-
if (comptime std.mem.eql(u8, es, @tagName(scope))) {
28-
break;
29-
}
30-
} else return;
31-
}
25+
// switch (scope) {
26+
// .root, .super_lsp, .@"html/ast" => {},
27+
// else => return,
28+
// }
29+
inline for (build_options.enabled_scopes) |es| {
30+
if (comptime std.mem.eql(u8, es, @tagName(scope))) {
31+
break;
32+
}
33+
} else return;
3234

3335
const l = log_file orelse return;
3436
const scope_prefix = "(" ++ @tagName(scope) ++ "): ";

0 commit comments

Comments
 (0)