Added textDocument/foldingRange (#718)
* Added textDocument/foldingRange * Added support for code regions * Fixed warning message in foldingRangeHandler Co-authored-by: LucaSas <sas.luca.alex@gmail.com>
This commit is contained in:
parent
5ddbf24d11
commit
2a17590bf4
@ -1574,7 +1574,7 @@ fn initializeHandler(server: *Server, writer: anytype, id: types.RequestId, req:
|
||||
.colorProvider = false,
|
||||
.documentFormattingProvider = true,
|
||||
.documentRangeFormattingProvider = false,
|
||||
.foldingRangeProvider = false,
|
||||
.foldingRangeProvider = true,
|
||||
.selectionRangeProvider = false,
|
||||
.workspaceSymbolProvider = false,
|
||||
.rangeProvider = false,
|
||||
@ -2339,6 +2339,89 @@ fn codeActionHandler(server: *Server, writer: anytype, id: types.RequestId, req:
|
||||
});
|
||||
}
|
||||
|
||||
fn foldingRangeHandler(server: *Server, writer: anytype, id: types.RequestId, req: requests.FoldingRange) !void
|
||||
{
|
||||
const Tag = std.zig.Token.Tag;
|
||||
const allocator = server.arena.allocator();
|
||||
const handle = server.document_store.getHandle(req.params.textDocument.uri) orelse {
|
||||
log.warn("Trying to get folding ranges of non existent document {s}", .{req.params.textDocument.uri});
|
||||
return try respondGeneric(writer, id, null_result_response);
|
||||
};
|
||||
|
||||
// Used to store the result
|
||||
var ranges = std.ArrayList(types.FoldingRange).init(allocator);
|
||||
|
||||
// We add opened curly braces to a stack as we go and pop one off when we find a closing brace.
|
||||
// As an optimization we start with a capacity of 10 which should work well in most cases since
|
||||
// people will almost never have more than 10 levels deep of nested braces.
|
||||
var stack = try std.ArrayList(usize).initCapacity(allocator, 10);
|
||||
|
||||
// Iterate over the token tags and look for pairs of braces
|
||||
for (handle.tree.tokens.items(.tag)) |tag, i| {
|
||||
const token_index = @intCast(Ast.TokenIndex, i);
|
||||
|
||||
// If we found a `{` we add it to our stack
|
||||
if (tag == Tag.l_brace) {
|
||||
const line = handle.tree.tokenLocation(0, token_index).line;
|
||||
try stack.append(line);
|
||||
}
|
||||
|
||||
// If we found a close `}` we have a matching pair
|
||||
if (tag == Tag.r_brace and stack.items.len > 0) {
|
||||
const start_line = stack.pop();
|
||||
const end_line = handle.tree.tokenLocation(0, token_index).line;
|
||||
|
||||
// Add brace pairs but discard those from the same line, no need to waste memory on them
|
||||
if (start_line != end_line)
|
||||
{
|
||||
try ranges.append(.{
|
||||
.startLine = start_line,
|
||||
.endLine = end_line,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Iterate over the source code and look for code regions with #region #endregion
|
||||
{
|
||||
// We will reuse the stack
|
||||
stack.clearRetainingCapacity();
|
||||
|
||||
var i: usize = 0;
|
||||
var lines_count: usize = 0;
|
||||
while (i < handle.tree.source.len) : (i += 1) {
|
||||
const slice = handle.tree.source[i..];
|
||||
|
||||
if (slice[0] == '\n') {
|
||||
lines_count += 1;
|
||||
}
|
||||
|
||||
if (std.mem.startsWith(u8, slice, "//#region")) {
|
||||
try stack.append(lines_count);
|
||||
}
|
||||
|
||||
if (std.mem.startsWith(u8, slice, "//#endregion") and stack.items.len > 0) {
|
||||
const start_line = stack.pop();
|
||||
const end_line = lines_count;
|
||||
|
||||
// Add brace pairs but discard those from the same line, no need to waste memory on them
|
||||
if (start_line != end_line)
|
||||
{
|
||||
try ranges.append(.{
|
||||
.startLine = start_line,
|
||||
.endLine = end_line,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try send(writer, allocator, types.Response {
|
||||
.id = id,
|
||||
.result = .{ .FoldingRange = ranges.items },
|
||||
});
|
||||
}
|
||||
|
||||
// Needed for the hack seen below.
|
||||
fn extractErr(val: anytype) anyerror {
|
||||
val catch |e| return e;
|
||||
@ -2475,6 +2558,7 @@ pub fn processJsonRpc(server: *Server, writer: anytype, json: []const u8) !void
|
||||
.{ "textDocument/documentHighlight", requests.DocumentHighlight, documentHighlightHandler },
|
||||
.{ "textDocument/codeAction", requests.CodeAction, codeActionHandler },
|
||||
.{ "workspace/didChangeConfiguration", Config.DidChangeConfigurationParams, didChangeConfigurationHandler },
|
||||
.{ "textDocument/foldingRange", requests.FoldingRange, foldingRangeHandler }
|
||||
};
|
||||
|
||||
if (zig_builtin.zig_backend == .stage1) {
|
||||
@ -2539,7 +2623,6 @@ pub fn processJsonRpc(server: *Server, writer: anytype, json: []const u8) !void
|
||||
.{ "textDocument/rangeFormatting", true },
|
||||
.{ "textDocument/onTypeFormatting", true },
|
||||
.{ "textDocument/prepareRename", true },
|
||||
.{ "textDocument/foldingRange", true },
|
||||
.{ "textDocument/selectionRange", true },
|
||||
.{ "textDocument/semanticTokens/range", true },
|
||||
.{ "workspace/didChangeWorkspaceFolders", false },
|
||||
|
@ -288,3 +288,9 @@ pub const CodeAction = struct {
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
pub const FoldingRange = struct {
|
||||
params: struct {
|
||||
textDocument: TextDocumentIdentifier,
|
||||
},
|
||||
};
|
@ -43,6 +43,7 @@ pub const ResponseParams = union(enum) {
|
||||
DocumentHighlight: []DocumentHighlight,
|
||||
CodeAction: []CodeAction,
|
||||
ApplyEdit: ApplyWorkspaceEditParams,
|
||||
FoldingRange: []FoldingRange,
|
||||
};
|
||||
|
||||
pub const Response = struct {
|
||||
@ -520,3 +521,8 @@ pub const DocumentHighlight = struct {
|
||||
range: Range,
|
||||
kind: ?DocumentHighlightKind,
|
||||
};
|
||||
|
||||
pub const FoldingRange = struct {
|
||||
startLine: usize,
|
||||
endLine: usize,
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user