Skip to content

Commit 0ac5325

Browse files
authored
provide global error set completions inside error{...} (zigtools#2561)
1 parent 25360ab commit 0ac5325

File tree

2 files changed

+66
-16
lines changed

2 files changed

+66
-16
lines changed

src/analysis.zig

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4855,9 +4855,14 @@ pub const PositionContext = union(enum) {
48554855
const StackState = struct {
48564856
ctx: PositionContext,
48574857
stack_id: StackId,
4858+
4859+
/// Indicates whether the current context is an ErrorSet definition, ie `error{...}`
4860+
pub fn isErrSetDef(self: StackState) bool {
4861+
return (self.stack_id == .brace and self.ctx == .global_error_set);
4862+
}
48584863
};
48594864

4860-
const StackId = enum { paren, bracket, global };
4865+
const StackId = enum { paren, bracket, brace, global };
48614866

48624867
fn peek(allocator: std.mem.Allocator, arr: *std.ArrayList(StackState)) !*StackState {
48634868
if (arr.items.len == 0) {
@@ -4917,6 +4922,25 @@ pub fn getPositionContext(
49174922
break;
49184923
}
49194924

4925+
// Check if the previous line ends with a ',', ie a continuation - targets multiline ErrorSet definitions
4926+
var lloc = line_loc;
4927+
while (true) {
4928+
while (lloc.start > 0) {
4929+
if (tree.source[lloc.start] != '\n') lloc.start -= 1 else break;
4930+
} else break;
4931+
while (lloc.start > 0 and tree.source[lloc.start] == '\n') lloc.start -= 1;
4932+
if (lloc.start == 0) break;
4933+
lloc = offsets.lineLocAtIndex(tree.source, lloc.start);
4934+
// Check if it's a comment first
4935+
while (lloc.start > 0 and std.mem.startsWith(u8, std.mem.trimStart(u8, offsets.locToSlice(tree.source, lloc), " \t"), "//")) {
4936+
const prev_line_loc = offsets.lineLocAtIndex(tree.source, lloc.start - 1); // `- 1` => prev line's `\n`
4937+
lloc = prev_line_loc;
4938+
}
4939+
if (std.mem.endsWith(u8, std.mem.trimEnd(u8, offsets.locToSlice(tree.source, lloc), " \t\r\n"), ",")) continue;
4940+
line_loc.start = lloc.start;
4941+
break;
4942+
}
4943+
49204944
var stack: std.ArrayList(StackState) = try .initCapacity(allocator, 8);
49214945
defer stack.deinit(allocator);
49224946
var should_do_lookahead = lookahead;
@@ -5013,7 +5037,9 @@ pub fn getPositionContext(
50135037
}
50145038
}
50155039
},
5016-
.identifier => switch (curr_ctx.ctx) {
5040+
.identifier => if (curr_ctx.isErrSetDef()) {
5041+
// Intent is to skip everything between the `error{...}` braces
5042+
} else switch (curr_ctx.ctx) {
50175043
.enum_literal => curr_ctx.ctx = .{ .enum_literal = tokenLocAppend(curr_ctx.ctx.loc(tree).?, tok) },
50185044
.field_access => curr_ctx.ctx = .{ .field_access = tokenLocAppend(curr_ctx.ctx.loc(tree).?, tok) },
50195045
.label_access => |loc| curr_ctx.ctx = if (loc.start == loc.end)
@@ -5061,21 +5087,29 @@ pub fn getPositionContext(
50615087
};
50625088
try stack.append(allocator, .{ .ctx = .empty, .stack_id = stack_id });
50635089
},
5064-
.l_bracket => try stack.append(allocator, .{ .ctx = .empty, .stack_id = .bracket }),
50655090
.r_paren => {
50665091
// Do this manually, as .pop() sets `stack.items[stack.items.len - 1]` to `undefined` which currently curr_ctx points to
50675092
if (stack.items.len != 0) stack.items.len -= 1;
50685093
if (curr_ctx.stack_id != .paren) {
50695094
(try peek(allocator, &stack)).ctx = .empty;
50705095
}
50715096
},
5097+
.l_bracket => try stack.append(allocator, .{ .ctx = .empty, .stack_id = .bracket }),
50725098
.r_bracket => {
50735099
// Do this manually, as .pop() sets `stack.items[stack.items.len - 1]` to `undefined` which currently curr_ctx points to
50745100
if (stack.items.len != 0) stack.items.len -= 1;
50755101
if (curr_ctx.stack_id != .bracket) {
50765102
(try peek(allocator, &stack)).ctx = .empty;
50775103
}
50785104
},
5105+
.l_brace => try stack.append(allocator, .{ .ctx = if (curr_ctx.ctx == .global_error_set) curr_ctx.ctx else .empty, .stack_id = .brace }),
5106+
.r_brace => {
5107+
// Do this manually, as .pop() sets `stack.items[stack.items.len - 1]` to `undefined` which currently curr_ctx points to
5108+
if (stack.items.len != 0) stack.items.len -= 1;
5109+
if (curr_ctx.stack_id != .brace) {
5110+
(try peek(allocator, &stack)).ctx = .empty;
5111+
}
5112+
},
50795113
.keyword_error => curr_ctx.ctx = .global_error_set,
50805114
.number_literal => {
50815115
if (tok.loc.start <= source_index and tok.loc.end >= source_index) {
@@ -5099,7 +5133,13 @@ pub fn getPositionContext(
50995133
std.debug.assert(tree.tokenTag(current_token) == tag);
51005134
curr_ctx.ctx = .{ .keyword = current_token };
51015135
},
5102-
.doc_comment, .container_doc_comment => curr_ctx.ctx = .comment,
5136+
.container_doc_comment => curr_ctx.ctx = .comment,
5137+
.doc_comment => {
5138+
if (!curr_ctx.isErrSetDef()) curr_ctx.ctx = .comment; // Intent is to skip everything between the `error{...}` braces
5139+
},
5140+
.comma => {
5141+
if (!curr_ctx.isErrSetDef()) curr_ctx.ctx = .empty; // Intent is to skip everything between the `error{...}` braces
5142+
},
51035143
else => curr_ctx.ctx = .empty,
51045144
}
51055145

tests/utility/position_context.zig

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -401,10 +401,9 @@ test "multi-line string literal" {
401401
}
402402

403403
test "global error set" {
404-
// TODO why is this a .var_access instead of a .global_error_set?
405-
// try testContext(
406-
// \\fn foo() <cursor>error!void {
407-
// , .global_error_set, .{});
404+
try testContext(
405+
\\fn foo() <cursor>error!void {
406+
, .global_error_set, .{ .lookahead = true });
408407
try testContext(
409408
\\fn foo() erro<cursor>r!void {
410409
, .global_error_set, .{ .lookahead = true });
@@ -417,14 +416,25 @@ test "global error set" {
417416
try testContext(
418417
\\fn foo() error.<cursor>!void {
419418
, .global_error_set, .{});
420-
421-
// TODO this should probably also be .global_error_set
422-
// try testContext(
423-
// \\fn foo() error{<cursor>}!void {
424-
// , .global_error_set, .{});
425-
// try testContext(
426-
// \\fn foo() error{OutOfMemory, <cursor>}!void {
427-
// , .global_error_set, .{});
419+
try testContext(
420+
\\fn foo() error{<cursor>}!void {
421+
, .global_error_set, .{});
422+
try testContext(
423+
\\fn foo() error{OutOfMemory, <cursor>}!void {
424+
, .global_error_set, .{});
425+
try testContext(
426+
\\fn foo() error{
427+
\\ OutOfMemory,
428+
\\ <cursor>
429+
\\}!void {
430+
, .global_error_set, .{});
431+
try testContext(
432+
\\fn foo() error{
433+
\\ /// Doc Comment
434+
\\ OutOfMemory,
435+
\\ <cursor>
436+
\\}!void {
437+
, .global_error_set, .{});
428438
}
429439

430440
test "number literal" {

0 commit comments

Comments
 (0)