Struct init fields completion.
This commit is contained in:
parent
3c165eabcd
commit
9723a92508
@ -728,12 +728,150 @@ fn kindToSortScore(kind: types.CompletionItemKind) ?[]const u8 {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn completeDot(server: *Server, handle: *const DocumentStore.Handle) error{OutOfMemory}![]types.CompletionItem {
|
/// Given a decl that is an ast_node, tag .simple_var_decl, and it's rhs is a container adds the container fields to completions
|
||||||
|
pub fn addStructInitNodeFields(server: *Server, decl: Analyser.DeclWithHandle, completions: *std.ArrayListUnmanaged(types.CompletionItem)) error{OutOfMemory}!void {
|
||||||
|
const node = switch (decl.decl.*) {
|
||||||
|
.ast_node => |ast_node| ast_node,
|
||||||
|
else => return,
|
||||||
|
};
|
||||||
|
const node_tags = decl.handle.tree.nodes.items(.tag);
|
||||||
|
if (node_tags[node] != .simple_var_decl) return;
|
||||||
|
const node_data = decl.handle.tree.nodes.items(.data)[node];
|
||||||
|
if (node_data.rhs != 0) {
|
||||||
|
var buffer: [2]Ast.Node.Index = undefined;
|
||||||
|
const container_decl = Ast.fullContainerDecl(decl.handle.tree, &buffer, node_data.rhs) orelse return;
|
||||||
|
for (container_decl.ast.members) |member| {
|
||||||
|
const field = decl.handle.tree.fullContainerField(member) orelse continue;
|
||||||
|
try completions.append(server.arena.allocator(), .{
|
||||||
|
.label = decl.handle.tree.tokenSlice(field.ast.main_token),
|
||||||
|
.kind = if (field.ast.tuple_like) .Enum else .Field,
|
||||||
|
.detail = Analyser.getContainerFieldSignature(decl.handle.tree, field),
|
||||||
|
.insertText = decl.handle.tree.tokenSlice(field.ast.main_token),
|
||||||
|
.insertTextFormat = .PlainText,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn completeDot(server: *Server, handle: *const DocumentStore.Handle, source_index: usize) error{OutOfMemory}![]types.CompletionItem {
|
||||||
const tracy_zone = tracy.trace(@src());
|
const tracy_zone = tracy.trace(@src());
|
||||||
defer tracy_zone.end();
|
defer tracy_zone.end();
|
||||||
|
|
||||||
var completions = try server.document_store.enumCompletionItems(server.arena.allocator(), handle.*);
|
const allocator = server.arena.allocator();
|
||||||
|
|
||||||
|
struct_init: {
|
||||||
|
const tree = handle.tree;
|
||||||
|
const tokens_start = tree.tokens.items(.start);
|
||||||
|
|
||||||
|
var upper_index = tokens_start.len - 1;
|
||||||
|
const mid = upper_index / 2;
|
||||||
|
const mid_tok_start = tokens_start[mid];
|
||||||
|
if (mid_tok_start < source_index) {
|
||||||
|
// std.log.debug("source_index is in upper half", .{});
|
||||||
|
const quart_index = mid + (mid / 2);
|
||||||
|
const quart_tok_start = tokens_start[quart_index];
|
||||||
|
if (quart_tok_start < source_index) {
|
||||||
|
// std.log.debug("source_index is in upper fourth", .{});
|
||||||
|
} else {
|
||||||
|
upper_index = quart_index;
|
||||||
|
// std.log.debug("source_index is in upper third", .{});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// std.log.debug("source_index is in lower half", .{});
|
||||||
|
const quart_index = mid / 2;
|
||||||
|
const quart_tok_start = tokens_start[quart_index];
|
||||||
|
if (quart_tok_start < source_index) {
|
||||||
|
// std.log.debug("source_index is in second quarth", .{});
|
||||||
|
upper_index = mid;
|
||||||
|
} else {
|
||||||
|
// std.log.debug("source_index is in first quarth", .{});
|
||||||
|
upper_index = quart_index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// iterate until we find current token loc (should be a .period)
|
||||||
|
while (upper_index > 1) : (upper_index -= 1) {
|
||||||
|
if (tokens_start[upper_index] > source_index) continue;
|
||||||
|
upper_index -= 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const token_tags = tree.tokens.items(.tag);
|
||||||
|
|
||||||
|
// look for an .l_brace (but don't extend past a .semicolon or .r_brace)
|
||||||
|
while (upper_index != 0 and token_tags[upper_index] != .l_brace) {
|
||||||
|
if (token_tags[upper_index] == .semicolon or token_tags[upper_index] == .r_brace) break :struct_init;
|
||||||
|
upper_index -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// the .l_brace should be preceded by an .identifier
|
||||||
|
if (upper_index == 0 or token_tags[upper_index - 1] != .identifier) {
|
||||||
|
break :struct_init;
|
||||||
|
}
|
||||||
|
|
||||||
|
upper_index -= 1; // identifier's index
|
||||||
|
var identifier_loc = offsets.tokenIndexToLoc(tree.source, tokens_start[upper_index]);
|
||||||
|
|
||||||
|
// if this is done as a field access collect all the identifiers, eg `path.to.MyStruct`
|
||||||
|
var identifier_original_start = identifier_loc.start;
|
||||||
|
while ((token_tags[upper_index] == .period or token_tags[upper_index] == .identifier) and upper_index != 0) : (upper_index -= 1) {
|
||||||
|
identifier_loc.start = tokens_start[upper_index];
|
||||||
|
}
|
||||||
|
|
||||||
|
var completions = std.ArrayListUnmanaged(types.CompletionItem){};
|
||||||
|
|
||||||
|
if (identifier_loc.start != identifier_original_start) { // field access
|
||||||
|
const possible_decls = (try server.getSymbolFieldAccesses(handle, identifier_loc.end, identifier_loc));
|
||||||
|
if (possible_decls) |decls| {
|
||||||
|
for (decls) |decl| {
|
||||||
|
switch (decl.decl.*) {
|
||||||
|
.ast_node => |node| {
|
||||||
|
if (try server.analyser.resolveVarDeclAlias(.{ .node = node, .handle = decl.handle })) |result| {
|
||||||
|
try addStructInitNodeFields(server, result, &completions);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
try addStructInitNodeFields(server, decl, &completions);
|
||||||
|
},
|
||||||
|
else => continue,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else { // var_access, but also field_access if the node's rhs is an alias, eg const MyStruct = path.to.MyStruct;
|
||||||
|
const maybe_decl = try server.analyser.lookupSymbolGlobal(handle, tree.source[identifier_loc.start..identifier_loc.end], identifier_loc.end);
|
||||||
|
if (maybe_decl) |local_decl| {
|
||||||
|
const nodes_tags = handle.tree.nodes.items(.tag);
|
||||||
|
const nodes_data = handle.tree.nodes.items(.data);
|
||||||
|
const node_data = nodes_data[local_decl.decl.ast_node];
|
||||||
|
if (node_data.rhs != 0) {
|
||||||
|
switch (nodes_tags[node_data.rhs]) {
|
||||||
|
.field_access => { // decl is an alias, ie const MyStruct = path.to.MyStruct;
|
||||||
|
const node_loc = offsets.nodeToLoc(tree, node_data.rhs);
|
||||||
|
const possible_decls = (try server.getSymbolFieldAccesses(handle, node_loc.end, node_loc));
|
||||||
|
if (possible_decls) |decls| {
|
||||||
|
for (decls) |decl| {
|
||||||
|
switch (decl.decl.*) {
|
||||||
|
.ast_node => |node| {
|
||||||
|
if (try server.analyser.resolveVarDeclAlias(.{ .node = node, .handle = decl.handle })) |result| {
|
||||||
|
try addStructInitNodeFields(server, result, &completions);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
try addStructInitNodeFields(server, decl, &completions);
|
||||||
|
},
|
||||||
|
else => continue,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
else => try addStructInitNodeFields(server, local_decl, &completions),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (completions.items.len != 0) return completions.toOwnedSlice(allocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
var completions = try server.document_store.enumCompletionItems(allocator, handle.*);
|
||||||
return completions;
|
return completions;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -836,7 +974,7 @@ pub fn completionAtIndex(server: *Server, source_index: usize, handle: *const Do
|
|||||||
.var_access, .empty => try completeGlobal(server, source_index, handle),
|
.var_access, .empty => try completeGlobal(server, source_index, handle),
|
||||||
.field_access => |loc| try completeFieldAccess(server, handle, source_index, loc),
|
.field_access => |loc| try completeFieldAccess(server, handle, source_index, loc),
|
||||||
.global_error_set => try completeError(server, handle),
|
.global_error_set => try completeError(server, handle),
|
||||||
.enum_literal => try completeDot(server, handle),
|
.enum_literal => try completeDot(server, handle, source_index),
|
||||||
.label => try completeLabel(server, source_index, handle),
|
.label => try completeLabel(server, source_index, handle),
|
||||||
.import_string_literal,
|
.import_string_literal,
|
||||||
.cinclude_string_literal,
|
.cinclude_string_literal,
|
||||||
|
Loading…
Reference in New Issue
Block a user