Skip to content

Commit

Permalink
Merge pull request #41 from nolanderc/32-nested-field-completion
Browse files Browse the repository at this point in the history
allow nested field completions
  • Loading branch information
nolanderc authored Oct 18, 2023
2 parents ee67f79 + 6bbd1ec commit 91d7e2b
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 22 deletions.
54 changes: 32 additions & 22 deletions src/analysis.zig
Original file line number Diff line number Diff line change
Expand Up @@ -227,35 +227,34 @@ pub fn visibleFields(
start_node: u32,
symbols: *std.ArrayList(Reference),
) !void {
const name = blk: {
const lhs = lhs: {
const parsed = try document.parseTree();
const tag = parsed.tree.tag(start_node);
if (tag != .identifier and tag != .@".") return;
const tree = parsed.tree;

const parent = parsed.tree.parent(start_node) orelse return;
const parent_tag = parsed.tree.tag(parent);
if (parent_tag != .selection) return;
const tag = tree.tag(start_node);
if (tag != .identifier and tag != .@".") return;

const children = parsed.tree.children(parent);
if (start_node == children.start) return;
const parent = tree.parent(start_node) orelse return;
const selection = syntax.Selection.tryExtract(tree, parent) orelse return;
var target = selection.get(.target, tree) orelse return;

var first = children.start;
while (parsed.tree.tag(first).isSyntax()) {
const grand_children = parsed.tree.children(first);
if (grand_children.start == grand_children.end) return;
first = grand_children.start;
while (true) {
switch (target.get(tree)) {
.identifier => break :lhs target.node,
.selection => |select| break :lhs select.nodeOf(.field, tree) orelse return,
.array => |array| target = array.prefix(tree) orelse return,
.number => return,
}
}
break :blk first;
};

if (start_node == name) {
if (lhs == start_node) {
// possible infinite loop if we are coming from `findDefinition`
return;
}

var name_definitions = std.ArrayList(Reference).init(arena);
try findDefinition(arena, document, name, &name_definitions);
if (name_definitions.items.len == 0) return;
try findDefinition(arena, document, lhs, &name_definitions);

var references = std.ArrayList(Reference).init(document.workspace.allocator);
defer references.deinit();
Expand Down Expand Up @@ -801,6 +800,22 @@ test "find definition field" {
});
}

test "find definition field recursive" {
try expectDefinition(
\\struct Foo { int /*1*/foo; };
\\struct Bar { Foo /*2*/bar; };
\\void main() {
\\ Bar baz;
\\ baz./*3*/bar./*4*/foo;
\\}
, &.{
.{ .source = "/*3*/", .target = "/*1*/", .should_exist = false },
.{ .source = "/*3*/", .target = "/*2*/", .should_exist = true },
.{ .source = "/*4*/", .target = "/*1*/", .should_exist = true },
.{ .source = "/*4*/", .target = "/*2*/", .should_exist = false },
});
}

test "find definition self" {
try expectDefinition(
\\void main(int /*1*/whatever) {
Expand Down Expand Up @@ -885,11 +900,6 @@ fn expectDefinition(

if (print_source) {
std.debug.print("================\n{s}\n================\n", .{source});
const parsed = try document.parseTree();
std.debug.print(
"================\n{}\n================\n",
.{parsed.tree.format(document.source())},
);
}
}

Expand Down
7 changes: 7 additions & 0 deletions src/syntax.zig
Original file line number Diff line number Diff line change
Expand Up @@ -188,8 +188,15 @@ pub const ExpressionUnion = union(enum) {
identifier: Token(.identifier),
number: Token(.number),
array: ArraySpecifier(Expression),
selection: Selection,
};

pub const Selection = Extractor(.selection, struct {
target: Expression,
@".": Token(.@"."),
field: Token(.identifier),
});

pub fn Token(comptime tag: Tag) type {
comptime std.debug.assert(tag.isToken());
return struct {
Expand Down

0 comments on commit 91d7e2b

Please sign in to comment.