improve completion on error and enums (#887)

This commit is contained in:
Techatrix 2023-01-06 18:59:20 +00:00 committed by GitHub
parent b163be51d3
commit 3f2700eaa5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 89 additions and 79 deletions

View File

@ -731,16 +731,14 @@ fn nodeToCompletion(
.container_field_init, .container_field_init,
=> { => {
const field = ast.containerField(tree, node).?; const field = ast.containerField(tree, node).?;
if (!field.ast.tuple_like) {
try list.append(allocator, .{ try list.append(allocator, .{
.label = handle.tree.tokenSlice(field.ast.main_token), .label = handle.tree.tokenSlice(field.ast.main_token),
.kind = .Field, .kind = if (field.ast.tuple_like) .Enum else .Field,
.documentation = doc, .documentation = doc,
.detail = analysis.getContainerFieldSignature(handle.tree, field), .detail = analysis.getContainerFieldSignature(handle.tree, field),
.insertText = tree.tokenSlice(field.ast.main_token), .insertText = tree.tokenSlice(field.ast.main_token),
.insertTextFormat = .PlainText, .insertTextFormat = .PlainText,
}); });
}
}, },
.array_type, .array_type,
.array_type_sentinel, .array_type_sentinel,
@ -919,7 +917,13 @@ fn hoverSymbol(server: *Server, decl_handle: analysis.DeclWithHandle) error{OutO
const end = offsets.tokenToLoc(tree, last_token).end; const end = offsets.tokenToLoc(tree, last_token).end;
break :def tree.source[start..end]; break :def tree.source[start..end];
}, },
.pointer_payload, .array_payload, .array_index, .switch_payload, .label_decl => tree.tokenSlice(decl_handle.nameToken()), .pointer_payload,
.array_payload,
.array_index,
.switch_payload,
.label_decl,
.error_token,
=> tree.tokenSlice(decl_handle.nameToken()),
}; };
var bound_type_params = analysis.BoundTypeParams{}; var bound_type_params = analysis.BoundTypeParams{};
@ -1223,6 +1227,17 @@ fn declToCompletion(context: DeclToCompletionContext, decl_handle: analysis.Decl
.insertTextFormat = .PlainText, .insertTextFormat = .PlainText,
}); });
}, },
.error_token => {
const name = tree.tokenSlice(decl_handle.decl.error_token);
try context.completions.append(allocator, .{
.label = name,
.kind = .Constant,
.detail = try std.fmt.allocPrint(allocator, "error.{s}", .{name}),
.insertText = name,
.insertTextFormat = .PlainText,
});
},
} }
} }

View File

