outlines, made JSON stdout memory dynamic

This commit is contained in:
SuperAuguste 2020-05-27 20:39:36 -04:00
parent 6fafceeb51
commit 2b153e046c
3 changed files with 167 additions and 8 deletions

View File

@ -1,6 +1,7 @@
const std = @import("std"); const std = @import("std");
const AnalysisContext = @import("document_store.zig").AnalysisContext; const AnalysisContext = @import("document_store.zig").AnalysisContext;
const ast = std.zig.ast; const ast = std.zig.ast;
const types = @import("types.zig");
/// REALLY BAD CODE, PLEASE DON'T USE THIS!!!!!!! (only for testing) /// REALLY BAD CODE, PLEASE DON'T USE THIS!!!!!!! (only for testing)
pub fn getFunctionByName(tree: *ast.Tree, name: []const u8) ?*ast.Node.FnProto { pub fn getFunctionByName(tree: *ast.Tree, name: []const u8) ?*ast.Node.FnProto {
@ -907,7 +908,6 @@ pub fn getImportStr(tree: *ast.Tree, source_index: usize) ?[]const u8 {
return null; return null;
} }
const types = @import("types.zig");
pub const SourceRange = std.zig.Token.Loc; pub const SourceRange = std.zig.Token.Loc;
pub const PositionContext = union(enum) { pub const PositionContext = union(enum) {
@ -1040,3 +1040,91 @@ pub fn documentPositionContext(allocator: *std.mem.Allocator, document: types.Te
break :block .empty; break :block .empty;
}; };
} }
fn addOutlineNodes(allocator: *std.mem.Allocator, children: *std.ArrayList(types.DocumentSymbol), tree: *ast.Tree, child: *ast.Node) anyerror!void {
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, .FnProto => return,
.ContainerDecl => {
const decl = child.cast(ast.Node.ContainerDecl).?;
for (decl.fieldsAndDecls()) |cchild|
try addOutlineNodes(allocator, children, tree, cchild);
// _ = try children.append(try getDocumentSymbolsInternal(allocator, tree, cchild));
return;
},
.Block => {
// const block = child.cast(ast.Node.Block).?;
// for (block.statements()) |cchild|
// try addOutlineNodes(allocator, children, tree, cchild);
// _ = try children.append(try getDocumentSymbolsInternal(allocator, tree, cchild));
return;
},
else => {}
}
std.debug.warn("{}\n", .{child.id});
_ = try children.append(try getDocumentSymbolsInternal(allocator, tree, child));
}
fn getDocumentSymbolsInternal(allocator: *std.mem.Allocator, tree: *ast.Tree, node: *ast.Node) anyerror!types.DocumentSymbol {
// const symbols = std.ArrayList(types.DocumentSymbol).init(allocator);
const start_loc = tree.tokenLocation(0, node.firstToken());
const end_loc = tree.tokenLocation(0, node.lastToken());
const range = types.Range{
.start = .{
.line = @intCast(i64, start_loc.line),
.character = @intCast(i64, start_loc.column),
},
.end = .{
.line = @intCast(i64, end_loc.line),
.character = @intCast(i64, end_loc.column),
}
};
if (getDeclName(tree, node) == null) {
std.debug.warn("NULL NAME: {}\n", .{node.id});
}
// TODO: Get my lazy bum to fix detail newlines
return types.DocumentSymbol{
.name = getDeclName(tree, node) orelse "no_name",
// .detail = (try getDocComments(allocator, tree, node)) orelse "",
.detail = "",
.kind = switch (node.id) {
.FnProto => .Function,
.VarDecl => .Variable,
.ContainerField => .Field,
else => .Variable
},
.range = range,
.selectionRange = range,
.children = ch: {
var children = std.ArrayList(types.DocumentSymbol).init(allocator);
var index: usize = 0;
while (node.iterate(index)) |child| : (index += 1) {
try addOutlineNodes(allocator, &children, tree, child);
}
break :ch children.items;
},
};
// return symbols.items;
}
pub fn getDocumentSymbols(allocator: *std.mem.Allocator, tree: *ast.Tree) ![]types.DocumentSymbol {
var symbols = std.ArrayList(types.DocumentSymbol).init(allocator);
for (tree.root_node.decls()) |node| {
_ = try symbols.append(try getDocumentSymbolsInternal(allocator, tree, node));
}
return symbols.items;
}

View File

