Skip to content

Commit

Permalink
Show doc comments for errors in error sets (zigtools#1302)
Browse files Browse the repository at this point in the history
  • Loading branch information
FnControlOption authored and KoltPenny committed Oct 18, 2023
1 parent 5e16322 commit 2f60853
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 39 deletions.
14 changes: 8 additions & 6 deletions src/analysis.zig
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,16 @@ pub fn invalidate(self: *Analyser) void {
_ = self.arena.reset(.free_all);
}

pub fn getDocCommentsBeforeToken(allocator: std.mem.Allocator, tree: Ast, base: Ast.TokenIndex) !?[]const u8 {
const tokens = tree.tokens.items(.tag);
const doc_comment_index = getDocCommentTokenIndex(tokens, base) orelse return null;
return try collectDocComments(allocator, tree, doc_comment_index, false);
}

/// Gets a declaration's doc comments. Caller owns returned memory.
pub fn getDocComments(allocator: std.mem.Allocator, tree: Ast, node: Ast.Node.Index) !?[]const u8 {
const base = tree.nodes.items(.main_token)[node];
const base_kind = tree.nodes.items(.tag)[node];
const tokens = tree.tokens.items(.tag);

switch (base_kind) {
// As far as I know, this does not actually happen yet, but it
Expand All @@ -67,10 +72,7 @@ pub fn getDocComments(allocator: std.mem.Allocator, tree: Ast, node: Ast.Node.In
.container_field_init,
.container_field_align,
.container_field,
=> {
if (getDocCommentTokenIndex(tokens, base)) |doc_comment_index|
return try collectDocComments(allocator, tree, doc_comment_index, false);
},
=> return try getDocCommentsBeforeToken(allocator, tree, base),
else => {},
}
return null;
Expand Down Expand Up @@ -2044,7 +2046,7 @@ pub const Declaration = union(enum) {
block: Ast.Node.Index,
},
/// always an identifier
error_token: Ast.Node.Index,
error_token: Ast.TokenIndex,

pub const Index = enum(u32) { _ };

Expand Down
78 changes: 46 additions & 32 deletions src/features/completions.zig
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,32 @@ fn typeToCompletion(
}
}

fn completionDoc(
server: *Server,
either_descriptor: ?[]const u8,
doc_comments: ?[]const u8,
) error{OutOfMemory}!@TypeOf(@as(types.CompletionItem, undefined).documentation) {
var list = std.ArrayList(u8).init(server.arena.allocator());
const writer = list.writer();

if (either_descriptor) |ed|
try writer.print("`Conditionally available: {s}`", .{ed});

if (doc_comments) |dc| {
if (either_descriptor != null)
try writer.writeAll("\n\n");
try writer.writeAll(dc);
}

if (list.items.len == 0)
return null;

return .{ .MarkupContent = types.MarkupContent{
.kind = if (server.client_capabilities.completion_doc_supports_md) .markdown else .plaintext,
.value = list.items,
} };
}

fn nodeToCompletion(
server: *Server,
list: *std.ArrayListUnmanaged(types.CompletionItem),
Expand All @@ -107,27 +133,11 @@ fn nodeToCompletion(
const datas = tree.nodes.items(.data);
const token_tags = tree.tokens.items(.tag);

const doc_kind: types.MarkupKind = if (server.client_capabilities.completion_doc_supports_md)
.markdown
else
.plaintext;

const Documentation = @TypeOf(@as(types.CompletionItem, undefined).documentation);

const doc: Documentation = if (try Analyser.getDocComments(
allocator,
handle.tree,
node,
)) |doc_comments| .{ .MarkupContent = types.MarkupContent{
.kind = doc_kind,
.value = if (either_descriptor) |ed|
try std.fmt.allocPrint(allocator, "`Conditionally available: {s}`\n\n{s}", .{ ed, doc_comments })
else
doc_comments,
} } else (if (either_descriptor) |ed| .{ .MarkupContent = types.MarkupContent{
.kind = doc_kind,
.value = try std.fmt.allocPrint(allocator, "`Conditionally available: {s}`", .{ed}),
} } else null);
const doc = try completionDoc(
server,
either_descriptor,
try Analyser.getDocComments(allocator, handle.tree, node),
);

if (ast.isContainer(handle.tree, node)) {
const context = DeclToCompletionContext{
Expand Down Expand Up @@ -358,17 +368,15 @@ fn declToCompletion(context: DeclToCompletionContext, decl_handle: Analyser.Decl
context.either_descriptor,
),
.param_payload => |pay| {
const Documentation = @TypeOf(@as(types.CompletionItem, undefined).documentation);

const param = pay.param;
const doc_kind: types.MarkupKind = if (context.server.client_capabilities.completion_doc_supports_md) .markdown else .plaintext;
const doc: Documentation = if (param.first_doc_comment) |doc_comments| .{ .MarkupContent = types.MarkupContent{
.kind = doc_kind,
.value = if (context.either_descriptor) |ed|
try std.fmt.allocPrint(allocator, "`Conditionally available: {s}`\n\n{s}", .{ ed, try Analyser.collectDocComments(allocator, tree, doc_comments, false) })
const doc = try completionDoc(
context.server,
context.either_descriptor,
if (param.first_doc_comment) |doc_comments|
try Analyser.collectDocComments(allocator, tree, doc_comments, false)
else
try Analyser.collectDocComments(allocator, tree, doc_comments, false),
} } else null;
null,
);

try context.completions.append(allocator, .{
.label = tree.tokenSlice(param.name_token.?),
Expand All @@ -395,12 +403,18 @@ fn declToCompletion(context: DeclToCompletionContext, decl_handle: Analyser.Decl
.insertTextFormat = .PlainText,
});
},
.error_token => {
const name = tree.tokenSlice(decl_handle.decl.error_token);
.error_token => |token| {
const name = tree.tokenSlice(token);
const doc = try completionDoc(
context.server,
context.either_descriptor,
try Analyser.getDocCommentsBeforeToken(allocator, tree, token),
);

try context.completions.append(allocator, .{
.label = name,
.kind = .Constant,
.documentation = doc,
.detail = try std.fmt.allocPrint(allocator, "error.{s}", .{name}),
.insertText = name,
.insertTextFormat = .PlainText,
Expand Down
5 changes: 4 additions & 1 deletion src/features/hover.zig
Original file line number Diff line number Diff line change
Expand Up @@ -81,13 +81,16 @@ pub fn hoverSymbol(server: *Server, decl_handle: Analyser.DeclWithHandle, markup

break :def ast.paramSlice(tree, param);
},
.error_token => |token| def: {
doc_str = try Analyser.getDocCommentsBeforeToken(server.arena.allocator(), tree, token);
break :def tree.tokenSlice(decl_handle.nameToken());
},
.pointer_payload,
.error_union_payload,
.array_payload,
.array_index,
.switch_payload,
.label_decl,
.error_token,
=> tree.tokenSlice(decl_handle.nameToken()),
};

Expand Down

0 comments on commit 2f60853

Please sign in to comment.