More .
completion
This commit is contained in:
parent
c89431c625
commit
e1d90a1a1b
@ -1513,6 +1513,26 @@ pub fn getFieldAccessType(analyser: *Analyser, handle: *const DocumentStore.Hand
|
||||
|
||||
current_type = (try analyser.resolveBracketAccessType(current_type orelse return null, if (is_range) .Range else .Single)) orelse return null;
|
||||
},
|
||||
.builtin => {
|
||||
const curr_handle = if (current_type == null) handle else current_type.?.handle;
|
||||
if (std.mem.eql(u8, tokenizer.buffer[tok.loc.start..tok.loc.end], "@import")) {
|
||||
if (tokenizer.next().tag != .l_paren) return null;
|
||||
var import_str_tok = tokenizer.next(); // should be the .string_literal
|
||||
if (import_str_tok.tag != .string_literal) return null;
|
||||
if (import_str_tok.loc.end - import_str_tok.loc.start < 2) return null;
|
||||
var import_str = offsets.locToSlice(tokenizer.buffer, .{
|
||||
.start = import_str_tok.loc.start + 1,
|
||||
.end = import_str_tok.loc.end - 1,
|
||||
});
|
||||
const uri = try analyser.store.uriFromImportStr(analyser.arena, curr_handle.*, import_str) orelse return null;
|
||||
const node_handle = analyser.store.getOrLoadHandle(uri) orelse return null;
|
||||
current_type = TypeWithHandle.typeVal(NodeWithHandle{ .handle = node_handle, .node = 0 });
|
||||
_ = tokenizer.next(); // eat the .r_paren
|
||||
} else {
|
||||
log.debug("Unhandled builtin: {s}", .{offsets.locToSlice(tokenizer.buffer, tok.loc)});
|
||||
return null;
|
||||
}
|
||||
},
|
||||
else => {
|
||||
log.debug("Unimplemented token: {}", .{tok.tag});
|
||||
return null;
|
||||
|
@ -728,28 +728,44 @@ fn kindToSortScore(kind: types.CompletionItemKind) ?[]const u8 {
|
||||
};
|
||||
}
|
||||
|
||||
/// 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
|
||||
/// Given a root node decl or a .simple_var_decl (const MyStruct = struct {..}) node decl, adds it's `.container_field*`s 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,
|
||||
});
|
||||
}
|
||||
switch (node_tags[node]) {
|
||||
.simple_var_decl => {
|
||||
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,
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
.root => {
|
||||
for (decl.handle.tree.rootDecls()) |root_node| {
|
||||
const field = decl.handle.tree.fullContainerField(@intCast(u32, root_node)) 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,
|
||||
});
|
||||
}
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
|
||||
@ -820,7 +836,7 @@ fn completeDot(server: *Server, handle: *const DocumentStore.Handle, source_inde
|
||||
|
||||
var completions = std.ArrayListUnmanaged(types.CompletionItem){};
|
||||
|
||||
if (identifier_loc.start != identifier_original_start) { // field access
|
||||
if (identifier_loc.start != identifier_original_start) { // path.to.MyStruct{.<cursor> => use field access resolution
|
||||
const possible_decls = (try server.getSymbolFieldAccesses(handle, identifier_loc.end, identifier_loc));
|
||||
if (possible_decls) |decls| {
|
||||
for (decls) |decl| {
|
||||
@ -836,7 +852,7 @@ fn completeDot(server: *Server, handle: *const DocumentStore.Handle, source_inde
|
||||
}
|
||||
}
|
||||
}
|
||||
} else { // var_access, but also field_access if the node's rhs is an alias, eg const MyStruct = path.to.MyStruct;
|
||||
} else { // MyStruct{.<cursor> => use var resolution (supports only one level of indirection)
|
||||
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);
|
||||
@ -844,7 +860,29 @@ fn completeDot(server: *Server, handle: *const DocumentStore.Handle, source_inde
|
||||
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;
|
||||
// decl is `const Alias = @import("MyStruct.zig");`
|
||||
.builtin_call_two => {
|
||||
var buffer: [2]Ast.Node.Index = undefined;
|
||||
const params = ast.builtinCallParams(tree, node_data.rhs, &buffer).?;
|
||||
|
||||
const main_tokens = tree.nodes.items(.main_token);
|
||||
const call_name = tree.tokenSlice(main_tokens[node_data.rhs]);
|
||||
|
||||
if (std.mem.eql(u8, call_name, "@import")) {
|
||||
if (params.len == 0) break :struct_init;
|
||||
const import_param = params[0];
|
||||
if (nodes_tags[import_param] != .string_literal) break :struct_init;
|
||||
|
||||
const import_str = tree.tokenSlice(main_tokens[import_param]);
|
||||
const import_uri = (try server.document_store.uriFromImportStr(allocator, handle.*, import_str[1 .. import_str.len - 1])) orelse break :struct_init;
|
||||
|
||||
const node_handle = server.document_store.getOrLoadHandle(import_uri) orelse break :struct_init;
|
||||
var decl = Analyser.Declaration{ .ast_node = 0 };
|
||||
try addStructInitNodeFields(server, Analyser.DeclWithHandle{ .handle = node_handle, .decl = &decl }, &completions);
|
||||
}
|
||||
},
|
||||
// decl is `const Alias = path.to.MyStruct` or `const Alias = @import("file.zig").MyStruct;`
|
||||
.field_access => {
|
||||
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| {
|
||||
@ -862,6 +900,9 @@ fn completeDot(server: *Server, handle: *const DocumentStore.Handle, source_inde
|
||||
}
|
||||
}
|
||||
},
|
||||
// decl is `const AliasB = AliasA;` (alias of an alias)
|
||||
//.identifier => {},
|
||||
// decl is `const MyStruct = struct {..}` which is a .simple_var_decl (check is in addStructInitNodeFields)
|
||||
else => try addStructInitNodeFields(server, local_decl, &completions),
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user