Optimize document symbols

This commit is contained in:
Alexandros Naskos 2020-07-07 11:57:02 +03:00
parent 3659a5c1a9
commit b61785eb3e
5 changed files with 76 additions and 40 deletions

View File

@ -2,6 +2,7 @@ const std = @import("std");
const DocumentStore = @import("document_store.zig"); const DocumentStore = @import("document_store.zig");
const ast = std.zig.ast; const ast = std.zig.ast;
const types = @import("types.zig"); const types = @import("types.zig");
const offsets = @import("offsets.zig");
/// Get a declaration's doc comment node /// Get a declaration's doc comment node
fn getDocCommentNode(tree: *ast.Tree, node: *ast.Node) ?*ast.Node.DocComment { fn getDocCommentNode(tree: *ast.Tree, node: *ast.Node) ?*ast.Node.DocComment {
@ -153,7 +154,6 @@ pub fn isTypeFunction(tree: *ast.Tree, func: *ast.Node.FnProto) bool {
} }
} }
// @TODO
pub fn isGenericFunction(tree: *ast.Tree, func: *ast.Node.FnProto) bool { pub fn isGenericFunction(tree: *ast.Tree, func: *ast.Node.FnProto) bool {
for (func.paramsConst()) |param| { for (func.paramsConst()) |param| {
if (param.param_type == .var_type or param.comptime_token != null) { if (param.param_type == .var_type or param.comptime_token != null) {
@ -1346,7 +1346,7 @@ pub fn documentPositionContext(arena: *std.heap.ArenaAllocator, document: types.
}; };
} }
fn addOutlineNodes(allocator: *std.mem.Allocator, children: *std.ArrayList(types.DocumentSymbol), tree: *ast.Tree, child: *ast.Node) anyerror!void { fn addOutlineNodes(allocator: *std.mem.Allocator, tree: *ast.Tree, child: *ast.Node, context: *GetDocumentSymbolsContext) anyerror!void {
switch (child.id) { switch (child.id) {
.StringLiteral, .IntegerLiteral, .BuiltinCall, .Call, .Identifier, .InfixOp, .PrefixOp, .SuffixOp, .ControlFlowExpression, .ArrayInitializerDot, .SwitchElse, .SwitchCase, .For, .EnumLiteral, .PointerIndexPayload, .StructInitializerDot, .PointerPayload, .While, .Switch, .Else, .BoolLiteral, .NullLiteral, .Defer, .StructInitializer, .FieldInitializer, .If, .MultilineStringLiteral, .UndefinedLiteral, .VarType, .Block, .ErrorSetDecl => return, .StringLiteral, .IntegerLiteral, .BuiltinCall, .Call, .Identifier, .InfixOp, .PrefixOp, .SuffixOp, .ControlFlowExpression, .ArrayInitializerDot, .SwitchElse, .SwitchCase, .For, .EnumLiteral, .PointerIndexPayload, .StructInitializerDot, .PointerPayload, .While, .Switch, .Else, .BoolLiteral, .NullLiteral, .Defer, .StructInitializer, .FieldInitializer, .If, .MultilineStringLiteral, .UndefinedLiteral, .VarType, .Block, .ErrorSetDecl => return,
@ -1354,18 +1354,36 @@ fn addOutlineNodes(allocator: *std.mem.Allocator, children: *std.ArrayList(types
const decl = child.cast(ast.Node.ContainerDecl).?; const decl = child.cast(ast.Node.ContainerDecl).?;
for (decl.fieldsAndDecls()) |cchild| for (decl.fieldsAndDecls()) |cchild|
try addOutlineNodes(allocator, children, tree, cchild); try addOutlineNodes(allocator, tree, cchild, context);
return; return;
}, },
else => {}, else => {},
} }
_ = try children.append(try getDocumentSymbolsInternal(allocator, tree, child)); try getDocumentSymbolsInternal(allocator, tree, child, context);
} }
fn getDocumentSymbolsInternal(allocator: *std.mem.Allocator, tree: *ast.Tree, node: *ast.Node) anyerror!types.DocumentSymbol { const GetDocumentSymbolsContext = struct {
// const symbols = std.ArrayList(types.DocumentSymbol).init(allocator); prev_loc: offsets.TokenLocation = .{
const start_loc = tree.tokenLocation(0, node.firstToken()); .line = 0,
const end_loc = tree.tokenLocation(0, node.lastToken()); .column = 0,
.offset = 0,
},
symbols: *std.ArrayList(types.DocumentSymbol),
encoding: offsets.Encoding,
};
fn getDocumentSymbolsInternal(allocator: *std.mem.Allocator, tree: *ast.Tree, node: *ast.Node, context: *GetDocumentSymbolsContext) anyerror!void {
const name = if (getDeclName(tree, node)) |name|
name
else
return;
if (name.len == 0)
return;
const start_loc = context.prev_loc.add(try offsets.tokenRelativeLocation(tree, context.prev_loc.offset, node.firstToken(), context.encoding));
const end_loc = start_loc.add(try offsets.tokenRelativeLocation(tree, start_loc.offset, node.lastToken(), context.encoding));
context.prev_loc = end_loc;
const range = types.Range{ const range = types.Range{
.start = .{ .start = .{
.line = @intCast(i64, start_loc.line), .line = @intCast(i64, start_loc.line),
@ -1377,23 +1395,8 @@ fn getDocumentSymbolsInternal(allocator: *std.mem.Allocator, tree: *ast.Tree, no
}, },
}; };
if (getDeclName(tree, node) == null) { (try context.symbols.addOne()).* = .{
std.log.debug(.analysis, "NULL NAME: {}\n", .{node.id}); .name = name,
}
const maybe_name = if (getDeclName(tree, node)) |name|
name
else
"";
// TODO: Get my lazy bum to fix detail newlines
return types.DocumentSymbol{
.name = if (maybe_name.len == 0) switch (node.id) {
.TestDecl => "Nameless Test",
else => "no_name",
} else maybe_name,
// .detail = (try getDocComments(allocator, tree, node)) orelse "",
.detail = "",
.kind = switch (node.id) { .kind = switch (node.id) {
.FnProto => .Function, .FnProto => .Function,
.VarDecl => .Variable, .VarDecl => .Variable,
@ -1402,26 +1405,36 @@ fn getDocumentSymbolsInternal(allocator: *std.mem.Allocator, tree: *ast.Tree, no
}, },
.range = range, .range = range,
.selectionRange = range, .selectionRange = range,
.detail = "",
.children = ch: { .children = ch: {
var children = std.ArrayList(types.DocumentSymbol).init(allocator); var children = std.ArrayList(types.DocumentSymbol).init(allocator);
var child_context = GetDocumentSymbolsContext{
.prev_loc = start_loc,
.symbols = &children,
.encoding = context.encoding,
};
var index: usize = 0; var index: usize = 0;
while (node.iterate(index)) |child| : (index += 1) { while (node.iterate(index)) |child| : (index += 1) {
try addOutlineNodes(allocator, &children, tree, child); try addOutlineNodes(allocator, tree, child, &child_context);
} }
break :ch children.items; break :ch children.items;
}, },
}; };
// return symbols.items;
} }
pub fn getDocumentSymbols(allocator: *std.mem.Allocator, tree: *ast.Tree) ![]types.DocumentSymbol { pub fn getDocumentSymbols(allocator: *std.mem.Allocator, tree: *ast.Tree, encoding: offsets.Encoding) ![]types.DocumentSymbol {
var symbols = std.ArrayList(types.DocumentSymbol).init(allocator); var symbols = try std.ArrayList(types.DocumentSymbol).initCapacity(allocator, tree.root_node.decls_len);
var context = GetDocumentSymbolsContext {
.symbols = &symbols,
.encoding = encoding,
};
for (tree.root_node.decls()) |node| { for (tree.root_node.decls()) |node| {
_ = try symbols.append(try getDocumentSymbolsInternal(allocator, tree, node)); try getDocumentSymbolsInternal(allocator, tree, node, &context);
} }
return symbols.items; return symbols.items;
@ -1462,9 +1475,9 @@ pub const DeclWithHandle = struct {
}; };
} }
pub fn location(self: DeclWithHandle) ast.Tree.Location { pub fn location(self: DeclWithHandle, encoding: offsets.Encoding) !offsets.TokenLocation {
const tree = self.handle.tree; const tree = self.handle.tree;
return tree.tokenLocation(0, self.nameToken()); return try offsets.tokenRelativeLocation(tree, 0, self.nameToken(), encoding);
} }
fn isPublic(self: DeclWithHandle) bool { fn isPublic(self: DeclWithHandle) bool {

View File

@ -99,7 +99,7 @@ pub fn init(base_allocator: *std.mem.Allocator, max_bytes: usize) DebugAllocator
}; };
} }
pub fn deinit(self: DebugAllocator) void { pub fn deinit(self: *DebugAllocator) void {
self.allocation_strack_addresses.deinit(); self.allocation_strack_addresses.deinit();
} }

View File

@ -483,15 +483,15 @@ fn gotoDefinitionSymbol(id: types.RequestId, arena: *std.heap.ArenaAllocator, de
if (resolve_alias) { if (resolve_alias) {
if (try analysis.resolveVarDeclAlias(&document_store, arena, .{ .node = node, .handle = handle })) |result| { if (try analysis.resolveVarDeclAlias(&document_store, arena, .{ .node = node, .handle = handle })) |result| {
handle = result.handle; handle = result.handle;
break :block result.location(); break :block result.location(offset_encoding) catch return;
} }
} }
const name_token = analysis.getDeclNameToken(handle.tree, node) orelse const name_token = analysis.getDeclNameToken(handle.tree, node) orelse
return try respondGeneric(id, null_result_response); return try respondGeneric(id, null_result_response);
break :block handle.tree.tokenLocation(0, name_token); break :block offsets.tokenRelativeLocation(handle.tree, 0, name_token, offset_encoding) catch return;
}, },
else => decl_handle.location(), else => decl_handle.location(offset_encoding) catch return,
}; };
try send(arena, types.Response{ try send(arena, types.Response{
@ -499,7 +499,16 @@ fn gotoDefinitionSymbol(id: types.RequestId, arena: *std.heap.ArenaAllocator, de
.result = .{ .result = .{
.Location = .{ .Location = .{
.uri = handle.document.uri, .uri = handle.document.uri,
.range = astLocationToRange(location), .range = .{
.start = .{
.line = @intCast(i64, location.line),
.character = @intCast(i64, location.column),
},
.end = .{
.line = @intCast(i64, location.line),
.character = @intCast(i64, location.column),
},
},
}, },
}, },
}); });
@ -907,7 +916,7 @@ fn completeFieldAccess(
fn documentSymbol(arena: *std.heap.ArenaAllocator, id: types.RequestId, handle: *DocumentStore.Handle) !void { fn documentSymbol(arena: *std.heap.ArenaAllocator, id: types.RequestId, handle: *DocumentStore.Handle) !void {
try send(arena, types.Response{ try send(arena, types.Response{
.id = id, .id = id,
.result = .{ .DocumentSymbols = try analysis.getDocumentSymbols(&arena.allocator, handle.tree) }, .result = .{ .DocumentSymbols = try analysis.getDocumentSymbols(&arena.allocator, handle.tree, offset_encoding) },
}); });
} }

View File

@ -56,6 +56,18 @@ pub fn documentPosition(doc: types.TextDocument, position: types.Position, encod
pub const TokenLocation = struct { pub const TokenLocation = struct {
line: usize, line: usize,
column: usize, column: usize,
offset: usize,
pub fn add(lhs: TokenLocation, rhs: TokenLocation) TokenLocation {
return .{
.line = lhs.line + rhs.line,
.column = if (rhs.line == 0)
lhs.column + rhs.column
else
rhs.column,
.offset = rhs.offset,
};
}
}; };
pub fn tokenRelativeLocation(tree: *std.zig.ast.Tree, start_index: usize, token: std.zig.ast.TokenIndex, encoding: Encoding) !TokenLocation { pub fn tokenRelativeLocation(tree: *std.zig.ast.Tree, start_index: usize, token: std.zig.ast.TokenIndex, encoding: Encoding) !TokenLocation {
@ -64,6 +76,7 @@ pub fn tokenRelativeLocation(tree: *std.zig.ast.Tree, start_index: usize, token:
var loc = TokenLocation{ var loc = TokenLocation{
.line = 0, .line = 0,
.column = 0, .column = 0,
.offset = 0,
}; };
const token_start = token_loc.start; const token_start = token_loc.start;
const source = tree.source[start_index..]; const source = tree.source[start_index..];
@ -90,6 +103,7 @@ pub fn tokenRelativeLocation(tree: *std.zig.ast.Tree, start_index: usize, token:
} }
} }
} }
loc.offset = i + start_index;
return loc; return loc;
} }

View File

@ -317,7 +317,7 @@ pub const DocumentSymbol = struct {
deprecated: bool = false, deprecated: bool = false,
range: Range, range: Range,
selectionRange: Range, selectionRange: Range,
children: []DocumentSymbol = &[_]DocumentSymbol{}, children: []const DocumentSymbol = &[_]DocumentSymbol{},
}; };
pub const ShowMessageParams = struct { pub const ShowMessageParams = struct {