@@ -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
522562pub 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
561602pub 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}
0 commit comments