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,
|
.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,
|
||||||
|
});
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
@ -2555,7 +2554,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.
|
||||||
|
@ -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;
|
||||||
|
@ -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 };
|
||||||
|
Loading…
Reference in New Issue
Block a user