outlines, made JSON stdout memory dynamic
This commit is contained in:
parent
6fafceeb51
commit
2b153e046c
@ -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;
|
||||||
|
}
|
||||||
|
37
src/main.zig
37
src/main.zig
@ -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);
|
||||||
|
@ -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{}
|
||||||
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user