@ -292,9 +292,12 @@ pub fn getDeclNameToken(tree: Ast, node: Ast.Node.Index) ?Ast.TokenIndex {
}, },
// containers // containers
.container_field, .container_field_init, .container_field_align => { .container_field,
.container_field_init,
.container_field_align,
=> {
const field = ast.containerField(tree, node).?.ast; const field = ast.containerField(tree, node).?.ast;
return if (field.tuple_like) null else field.main_token; return field.main_token;
}, },
.identifier => main_token, .identifier => main_token,
@ -1937,6 +1940,8 @@ pub const Declaration = union(enum) {
label: Ast.TokenIndex, label: Ast.TokenIndex,
block: Ast.Node.Index, block: Ast.Node.Index,
}, },
/// always an identifier
error_token: Ast.Node.Index,
}; };
pub const DeclWithHandle = struct { pub const DeclWithHandle = struct {
@ -1953,6 +1958,7 @@ pub const DeclWithHandle = struct {
.array_index => |ai| ai, .array_index => |ai| ai,
.switch_payload => |sp| sp.node, .switch_payload => |sp| sp.node,
.label_decl => |ld| ld.label, .label_decl => |ld| ld.label,
.error_token => |et| et,
}; };
} }
@ -2052,6 +2058,7 @@ pub const DeclWithHandle = struct {
} }
return null; return null;
}, },
.error_token => return null,
}; };
} }
}; };
@ -2395,6 +2402,7 @@ pub const DocumentScope = struct {
} }
self.scopes.deinit(allocator); self.scopes.deinit(allocator);
for (self.error_completions.entries.items(.key)) |item| { for (self.error_completions.entries.items(.key)) |item| {
if (item.detail) |detail| allocator.free(detail);
switch (item.documentation orelse continue) { switch (item.documentation orelse continue) {
.string => |str| allocator.free(str), .string => |str| allocator.free(str),
.MarkupContent => |content| allocator.free(content.value), .MarkupContent => |content| allocator.free(content.value),
@ -2402,6 +2410,7 @@ pub const DocumentScope = struct {
} }
self.error_completions.deinit(allocator); self.error_completions.deinit(allocator);
for (self.enum_completions.entries.items(.key)) |item| { for (self.enum_completions.entries.items(.key)) |item| {
if (item.detail) |detail| allocator.free(detail);
switch (item.documentation orelse continue) { switch (item.documentation orelse continue) {
.string => |str| allocator.free(str), .string => |str| allocator.free(str),
.MarkupContent => |content| allocator.free(content.value), .MarkupContent => |content| allocator.free(content.value),
@ -2475,9 +2484,6 @@ fn makeInnerScope(allocator: std.mem.Allocator, context: ScopeContext, node_idx:
const main_tokens = tree.nodes.items(.main_token); const main_tokens = tree.nodes.items(.main_token);
const node_tag = tags[node_idx]; const node_tag = tags[node_idx];
var buf: [2]Ast.Node.Index = undefined;
const ast_decls = ast.declMembers(tree, node_idx, &buf);
var scope = try scopes.addOne(allocator); var scope = try scopes.addOne(allocator);
scope.* = .{ scope.* = .{
.loc = offsets.nodeToLoc(tree, node_idx), .loc = offsets.nodeToLoc(tree, node_idx),
@ -2490,26 +2496,26 @@ fn makeInnerScope(allocator: std.mem.Allocator, context: ScopeContext, node_idx:
var i = main_tokens[node_idx]; var i = main_tokens[node_idx];
while (i < data[node_idx].rhs) : (i += 1) { while (i < data[node_idx].rhs) : (i += 1) {
if (token_tags[i] == .identifier) { if (token_tags[i] == .identifier) {
try context.errors.put(allocator, .{ const name = offsets.tokenToSlice(tree, i);
.label = tree.tokenSlice(i), if (try scopes.items[scope_idx].decls.fetchPut(allocator, name, .{ .error_token = i })) |_| {
// TODO Record a redefinition error.
}
const gop = try context.errors.getOrPut(allocator, .{
.label = name,
.kind = .Constant, .kind = .Constant,
.insertText = tree.tokenSlice(i), //.detail =
.insertText = name,
.insertTextFormat = .PlainText, .insertTextFormat = .PlainText,
}, {}); });
if (!gop.found_existing) {
gop.key_ptr.detail = try std.fmt.allocPrint(allocator, "error.{s}", .{name});
}
} }
} }
} }
var buffer: [2]Ast.Node.Index = undefined; var buf: [2]Ast.Node.Index = undefined;
const container_decl = ast.containerDecl(tree, node_idx, &buffer); const ast_decls = ast.declMembers(tree, node_idx, &buf);
// Only tagged unions and enums should pass this
const can_have_enum_completions = if (container_decl) |container| blk: {
const kind = token_tags[container.ast.main_token];
break :blk kind != .keyword_struct and
(kind != .keyword_union or container.ast.enum_token != null or container.ast.arg != 0);
} else false;
for (ast_decls) |decl| { for (ast_decls) |decl| {
if (tags[decl] == .@"usingnamespace") { if (tags[decl] == .@"usingnamespace") {
try scopes.items[scope_idx].uses.append(allocator, decl); try scopes.items[scope_idx].uses.append(allocator, decl);
@ -2528,18 +2534,11 @@ fn makeInnerScope(allocator: std.mem.Allocator, context: ScopeContext, node_idx:
// TODO Record a redefinition error. // TODO Record a redefinition error.
} }
if (!can_have_enum_completions) var buffer: [2]Ast.Node.Index = undefined;
continue; const container_decl = ast.containerDecl(tree, node_idx, &buffer) orelse continue;
const container_field = switch (tags[decl]) { if (container_decl.ast.enum_token != null) {
.container_field => tree.containerField(decl), if (std.mem.eql(u8, name, "_")) return;
.container_field_align => tree.containerFieldAlign(decl),
.container_field_init => tree.containerFieldInit(decl),
else => null,
};
if (container_field) |_| {
if (!std.mem.eql(u8, name, "_")) {
const Documentation = @TypeOf(@as(types.CompletionItem, undefined).documentation); const Documentation = @TypeOf(@as(types.CompletionItem, undefined).documentation);
var doc: Documentation = if (try getDocComments(allocator, tree, decl, .markdown)) |docs| .{ .MarkupContent = types.MarkupContent{ .kind = .markdown, .value = docs } } else null; var doc: Documentation = if (try getDocComments(allocator, tree, decl, .markdown)) |docs| .{ .MarkupContent = types.MarkupContent{ .kind = .markdown, .value = docs } } else null;
@ -2556,7 +2555,6 @@ fn makeInnerScope(allocator: std.mem.Allocator, context: ScopeContext, node_idx:
} }
} }
} }
}
// Whether we have already visited the root node. // Whether we have already visited the root node.
var had_root = true; var had_root = true;

View File

@ -534,6 +534,7 @@ pub fn symbolReferences(
log.warn("Could not find param decl's function", .{}); log.warn("Could not find param decl's function", .{});
}, },
.label_decl => unreachable, // handled separately by labelReferences .label_decl => unreachable, // handled separately by labelReferences
.error_token => {},
} }
return builder.locations; return builder.locations;

View File

@ -268,19 +268,16 @@ test "completion - union" {
} }
test "completion - enum" { test "completion - enum" {
// TODO: Fix try testCompletion(
return error.SkipZigTest; \\const E = enum {
// try testCompletion( \\ alpha,
// \\const E = enum { \\ beta,
// \\ alpha, \\};
// \\ beta, \\const foo = E.<cursor>
// \\}; , &.{
// \\const foo = E.<cursor> .{ .label = "alpha", .kind = .Enum },
// , &.{ .{ .label = "beta", .kind = .Enum },
// // TODO kind should be Enum });
// .{ .label = "alpha", .kind = .Field },
// .{ .label = "beta", .kind = .Field },
// });
} }
test "completion - error union" { test "completion - error union" {
@ -291,21 +288,20 @@ test "completion - error union" {
\\}; \\};
\\const baz = error.<cursor> \\const baz = error.<cursor>
, &.{ , &.{
.{ .label = "Foo", .kind = .Constant }, .{ .label = "Foo", .kind = .Constant, .detail = "error.Foo" },
.{ .label = "Bar", .kind = .Constant }, .{ .label = "Bar", .kind = .Constant, .detail = "error.Bar" },
}); });
// TODO implement completion for error unions try testCompletion(
// try testCompletion( \\const E = error {
// \\const E = error { \\ foo,
// \\ foo, \\ bar,
// \\ bar, \\};
// \\}; \\const baz = E.<cursor>
// \\const baz = E.<cursor> , &.{
// , &.{ .{ .label = "foo", .kind = .Constant, .detail = "error.foo" },
// .{ .label = "foo", .kind = .Constant }, .{ .label = "bar", .kind = .Constant, .detail = "error.bar" },
// .{ .label = "bar", .kind = .Constant }, });
// });
try testCompletion( try testCompletion(
\\const S = struct { alpha: u32 }; \\const S = struct { alpha: u32 };