Fixes and completions
This commit is contained in:
parent
1c9da7053c
commit
4645638434
@ -79,14 +79,14 @@ pub fn collectDocComments(
|
||||
}
|
||||
|
||||
/// Gets a function signature (keywords, name, return value)
|
||||
pub fn getFunctionSignature(tree: ast.Tree, func: *ast.full.FnProto) []const u8 {
|
||||
pub fn getFunctionSignature(tree: ast.Tree, func: ast.full.FnProto) []const u8 {
|
||||
const start = tree.tokenLocation(func.ast.fn_token).line_start;
|
||||
const end = tree.tokenLocation(func.ast.return_type).line_end;
|
||||
return tree.source[start..end];
|
||||
}
|
||||
|
||||
/// Gets a function snippet insert text
|
||||
pub fn getFunctionSnippet(allocator: *std.mem.Allocator, tree: ast.Tree, func: *ast.full.FnProto, skip_self_param: bool) ![]const u8 {
|
||||
pub fn getFunctionSnippet(allocator: *std.mem.Allocator, tree: ast.Tree, func: ast.full.FnProto, skip_self_param: bool) ![]const u8 {
|
||||
const name_index = func.name_token orelse unreachable;
|
||||
|
||||
var buffer = std.ArrayList(u8).init(allocator);
|
||||
@ -143,14 +143,14 @@ pub fn getFunctionSnippet(allocator: *std.mem.Allocator, tree: ast.Tree, func: *
|
||||
}
|
||||
|
||||
/// Gets a function signature (keywords, name, return value)
|
||||
pub fn getVariableSignature(tree: ast.Tree, var_decl: *ast.full.VarDecl) []const u8 {
|
||||
pub fn getVariableSignature(tree: ast.Tree, var_decl: ast.full.VarDecl) []const u8 {
|
||||
const start = tree.tokenLocation(0, var_decl.ast.mut_token).line_start;
|
||||
const end = tree.tokenLocation(@truncate(u32, start), tree.lastToken(var_decl.ast.init_node)).line_end;
|
||||
return tree.source[start..end];
|
||||
}
|
||||
|
||||
// analysis.getContainerFieldSignature(handle.tree, field)
|
||||
pub fn getContainerFieldSignature(tree: ast.Tree, field: *ast.full.ContainerField) []const u8 {
|
||||
pub fn getContainerFieldSignature(tree: ast.Tree, field: ast.full.ContainerField) []const u8 {
|
||||
const start = tree.tokenLocation(0, field.ast.name_token).line_start;
|
||||
const end = tree.tokenLocation(@truncate(u32, start), tree.lastToken(field.ast.value_expr)).line_start;
|
||||
return tree.source[start..end];
|
||||
@ -430,7 +430,7 @@ fn resolveUnwrapErrorType(
|
||||
return null;
|
||||
}
|
||||
|
||||
fn isPtrType(tree: ast.Tree, node: ast.Node.Index) bool {
|
||||
pub fn isPtrType(tree: ast.Tree, node: ast.Node.Index) bool {
|
||||
return switch (tree.nodes.items(.tag)[node]) {
|
||||
.ptr_type,
|
||||
.ptr_type_aligned,
|
||||
@ -1807,7 +1807,7 @@ pub const DeclWithHandle = struct {
|
||||
}
|
||||
};
|
||||
|
||||
fn containerField(tree: ast.Tree, node: ast.Node.Index) ?ast.full.ContainerField {
|
||||
pub fn containerField(tree: ast.Tree, node: ast.Node.Index) ?ast.full.ContainerField {
|
||||
return switch (tree.nodes.items(.tag)[node]) {
|
||||
.container_field => tree.containerField(node),
|
||||
.container_field_init => tree.containerFieldInit(node),
|
||||
@ -1816,6 +1816,16 @@ fn containerField(tree: ast.Tree, node: ast.Node.Index) ?ast.full.ContainerField
|
||||
};
|
||||
}
|
||||
|
||||
pub fn ptrType(tree: ast.Tree, node: ast.Node.Index) ?ast.full.PtrType {
|
||||
return switch (tree.nodes.items(.tag)[node]) {
|
||||
.ptr_type => tree.ptrType(node),
|
||||
.ptr_type_aligned => tree.ptrTypeAligned(node),
|
||||
.ptr_type_bit_range => tree.ptrTypeBitRange(node),
|
||||
.ptr_type_sentinel => tree.ptrTypeSentinel(node),
|
||||
else => null,
|
||||
};
|
||||
}
|
||||
|
||||
fn findContainerScope(container_handle: NodeWithHandle) ?*Scope {
|
||||
const container = container_handle.node;
|
||||
const handle = container_handle.handle;
|
||||
@ -2218,7 +2228,7 @@ fn nodeSourceRange(tree: ast.Tree, node: ast.Node.Index) SourceRange {
|
||||
};
|
||||
}
|
||||
|
||||
fn isContainer(tag: ast.Node.Tag) bool {
|
||||
pub fn isContainer(tag: ast.Node.Tag) bool {
|
||||
return switch (tag) {
|
||||
.container_decl,
|
||||
.container_decl_trailing,
|
||||
@ -2265,7 +2275,7 @@ fn declMembers(tree: ast.Tree, tag: ast.Node.Tag, node_idx: ast.Node.Index) []co
|
||||
|
||||
/// Returns an `ast.full.VarDecl` for a given node index.
|
||||
/// Returns null if the tag doesn't match
|
||||
fn varDecl(tree: ast.Tree, node_idx: ast.Node.Index) ?ast.full.VarDecl {
|
||||
pub fn varDecl(tree: ast.Tree, node_idx: ast.Node.Index) ?ast.full.VarDecl {
|
||||
return switch (tree.nodes.items(.tag)[node_idx]) {
|
||||
.global_var_decl => tree.globalVarDecl(node_idx),
|
||||
.local_var_decl => tree.localVarDecl(node_idx),
|
||||
|
176
src/main.zig
176
src/main.zig
@ -332,6 +332,10 @@ fn nodeToCompletion(
|
||||
) error{OutOfMemory}!void {
|
||||
const node = node_handle.node;
|
||||
const handle = node_handle.handle;
|
||||
const tree = handle.tree;
|
||||
const node_tags = tree.nodes.items(.tag);
|
||||
const datas = tree.nodes.items(.data);
|
||||
const token_tags = tree.tokens.items(.tag);
|
||||
|
||||
const doc_kind: types.MarkupContent.Kind = if (client_capabilities.completion_doc_supports_md)
|
||||
.Markdown
|
||||
@ -351,7 +355,7 @@ fn nodeToCompletion(
|
||||
else
|
||||
null;
|
||||
|
||||
if (node.tag == .ErrorSetDecl or node.tag == .Root or node.tag == .ContainerDecl) {
|
||||
if (analysis.isContainer(node_tags[node])) {
|
||||
const context = DeclToCompletionContext{
|
||||
.completions = list,
|
||||
.config = &config,
|
||||
@ -363,44 +367,43 @@ fn nodeToCompletion(
|
||||
|
||||
if (is_type_val) return;
|
||||
|
||||
switch (node.tag) {
|
||||
.FnProto => {
|
||||
const func = node.cast(std.zig.ast.Node.FnProto).?;
|
||||
if (func.getNameToken()) |name_token| {
|
||||
switch (node_tags[node]) {
|
||||
.fn_proto, .fn_proto_multi, .fn_proto_one, .fn_proto_multi, .fn_decl => {
|
||||
var buf: [1]std.zig.ast.Node.Index = undefined;
|
||||
const func = analysis.fnProto(tree, node, &buf).?;
|
||||
if (func.name_token) |name_token| {
|
||||
const use_snippets = config.enable_snippets and client_capabilities.supports_snippets;
|
||||
|
||||
const insert_text = if (use_snippets) blk: {
|
||||
// TODO Also check if we are dot accessing from a type val and dont skip in that case.
|
||||
const skip_self_param = if (func.params_len > 0) param_check: {
|
||||
const in_container = analysis.innermostContainer(handle, handle.tree.token_locs[func.firstToken()].start);
|
||||
const skip_self_param = if (func.ast.params.len > 0) param_check: {
|
||||
const in_container = analysis.innermostContainer(handle, tree.tokenLocation(0, func.ast.fn_token).line_start);
|
||||
|
||||
switch (func.paramsConst()[0].param_type) {
|
||||
.type_expr => |type_node| {
|
||||
if (try analysis.resolveTypeOfNode(&document_store, arena, .{
|
||||
.node = type_node,
|
||||
.handle = handle,
|
||||
})) |resolved_type| {
|
||||
if (std.meta.eql(in_container, resolved_type))
|
||||
break :param_check true;
|
||||
}
|
||||
var it = func.iterate(tree);
|
||||
const param = it.next().?;
|
||||
|
||||
if (type_node.castTag(.PtrType)) |ptr_type| {
|
||||
if (try analysis.resolveTypeOfNode(&document_store, arena, .{
|
||||
.node = ptr_type.rhs,
|
||||
.handle = handle,
|
||||
})) |resolved_prefix_op| {
|
||||
if (std.meta.eql(in_container, resolved_prefix_op))
|
||||
break :param_check true;
|
||||
}
|
||||
}
|
||||
|
||||
break :param_check false;
|
||||
},
|
||||
else => break :param_check false,
|
||||
if (try analysis.resolveTypeOfNode(&document_store, arena, .{
|
||||
.node = param.type_expr,
|
||||
.handle = handle,
|
||||
})) |resolved_type| {
|
||||
if (std.meta.eql(in_container, resolved_type))
|
||||
break :param_check true;
|
||||
}
|
||||
|
||||
if (analysis.isPtrType(tree, param.type_expr)) {
|
||||
if (try analysis.resolveTypeOfNode(&document_store, arena, .{
|
||||
.node = datas[param.type_expr].rhs,
|
||||
.handle = handle,
|
||||
})) |resolved_prefix_op| {
|
||||
if (std.meta.eql(in_container, resolved_prefix_op))
|
||||
break :param_check true;
|
||||
}
|
||||
}
|
||||
|
||||
break :param_check false;
|
||||
} else false;
|
||||
|
||||
break :blk try analysis.getFunctionSnippet(&arena.allocator, handle.tree, func, skip_self_param);
|
||||
break :blk try analysis.getFunctionSnippet(&arena.allocator, tree, func, skip_self_param);
|
||||
} else null;
|
||||
|
||||
const is_type_function = analysis.isTypeFunction(handle.tree, func);
|
||||
@ -415,9 +418,9 @@ fn nodeToCompletion(
|
||||
});
|
||||
}
|
||||
},
|
||||
.VarDecl => {
|
||||
const var_decl = node.cast(std.zig.ast.Node.VarDecl).?;
|
||||
const is_const = handle.tree.token_ids[var_decl.mut_token] == .Keyword_const;
|
||||
.global_var_decl, .local_var_decl, .aligned_var_decl, .simple_var_decl => {
|
||||
const var_decl = analysis.varDecl(tree, node).?;
|
||||
const is_const = token_tags[var_decl.ast.mut_token] == .keyword_const;
|
||||
|
||||
if (try analysis.resolveVarDeclAlias(&document_store, arena, node_handle)) |result| {
|
||||
const context = DeclToCompletionContext{
|
||||
@ -430,57 +433,46 @@ fn nodeToCompletion(
|
||||
}
|
||||
|
||||
try list.append(.{
|
||||
.label = handle.tree.tokenSlice(var_decl.name_token),
|
||||
.label = handle.tree.tokenSlice(var_decl.ast.mut_token + 1),
|
||||
.kind = if (is_const) .Constant else .Variable,
|
||||
.documentation = doc,
|
||||
.detail = analysis.getVariableSignature(handle.tree, var_decl),
|
||||
.detail = analysis.getVariableSignature(tree, var_decl),
|
||||
});
|
||||
},
|
||||
.ContainerField => {
|
||||
const field = node.cast(std.zig.ast.Node.ContainerField).?;
|
||||
.container_field, .container_field_align, .container_field_init => {
|
||||
const field = analysis.containerField(tree, node).?;
|
||||
try list.append(.{
|
||||
.label = handle.tree.tokenSlice(field.name_token),
|
||||
.label = handle.tree.tokenSlice(field.ast.name_token),
|
||||
.kind = .Field,
|
||||
.documentation = doc,
|
||||
.detail = analysis.getContainerFieldSignature(handle.tree, field),
|
||||
});
|
||||
},
|
||||
.SliceType => {
|
||||
try list.append(.{
|
||||
.label = "len",
|
||||
.kind = .Field,
|
||||
});
|
||||
try list.append(.{
|
||||
.label = "ptr",
|
||||
.kind = .Field,
|
||||
});
|
||||
},
|
||||
.ArrayType => {
|
||||
.array_type, .array_type_sentinel => {
|
||||
try list.append(.{
|
||||
.label = "len",
|
||||
.kind = .Field,
|
||||
});
|
||||
},
|
||||
.PtrType => {
|
||||
if (config.operator_completions) {
|
||||
try list.append(.{
|
||||
.label = "*",
|
||||
.kind = .Operator,
|
||||
});
|
||||
.ptr_type, .ptr_type_aligned, .ptr_type_bit_range, .ptr_type_sentinel => {
|
||||
const ptr_type = analysis.ptrType(tree, node).?;
|
||||
|
||||
switch (ptr_type.size) {
|
||||
.One, .C => if (config.operator_completions) {
|
||||
try list.append(.{
|
||||
.label = "*",
|
||||
.kind = .Operator,
|
||||
});
|
||||
},
|
||||
.Many, .Slice => return list.append(.{ .label = "len", .kind = .Field }),
|
||||
}
|
||||
|
||||
const ptr_type = node.castTag(.PtrType).?;
|
||||
if (ptr_type.rhs.castTag(.ArrayType) != null) {
|
||||
try list.append(.{
|
||||
.label = "len",
|
||||
.kind = .Field,
|
||||
});
|
||||
} else if (unwrapped) |actual_type| {
|
||||
if (unwrapped) |actual_type| {
|
||||
try typeToCompletion(arena, list, .{ .original = actual_type }, orig_handle, config);
|
||||
}
|
||||
return;
|
||||
},
|
||||
.OptionalType => {
|
||||
.optional_type => {
|
||||
if (config.operator_completions) {
|
||||
try list.append(.{
|
||||
.label = "?",
|
||||
@ -489,7 +481,7 @@ fn nodeToCompletion(
|
||||
}
|
||||
return;
|
||||
},
|
||||
.StringLiteral => {
|
||||
.string_literal => {
|
||||
try list.append(.{
|
||||
.label = "len",
|
||||
.kind = .Field,
|
||||
@ -500,7 +492,7 @@ fn nodeToCompletion(
|
||||
.label = string,
|
||||
.kind = .Field,
|
||||
.documentation = doc,
|
||||
.detail = handle.tree.getNodeSource(node),
|
||||
.detail = tree.getNodeSource(node),
|
||||
});
|
||||
},
|
||||
}
|
||||
@ -564,8 +556,13 @@ fn gotoDefinitionSymbol(id: types.RequestId, arena: *std.heap.ArenaAllocator, de
|
||||
});
|
||||
}
|
||||
|
||||
fn hoverSymbol(id: types.RequestId, arena: *std.heap.ArenaAllocator, decl_handle: analysis.DeclWithHandle) (std.os.WriteError || error{OutOfMemory})!void {
|
||||
fn hoverSymbol(
|
||||
id: types.RequestId,
|
||||
arena: *std.heap.ArenaAllocator,
|
||||
decl_handle: analysis.DeclWithHandle,
|
||||
) (std.os.WriteError || error{OutOfMemory})!void {
|
||||
const handle = decl_handle.handle;
|
||||
const tree = handle.tree;
|
||||
|
||||
const hover_kind: types.MarkupContent.Kind = if (client_capabilities.hover_supports_md) .Markdown else .PlainText;
|
||||
const md_string = switch (decl_handle.decl.*) {
|
||||
@ -574,26 +571,20 @@ fn hoverSymbol(id: types.RequestId, arena: *std.heap.ArenaAllocator, decl_handle
|
||||
return try hoverSymbol(id, arena, result);
|
||||
}
|
||||
|
||||
const doc_str = if (try analysis.getDocComments(&arena.allocator, handle.tree, node, hover_kind)) |str|
|
||||
const doc_str = if (try analysis.getDocComments(&arena.allocator, tree, node, hover_kind)) |str|
|
||||
str
|
||||
else
|
||||
"";
|
||||
|
||||
const signature_str = switch (node.tag) {
|
||||
.VarDecl => blk: {
|
||||
const var_decl = node.cast(std.zig.ast.Node.VarDecl).?;
|
||||
break :blk analysis.getVariableSignature(handle.tree, var_decl);
|
||||
},
|
||||
.FnProto => blk: {
|
||||
const fn_decl = node.cast(std.zig.ast.Node.FnProto).?;
|
||||
break :blk analysis.getFunctionSignature(handle.tree, fn_decl);
|
||||
},
|
||||
.ContainerField => blk: {
|
||||
const field = node.cast(std.zig.ast.Node.ContainerField).?;
|
||||
break :blk analysis.getContainerFieldSignature(handle.tree, field);
|
||||
},
|
||||
else => analysis.nodeToString(handle.tree, node) orelse return try respondGeneric(id, null_result_response),
|
||||
};
|
||||
var buf: [1]std.zig.ast.Node.Index = undefined;
|
||||
const signature_str = if (analysis.varDecl(tree, node)) |var_decl| blk: {
|
||||
break :blk analysis.getVariableSignature(tree, var_decl);
|
||||
} else if (analysis.fnProto(tree, node, &buf)) |fn_proto| blk: {
|
||||
break :blk analysis.getFunctionSignature(tree, fn_proto);
|
||||
} else if (analysis.containerField(tree, node)) |field| blk: {
|
||||
break :blk analysis.getContainerFieldSignature(tree, field);
|
||||
} else analysis.nodeToString(tree, node) orelse
|
||||
return try respondGeneric(id, null_result_response);
|
||||
|
||||
break :ast_node if (hover_kind == .Markdown)
|
||||
try std.fmt.allocPrint(&arena.allocator, "```zig\n{s}\n```\n{s}", .{ signature_str, doc_str })
|
||||
@ -601,31 +592,38 @@ fn hoverSymbol(id: types.RequestId, arena: *std.heap.ArenaAllocator, decl_handle
|
||||
try std.fmt.allocPrint(&arena.allocator, "{s}\n{s}", .{ signature_str, doc_str });
|
||||
},
|
||||
.param_decl => |param| param_decl: {
|
||||
const doc_str = if (param.doc_comments) |doc_comments|
|
||||
const doc_str = if (param.first_doc_comment) |doc_comments|
|
||||
try analysis.collectDocComments(&arena.allocator, handle.tree, doc_comments, hover_kind)
|
||||
else
|
||||
"";
|
||||
|
||||
const signature_str = handle.tree.source[handle.tree.token_locs[param.firstToken()].start..handle.tree.token_locs[param.lastToken()].end];
|
||||
const first_token = param.first_doc_comment orelse
|
||||
param.comptime_noalias orelse
|
||||
param.name_token orelse
|
||||
param.anytype_ellipsis3 orelse
|
||||
tree.firstToken(param.type_expr);
|
||||
const last_token = tree.lastToken(param.type_expr);
|
||||
|
||||
const signature_str = tree.source[tree.tokenLocation(0, first_token).line_start..tree.tokenLocation(0, last_token).line_end];
|
||||
break :param_decl if (hover_kind == .Markdown)
|
||||
try std.fmt.allocPrint(&arena.allocator, "```zig\n{s}\n```\n{s}", .{ signature_str, doc_str })
|
||||
else
|
||||
try std.fmt.allocPrint(&arena.allocator, "{s}\n{s}", .{ signature_str, doc_str });
|
||||
},
|
||||
.pointer_payload => |payload| if (hover_kind == .Markdown)
|
||||
try std.fmt.allocPrint(&arena.allocator, "```zig\n{s}\n```", .{handle.tree.tokenSlice(payload.node.value_symbol.firstToken())})
|
||||
try std.fmt.allocPrint(&arena.allocator, "```zig\n{s}\n```", .{tree.tokenSlice(payload.name)})
|
||||
else
|
||||
try std.fmt.allocPrint(&arena.allocator, "{s}", .{handle.tree.tokenSlice(payload.node.value_symbol.firstToken())}),
|
||||
try std.fmt.allocPrint(&arena.allocator, "{s}", .{tree.tokenSlice(payload.name)}),
|
||||
// .array_payload => |payload| if (hover_kind == .Markdown)
|
||||
// try std.fmt.allocPrint(&arena.allocator, "```zig\n{s}\n```", .{handle.tree.tokenSlice(payload.identifier.firstToken())})
|
||||
// else
|
||||
// try std.fmt.allocPrint(&arena.allocator, "{s}", .{handle.tree.tokenSlice(payload.identifier.firstToken())}),
|
||||
.switch_payload => |payload| if (hover_kind == .Markdown)
|
||||
try std.fmt.allocPrint(&arena.allocator, "```zig\n{s}\n```", .{handle.tree.tokenSlice(payload.node.value_symbol.firstToken())})
|
||||
try std.fmt.allocPrint(&arena.allocator, "```zig\n{s}\n```", .{tree.tokenSlice(payload.node)})
|
||||
else
|
||||
try std.fmt.allocPrint(&arena.allocator, "{s}", .{handle.tree.tokenSlice(payload.node.value_symbol.firstToken())}),
|
||||
try std.fmt.allocPrint(&arena.allocator, "{s}", .{tree.tokenSlice(payload.node)}),
|
||||
.label_decl => |label_decl| block: {
|
||||
const source = handle.tree.source[handle.tree.token_locs[label_decl.firstToken()].start..handle.tree.token_locs[label_decl.lastToken()].end];
|
||||
const source = tree.tokenSlice(label_decl);
|
||||
break :block if (hover_kind == .Markdown)
|
||||
try std.fmt.allocPrint(&arena.allocator, "```zig\n{s}\n```", .{source})
|
||||
else
|
||||
|
@ -113,9 +113,9 @@ pub fn tokenLength(tree: std.zig.ast.Tree, token: std.zig.ast.TokenIndex, encodi
|
||||
if (encoding == .utf8)
|
||||
return token_loc.line_end - token_loc.line_start;
|
||||
|
||||
var i: usize = token_loc.start;
|
||||
var i: usize = token_loc.line_start;
|
||||
var utf16_len: usize = 0;
|
||||
while (i < token_loc.end) {
|
||||
while (i < token_loc.line_end) {
|
||||
const n = std.unicode.utf8ByteSequenceLength(tree.source[i]) catch unreachable;
|
||||
const codepoint = std.unicode.utf8Decode(tree.source[i .. i + n]) catch unreachable;
|
||||
if (codepoint < 0x10000) {
|
||||
|
@ -78,7 +78,7 @@ fn symbolReferencesInternal(
|
||||
const node = node_handle.node;
|
||||
const handle = node_handle.handle;
|
||||
|
||||
switch (node.tag) {
|
||||
switch (handle.tree.nodes.items(.tag)[node]) {
|
||||
.ContainerDecl, .Root, .Block => {
|
||||
var idx: usize = 0;
|
||||
while (node.iterate(idx)) |child| : (idx += 1) {
|
||||
|
Loading…
Reference in New Issue
Block a user