Skip to content

Commit bdc30e9

Browse files
committed
wip
1 parent 8cb16ba commit bdc30e9

Some content is hidden

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

41 files changed

+7602
-380
lines changed

editors/vscode/.vscode/test.html

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<!DOCTYPE html>
2+
3+
<html>
4+
<title>
5+
<< /title>
6+
7+
<head>
8+
</head>
9+
10+
<body id id>
11+
<p>
12+
<< /p>
13+
</body>
14+
15+
16+
</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: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ pub fn panic(
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;
4141
if (builtin.strip_debug_info) {
4242
w.print("Unable to dump stack trace: debug info stripped\n", .{}) catch return;
@@ -51,6 +51,7 @@ pub fn panic(
5151
break :blk;
5252
};
5353
}
54+
5455
if (builtin.mode == .Debug) @breakpoint();
5556
std.process.exit(1);
5657
}

src/cli/logging.zig

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,12 @@ 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+
// if (scope != .srcset) return;
26+
inline for (build_options.enabled_scopes) |es| {
27+
if (comptime std.mem.eql(u8, es, @tagName(scope))) {
28+
break;
29+
}
30+
} else return;
3231

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

src/cli/lsp.zig

Lines changed: 76 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -122,9 +122,15 @@ pub fn initialize(
122122
.referencesProvider = .{ .bool = true },
123123

124124
.completionProvider = .{
125-
.triggerCharacters = &.{ "<", "/" },
125+
.triggerCharacters = &.{
126+
"<", "/", " ",
127+
"\n", "'", "\"",
128+
"=",
129+
},
126130
},
127131

132+
.hoverProvider = .{ .bool = true },
133+
128134
.documentFormattingProvider = .{ .bool = true },
129135
};
130136

