improve completion on error and enums (#887)
This commit is contained in:
parent
b163be51d3
commit
3f2700eaa5
@ -731,16 +731,14 @@ fn nodeToCompletion(
|
||||
.container_field_init,
|
||||
=> {
|
||||
const field = ast.containerField(tree, node).?;
|
||||
if (!field.ast.tuple_like) {
|
||||
try list.append(allocator, .{
|
||||
.label = handle.tree.tokenSlice(field.ast.main_token),
|
||||
.kind = .Field,
|
||||
.kind = if (field.ast.tuple_like) .Enum else .Field,
|
||||
.documentation = doc,
|
||||
.detail = analysis.getContainerFieldSignature(handle.tree, field),
|
||||
.insertText = tree.tokenSlice(field.ast.main_token),
|
||||
.insertTextFormat = .PlainText,
|
||||
});
|
||||
}
|
||||
},
|
||||
.array_type,
|
||||
.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;
|
||||
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{};
|
||||
@ -1223,6 +1227,17 @@ fn declToCompletion(context: DeclToCompletionContext, decl_handle: analysis.Decl
|
||||
.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,
|
||||
});
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -292,9 +292,12 @@ pub fn getDeclNameToken(tree: Ast, node: Ast.Node.Index) ?Ast.TokenIndex {
|
||||
},
|
||||
|
||||
// containers
|
||||
.container_field, .container_field_init, .container_field_align => {
|
||||
.container_field,
|
||||
.container_field_init,
|
||||
.container_field_align,
|
||||
=> {
|
||||
const field = ast.containerField(tree, node).?.ast;
|
||||
return if (field.tuple_like) null else field.main_token;
|
||||
return field.main_token;
|
||||
},
|
||||
|
||||
.identifier => main_token,
|
||||
@ -1937,6 +1940,8 @@ pub const Declaration = union(enum) {
|
||||
label: Ast.TokenIndex,
|
||||
block: Ast.Node.Index,
|
||||
},
|
||||
/// always an identifier
|
||||
error_token: Ast.Node.Index,
|
||||
};
|
||||
|
||||
pub const DeclWithHandle = struct {
|
||||
@ -1953,6 +1958,7 @@ pub const DeclWithHandle = struct {
|
||||
.array_index => |ai| ai,
|
||||
.switch_payload => |sp| sp.node,
|
||||
.label_decl => |ld| ld.label,
|
||||
.error_token => |et| et,
|
||||
};
|
||||
}
|
||||
|
||||
@ -2052,6 +2058,7 @@ pub const DeclWithHandle = struct {
|
||||
}
|
||||
return null;
|
||||
},
|
||||
.error_token => return null,
|
||||
};
|
||||
}
|
||||
};
|
||||
@ -2395,6 +2402,7 @@ pub const DocumentScope = struct {
|
||||
}
|
||||
self.scopes.deinit(allocator);
|
||||
for (self.error_completions.entries.items(.key)) |item| {
|
||||
if (item.detail) |detail| allocator.free(detail);
|
||||
switch (item.documentation orelse continue) {
|
||||
.string => |str| allocator.free(str),
|
||||
.MarkupContent => |content| allocator.free(content.value),
|
||||
@ -2402,6 +2410,7 @@ pub const DocumentScope = struct {
|
||||
}
|
||||
self.error_completions.deinit(allocator);
|
||||
for (self.enum_completions.entries.items(.key)) |item| {
|
||||
if (item.detail) |detail| allocator.free(detail);
|
||||
switch (item.documentation orelse continue) {
|
||||
.string => |str| allocator.free(str),
|
||||
.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 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);
|
||||
scope.* = .{
|
||||
.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];
|
||||
while (i < data[node_idx].rhs) : (i += 1) {
|
||||
if (token_tags[i] == .identifier) {
|
||||
try context.errors.put(allocator, .{
|
||||
.label = tree.tokenSlice(i),
|
||||
const name = offsets.tokenToSlice(tree, 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,
|
||||
.insertText = tree.tokenSlice(i),
|
||||
//.detail =
|
||||
.insertText = name,
|
||||
.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;
|
||||
const container_decl = ast.containerDecl(tree, node_idx, &buffer);
|
||||
|
||||
// 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;
|
||||
|
||||
var buf: [2]Ast.Node.Index = undefined;
|
||||
const ast_decls = ast.declMembers(tree, node_idx, &buf);
|
||||
for (ast_decls) |decl| {
|
||||
if (tags[decl] == .@"usingnamespace") {
|
||||
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.
|
||||
}
|
||||
|
||||
if (!can_have_enum_completions)
|
||||
continue;
|
||||
var buffer: [2]Ast.Node.Index = undefined;
|
||||
const container_decl = ast.containerDecl(tree, node_idx, &buffer) orelse continue;
|
||||
|
||||
const container_field = switch (tags[decl]) {
|
||||
.container_field => tree.containerField(decl),
|
||||
.container_field_align => tree.containerFieldAlign(decl),
|
||||
.container_field_init => tree.containerFieldInit(decl),
|
||||
else => null,
|
||||
};
|
||||
|
||||
if (container_field) |_| {
|
||||
if (!std.mem.eql(u8, name, "_")) {
|
||||
if (container_decl.ast.enum_token != null) {
|
||||
if (std.mem.eql(u8, name, "_")) return;
|
||||
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;
|
||||
@ -2555,7 +2554,6 @@ fn makeInnerScope(allocator: std.mem.Allocator, context: ScopeContext, node_idx:
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Whether we have already visited the root node.
|
||||
|
@ -534,6 +534,7 @@ pub fn symbolReferences(
|
||||
log.warn("Could not find param decl's function", .{});
|
||||
},
|
||||
.label_decl => unreachable, // handled separately by labelReferences
|
||||
.error_token => {},
|
||||
}
|
||||
|
||||
return builder.locations;
|
||||
|
@ -268,19 +268,16 @@ test "completion - union" {
|
||||
}
|
||||
|
||||
test "completion - enum" {
|
||||
// TODO: Fix
|
||||
return error.SkipZigTest;
|
||||
// try testCompletion(
|
||||
// \\const E = enum {
|
||||
// \\ alpha,
|
||||
// \\ beta,
|
||||
// \\};
|
||||
// \\const foo = E.<cursor>
|
||||
// , &.{
|
||||
// // TODO kind should be Enum
|
||||
// .{ .label = "alpha", .kind = .Field },
|
||||
// .{ .label = "beta", .kind = .Field },
|
||||
// });
|
||||
try testCompletion(
|
||||
\\const E = enum {
|
||||
\\ alpha,
|
||||
\\ beta,
|
||||
\\};
|
||||
\\const foo = E.<cursor>
|
||||
, &.{
|
||||
.{ .label = "alpha", .kind = .Enum },
|
||||
.{ .label = "beta", .kind = .Enum },
|
||||
});
|
||||
}
|
||||
|
||||
test "completion - error union" {
|
||||
@ -291,21 +288,20 @@ test "completion - error union" {
|
||||
\\};
|
||||
\\const baz = error.<cursor>
|
||||
, &.{
|
||||
.{ .label = "Foo", .kind = .Constant },
|
||||
.{ .label = "Bar", .kind = .Constant },
|
||||
.{ .label = "Foo", .kind = .Constant, .detail = "error.Foo" },
|
||||
.{ .label = "Bar", .kind = .Constant, .detail = "error.Bar" },
|
||||
});
|
||||
|
||||
// TODO implement completion for error unions
|
||||
// try testCompletion(
|
||||
// \\const E = error {
|
||||
// \\ foo,
|
||||
// \\ bar,
|
||||
// \\};
|
||||
// \\const baz = E.<cursor>
|
||||
// , &.{
|
||||
// .{ .label = "foo", .kind = .Constant },
|
||||
// .{ .label = "bar", .kind = .Constant },
|
||||
// });
|
||||
try testCompletion(
|
||||
\\const E = error {
|
||||
\\ foo,
|
||||
\\ bar,
|
||||
\\};
|
||||
\\const baz = E.<cursor>
|
||||
, &.{
|
||||
.{ .label = "foo", .kind = .Constant, .detail = "error.foo" },
|
||||
.{ .label = "bar", .kind = .Constant, .detail = "error.bar" },
|
||||
});
|
||||
|
||||
try testCompletion(
|
||||
\\const S = struct { alpha: u32 };
|
||||
|
Loading…
Reference in New Issue
Block a user