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,
|
.colorProvider = false,
|
||||||
.documentFormattingProvider = true,
|
.documentFormattingProvider = true,
|
||||||
.documentRangeFormattingProvider = false,
|
.documentRangeFormattingProvider = false,
|
||||||
.foldingRangeProvider = false,
|
.foldingRangeProvider = true,
|
||||||
.selectionRangeProvider = false,
|
.selectionRangeProvider = false,
|
||||||
.workspaceSymbolProvider = false,
|
.workspaceSymbolProvider = false,
|
||||||
.rangeProvider = 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.
|
// Needed for the hack seen below.
|
||||||
fn extractErr(val: anytype) anyerror {
|
fn extractErr(val: anytype) anyerror {
|
||||||
val catch |e| return e;
|
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/documentHighlight", requests.DocumentHighlight, documentHighlightHandler },
|
||||||
.{ "textDocument/codeAction", requests.CodeAction, codeActionHandler },
|
.{ "textDocument/codeAction", requests.CodeAction, codeActionHandler },
|
||||||
.{ "workspace/didChangeConfiguration", Config.DidChangeConfigurationParams, didChangeConfigurationHandler },
|
.{ "workspace/didChangeConfiguration", Config.DidChangeConfigurationParams, didChangeConfigurationHandler },
|
||||||
|
.{ "textDocument/foldingRange", requests.FoldingRange, foldingRangeHandler }
|
||||||
};
|
};
|
||||||
|
|
||||||
if (zig_builtin.zig_backend == .stage1) {
|
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/rangeFormatting", true },
|
||||||
.{ "textDocument/onTypeFormatting", true },
|
.{ "textDocument/onTypeFormatting", true },
|
||||||
.{ "textDocument/prepareRename", true },
|
.{ "textDocument/prepareRename", true },
|
||||||
.{ "textDocument/foldingRange", true },
|
|
||||||
.{ "textDocument/selectionRange", true },
|
.{ "textDocument/selectionRange", true },
|
||||||
.{ "textDocument/semanticTokens/range", true },
|
.{ "textDocument/semanticTokens/range", true },
|
||||||
.{ "workspace/didChangeWorkspaceFolders", false },
|
.{ "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,
|
DocumentHighlight: []DocumentHighlight,
|
||||||
CodeAction: []CodeAction,
|
CodeAction: []CodeAction,
|
||||||
ApplyEdit: ApplyWorkspaceEditParams,
|
ApplyEdit: ApplyWorkspaceEditParams,
|
||||||
|
FoldingRange: []FoldingRange,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Response = struct {
|
pub const Response = struct {
|
||||||
@ -520,3 +521,8 @@ pub const DocumentHighlight = struct {
|
|||||||
range: Range,
|
range: Range,
|
||||||
kind: ?DocumentHighlightKind,
|
kind: ?DocumentHighlightKind,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const FoldingRange = struct {
|
||||||
|
startLine: usize,
|
||||||
|
endLine: usize,
|
||||||
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user