@@ -271,7 +277,7 @@ pub fn @"textDocument/codeAction"(
271277
if (!self.strict) return null;
272278

273279
for (doc.html.errors) |err| {
274-
if (err.tag != .ast or err.tag.ast != .invalid_html_tag_name) continue;
280+
if (err.tag != .invalid_html_tag_name) continue;
275281

276282
const span = err.main_location;
277283
if (span.start <= offset and span.end > offset) {
@@ -283,7 +289,7 @@ pub fn @"textDocument/codeAction"(
283289

284290
const edits_len: usize = if (err.node_idx != 0) blk: {
285291
const node = doc.html.nodes[err.node_idx];
286-
if (node.kind != .element) break :blk 1;
292+
if (node.kind.isVoid() or node.self_closing) break :blk 1;
287293

288294
const close = node.close;
289295
if (close.end < 2 or close.start > close.end - 2) break :blk 1;
@@ -339,7 +345,7 @@ pub fn @"textDocument/prepareRename"(
339345
self.offset_encoding,
340346
);
341347

342-
const node_idx = findNode(doc, @intCast(offset));
348+
const node_idx = doc.html.findNodeTagsIdx(@intCast(offset));
343349
if (node_idx == 0) return null;
344350

345351
const node = doc.html.nodes[node_idx];
@@ -434,7 +440,7 @@ pub fn @"textDocument/references"(
434440
self.offset_encoding,
435441
);
436442

437-
const node_idx = findNode(doc, @intCast(offset));
443+
const node_idx = doc.html.findNodeTagsIdx(@intCast(offset));
438444
log.debug("------ References request! (node: {}) ------", .{node_idx});
439445
if (node_idx == 0) return null;
440446

@@ -466,10 +472,7 @@ pub fn @"textDocument/references"(
466472

467473
var locations: std.ArrayListUnmanaged(lsp.types.Location) = .empty;
468474
for (doc.html.nodes) |n| {
469-
switch (n.kind) {
470-
.element, .element_void, .element_self_closing => {},
471-
else => continue,
472-
}
475+
if (!n.kind.isElement()) continue;
473476

474477
var it = n.startTagIterator(doc.src, doc.language);
475478
outer: while (it.next(doc.src)) |attr| {
@@ -511,12 +514,49 @@ pub fn @"textDocument/completion"(
511514
self.offset_encoding,
512515
);
513516

514-
_ = offset;
517+
log.debug("===== lsp autocomplete!", .{});
518+
519+
const completions = try doc.html.completions(arena, doc.src, @intCast(offset));
520+
const items = try arena.alloc(lsp.types.CompletionItem, completions.len);
521+
for (items, completions) |*it, cpl| {
522+
it.* = .{
523+
.label = cpl.label,
524+
.documentation = if (cpl.desc.len == 0) null else .{
525+
.MarkupContent = .{
526+
.kind = .markdown,
527+
.value = cpl.desc,
528+
},
529+
},
530+
.commitCharacters = &.{" >"},
531+
};
532+
}
533+
534+
return .{ .array_of_CompletionItem = items };
535+
}
536+
537+
pub fn @"textDocument/hover"(
538+
self: *Handler,
539+
arena: std.mem.Allocator,
540+
request: types.HoverParams,
541+
) error{OutOfMemory}!lsp.ResultType("textDocument/hover") {
515542
_ = arena;
516-
return null;
517-
// const completions = doc.html.completions(arena, @intCast(offset));
518543

519-
// _ = completions;
544+
const doc = self.files.getPtr(request.textDocument.uri) orelse return null;
545+
const offset = lsp.offsets.positionToIndex(
546+
doc.src,
547+
request.position,
548+
self.offset_encoding,
549+
);
550+
551+
const desc = doc.html.description(doc.src, @intCast(offset)) orelse return null;
552+
return .{
553+
.contents = .{
554+
.MarkupContent = .{
555+
.kind = .markdown,
556+
.value = desc,
557+
},
558+
},
559+
};
520560
}
521561

522562
pub fn onResponse(
@@ -558,6 +598,7 @@ pub fn findNode(doc: *const Document, offset: u32) u32 {
558598
return cur_idx;
559599
}
560600

601+
// TODO this should not allocate
561602
pub fn tagRanges(
562603
self: *Handler,
563604
arena: std.mem.Allocator,
@@ -575,7 +616,7 @@ pub fn tagRanges(
575616
// has a node associated that happens to match our offset.
576617
const span = err.main_location;
577618
if (span.start <= offset and span.end > offset) {
578-
if (err.tag == .ast and err.tag.ast == .erroneous_end_tag) {
619+
if (err.tag == .erroneous_end_tag) {
579620
const ranges = try arena.alloc(types.Range, 1);
580621
ranges[0] = getRange(span, doc.src);
581622
return ranges;
@@ -585,31 +626,29 @@ pub fn tagRanges(
585626
} else findNode(doc, @intCast(offset));
586627

587628
const node = doc.html.nodes[node_idx];
588-
return blk: switch (node.kind) {
589-
else => return null,
590-
.element => {
591-
const ranges = try arena.alloc(types.Range, 2);
592629

593-
const it = node.startTagIterator(doc.src, doc.language);
594-
ranges[0] = getRange(it.name_span, doc.src);
630+
assert(node.kind.isElement());
631+
if (node.kind.isVoid() or node.self_closing) {
632+
const ranges = try arena.alloc(lsp.types.Range, 1);
595633

596-
const close = node.close;
597-
if (close.end < 2 or close.start > close.end - 2) {
598-
break :blk ranges[0..1];
599-
}
634+
const it = node.startTagIterator(doc.src, doc.language);
635+
ranges[0] = getRange(it.name_span, doc.src);
636+
return ranges;
637+
}
600638

601-
ranges[1] = getRange(.{
602-
.start = @intCast(close.start + "</".len),
603-
.end = close.end - 1,
604-
}, doc.src);
605-
break :blk ranges;
606-
},
607-
.element_void, .element_self_closing => {
608-
const ranges = try arena.alloc(lsp.types.Range, 1);
639+
const ranges = try arena.alloc(types.Range, 2);
609640

610-
const it = node.startTagIterator(doc.src, doc.language);
611-
ranges[0] = getRange(it.name_span, doc.src);
612-
break :blk ranges;
613-
},
614-
};
641+
const it = node.startTagIterator(doc.src, doc.language);
642+
ranges[0] = getRange(it.name_span, doc.src);
643+
644+
const close = node.close;
645+
if (close.end < 2 or close.start > close.end - 2) {
646+
return ranges[0..1];
647+
}
648+
649+
ranges[1] = getRange(.{
650+
.start = @intCast(close.start + "</".len),
651+
.end = close.end - 1,
652+
}, doc.src);
653+
return ranges;
615654
}

src/cli/lsp/logic.zig

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,47 @@ pub fn loadFile(
4949
d.* = .{
5050
.range = range,
5151
.severity = .Error,
52-
.message = switch (err.tag) {
53-
.token => |t| @tagName(t),
54-
.ast => |t| @tagName(t),
52+
.message = try std.fmt.allocPrint(arena, "{f}", .{err.tag.fmt(doc.src)}),
53+
.code = .{ .string = @tagName(err.tag) },
54+
.source = if (err.tag == .token) "html tokenizer" else "html parser",
55+
.relatedInformation = switch (err.tag) {
56+
else => null,
57+
.duplicate_attribute_name => |span| try arena.dupe(
58+
lsp.types.DiagnosticRelatedInformation,
59+
&.{
60+
.{
61+
.location = .{ .uri = uri, .range = getRange(
62+
span,
63+
doc.src,
64+
) },
65+
.message = "original",
66+
},
67+
},
68+
),
69+
.duplicate_child => |dc| try arena.dupe(
70+
lsp.types.DiagnosticRelatedInformation,
71+
&.{
72+
.{
73+
.location = .{ .uri = uri, .range = getRange(
74+
dc.span,
75+
doc.src,
76+
) },
77+
.message = "original",
78+
},
79+
},
80+
),
81+
.invalid_nesting => |in| try arena.dupe(
82+
lsp.types.DiagnosticRelatedInformation,
83+
&.{
84+
.{
85+
.location = .{ .uri = uri, .range = getRange(
86+
in.span,
87+
doc.src,
88+
) },
89+
.message = in.reason,
90+
},
91+
},
92+
),
5593
},
5694
};
5795
}

0 commit comments

Comments
 (0)