@ -19,7 +19,7 @@ var document_store: DocumentStore = undefined;
var workspace_folder_configs: std.StringHashMap(?Config) = undefined; var workspace_folder_configs: std.StringHashMap(?Config) = undefined;
const initialize_response = const initialize_response =
\\,"result":{"capabilities":{"signatureHelpProvider":{"triggerCharacters":["(",","]},"textDocumentSync":1,"completionProvider":{"resolveProvider":false,"triggerCharacters":[".",":","@"]},"documentHighlightProvider":false,"hoverProvider":true,"codeActionProvider":false,"declarationProvider":true,"definitionProvider":true,"typeDefinitionProvider":true,"implementationProvider":false,"referencesProvider":false,"documentSymbolProvider":false,"colorProvider":false,"documentFormattingProvider":false,"documentRangeFormattingProvider":false,"foldingRangeProvider":false,"selectionRangeProvider":false,"workspaceSymbolProvider":false,"workspace":{"workspaceFolders":{"supported":true,"changeNotifications":true}}}}} \\,"result":{"capabilities":{"signatureHelpProvider":{"triggerCharacters":["(",","]},"textDocumentSync":1,"completionProvider":{"resolveProvider":false,"triggerCharacters":[".",":","@"]},"documentHighlightProvider":false,"hoverProvider":true,"codeActionProvider":false,"declarationProvider":true,"definitionProvider":true,"typeDefinitionProvider":true,"implementationProvider":false,"referencesProvider":false,"documentSymbolProvider":true,"colorProvider":false,"documentFormattingProvider":false,"documentRangeFormattingProvider":false,"foldingRangeProvider":false,"selectionRangeProvider":false,"workspaceSymbolProvider":false,"workspace":{"workspaceFolders":{"supported":true,"changeNotifications":true}}}}}
; ;
const not_implemented_response = const not_implemented_response =
@ -44,14 +44,15 @@ const no_completions_response =
/// Sends a request or response /// Sends a request or response
fn send(reqOrRes: var) !void { fn send(reqOrRes: var) !void {
// The most memory we'll probably need var arena = std.heap.ArenaAllocator.init(allocator);
var mem_buffer: [1024 * 128]u8 = undefined; defer arena.deinit();
var fbs = std.io.fixedBufferStream(&mem_buffer);
try std.json.stringify(reqOrRes, std.json.StringifyOptions{}, fbs.outStream()); var arr = std.ArrayList(u8).init(&arena.allocator);
try std.json.stringify(reqOrRes, std.json.StringifyOptions{}, arr.outStream());
const stdout_stream = stdout.outStream(); const stdout_stream = stdout.outStream();
try stdout_stream.print("Content-Length: {}\r\n\r\n", .{fbs.pos}); try stdout_stream.print("Content-Length: {}\r\n\r\n", .{arr.items.len});
try stdout_stream.writeAll(fbs.getWritten()); try stdout_stream.writeAll(arr.items);
try stdout.flush(); try stdout.flush();
} }
@ -526,6 +527,18 @@ fn completeFieldAccess(id: i64, handle: *DocumentStore.Handle, position: types.P
}); });
} }
fn documentSymbol(id: i64, handle: *DocumentStore.Handle) !void {
var arena = std.heap.ArenaAllocator.init(allocator);
defer arena.deinit();
try send(types.Response{
.id = .{ .Integer = id },
.result = .{
.DocumentSymbols = try analysis.getDocumentSymbols(&arena.allocator, handle.tree)
},
});
}
// Compute builtin completions at comptime. // Compute builtin completions at comptime.
const builtin_completions = block: { const builtin_completions = block: {
@setEvalBranchQuota(3_500); @setEvalBranchQuota(3_500);
@ -834,6 +847,16 @@ fn processJsonRpc(parser: *std.json.Parser, json: []const u8, config: Config) !v
} else { } else {
try respondGeneric(id, null_result_response); try respondGeneric(id, null_result_response);
} }
} else if (std.mem.eql(u8, method, "textDocument/documentSymbol")) {
const document = params.getValue("textDocument").?.Object;
const uri = document.getValue("uri").?.String;
const handle = document_store.getHandle(uri) orelse {
std.debug.warn("Trying to got to definition in non existent document {}", .{uri});
return try respondGeneric(id, null_result_response);
};
try documentSymbol(id, handle);
} else if (root.Object.getValue("id")) |_| { } else if (root.Object.getValue("id")) |_| {
std.debug.warn("Method with return value not implemented: {}", .{method}); std.debug.warn("Method with return value not implemented: {}", .{method});
try respondGeneric(id, not_implemented_response); try respondGeneric(id, not_implemented_response);

View File

@ -62,6 +62,7 @@ pub const ResponseParams = union(enum) {
CompletionList: CompletionList, CompletionList: CompletionList,
Location: Location, Location: Location,
Hover: Hover, Hover: Hover,
DocumentSymbols: []DocumentSymbol
}; };
/// JSONRPC error /// JSONRPC error
@ -292,3 +293,50 @@ pub const CompletionItem = struct {
documentation: ?MarkupContent = null documentation: ?MarkupContent = null
// filterText: String = .NotDefined, // filterText: String = .NotDefined,
}; };
const SymbolKind = enum {
File = 1,
Module = 2,
Namespace = 3,
Package = 4,
Class = 5,
Method = 6,
Property = 7,
Field = 8,
Constructor = 9,
Enum = 10,
Interface = 11,
Function = 12,
Variable = 13,
Constant = 14,
String = 15,
Number = 16,
Boolean = 17,
Array = 18,
Object = 19,
Key = 20,
Null = 21,
EnumMember = 22,
Struct = 23,
Event = 24,
Operator = 25,
TypeParameter = 26,
pub fn jsonStringify(
value: SymbolKind,
options: json.StringifyOptions,
out_stream: var,
) !void {
try json.stringify(@enumToInt(value), options, out_stream);
}
};
pub const DocumentSymbol = struct {
name: []const u8,
detail: ?[]const u8 = null,
kind: SymbolKind,
deprecated: bool = false,
range: Range,
selectionRange: Range,
children: []DocumentSymbol = &[_]DocumentSymbol{}
};