...
This commit is contained in:
@@ -493,12 +493,75 @@ pub const Server = struct {
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Bare dot (no prefix) — check if we're inside a match expression
|
||||
// and offer the subject's enum variants (e.g. case .quit)
|
||||
try self.collectMatchEnumCompletions(&items, doc, cursor_offset);
|
||||
}
|
||||
|
||||
const items_json = try lsp.completionListJson(self.allocator, items.items);
|
||||
try self.sendResponse(id_json, items_json);
|
||||
}
|
||||
|
||||
fn collectMatchEnumCompletions(self: *Server, items: *std.ArrayList(lsp.CompletionItem), doc: *const Document, cursor_offset: u32) !void {
|
||||
const root = doc.root orelse return;
|
||||
const sema = doc.sema orelse return;
|
||||
|
||||
// Find enclosing match expression's subject
|
||||
const subject = sx.sema.findEnclosingMatchSubject(root, cursor_offset) orelse return;
|
||||
|
||||
// Resolve the subject to an enum type name
|
||||
const enum_name: ?[]const u8 = switch (subject.data) {
|
||||
.identifier => |id| blk: {
|
||||
// Look up variable type, then check if it's an enum
|
||||
for (sema.symbols) |sym| {
|
||||
if (!std.mem.eql(u8, sym.name, id.name)) continue;
|
||||
if (sym.kind != .variable and sym.kind != .param) continue;
|
||||
const ty = sym.ty orelse break;
|
||||
break :blk switch (ty) {
|
||||
.enum_type => |n| n,
|
||||
.union_type => |n| n,
|
||||
else => null,
|
||||
};
|
||||
}
|
||||
break :blk null;
|
||||
},
|
||||
.field_access => |fa| blk: {
|
||||
// e.g. e.key — resolve the field's type
|
||||
if (fa.object.data == .identifier) {
|
||||
const var_name = fa.object.data.identifier.name;
|
||||
// Find variable's struct type, then look up the field type
|
||||
for (sema.symbols) |sym| {
|
||||
if (!std.mem.eql(u8, sym.name, var_name)) continue;
|
||||
const ty = sym.ty orelse break;
|
||||
const struct_name = switch (ty) {
|
||||
.struct_type => |n| n,
|
||||
else => break,
|
||||
};
|
||||
// Look up the struct's field type
|
||||
if (sema.struct_types.get(struct_name)) |info| {
|
||||
for (info.field_names, 0..) |fname, fi| {
|
||||
if (std.mem.eql(u8, fname, fa.field) and fi < info.field_types.len) {
|
||||
break :blk switch (info.field_types[fi]) {
|
||||
.enum_type => |n| n,
|
||||
.union_type => |n| n,
|
||||
else => null,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break :blk null;
|
||||
},
|
||||
else => null,
|
||||
};
|
||||
|
||||
const name = enum_name orelse return;
|
||||
try self.collectMemberCompletions(items, sema, root, name);
|
||||
}
|
||||
|
||||
fn collectDeclCompletions(allocator: std.mem.Allocator, items: *std.ArrayList(lsp.CompletionItem), decls: []const *sx.ast.Node) !void {
|
||||
for (decls) |decl| {
|
||||
switch (decl.data) {
|
||||
@@ -1643,6 +1706,33 @@ pub const Server = struct {
|
||||
if (bt.data == .type_expr) {
|
||||
try buf.appendSlice(allocator, bt.data.type_expr.name);
|
||||
try buf.appendSlice(allocator, " ");
|
||||
} else if (bt.data == .struct_decl) {
|
||||
const sd = bt.data.struct_decl;
|
||||
try buf.appendSlice(allocator, "struct { ");
|
||||
for (sd.field_names, 0..) |fn_, fi| {
|
||||
if (fi > 0) try buf.appendSlice(allocator, "; ");
|
||||
try buf.appendSlice(allocator, fn_);
|
||||
try buf.appendSlice(allocator, ": ");
|
||||
if (fi < sd.field_types.len) {
|
||||
if (sd.field_types[fi].data == .type_expr) {
|
||||
try buf.appendSlice(allocator, sd.field_types[fi].data.type_expr.name);
|
||||
} else if (sd.field_types[fi].data == .array_type_expr) {
|
||||
const ate = sd.field_types[fi].data.array_type_expr;
|
||||
try buf.append(allocator, '[');
|
||||
if (ate.length.data == .int_literal) {
|
||||
const val = ate.length.data.int_literal.value;
|
||||
var num_buf: [20]u8 = undefined;
|
||||
const num_str = std.fmt.bufPrint(&num_buf, "{d}", .{val}) catch "?";
|
||||
try buf.appendSlice(allocator, num_str);
|
||||
}
|
||||
try buf.append(allocator, ']');
|
||||
if (ate.element_type.data == .type_expr) {
|
||||
try buf.appendSlice(allocator, ate.element_type.data.type_expr.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
try buf.appendSlice(allocator, " } ");
|
||||
}
|
||||
}
|
||||
try buf.appendSlice(allocator, "{ ");
|
||||
|
||||
Reference in New Issue
Block a user