remove types.TextDocument (#693)
* remove types.TextDocument * resolve compile errors because of previous merge
This commit is contained in:
parent
a8fa5c68a7
commit
a9a1fad13e
@ -1,6 +1,7 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
const types = @import("types.zig");
|
const types = @import("types.zig");
|
||||||
|
const requests = @import("requests.zig");
|
||||||
const URI = @import("uri.zig");
|
const URI = @import("uri.zig");
|
||||||
const analysis = @import("analysis.zig");
|
const analysis = @import("analysis.zig");
|
||||||
const offsets = @import("offsets.zig");
|
const offsets = @import("offsets.zig");
|
||||||
@ -62,23 +63,20 @@ pub const BuildFileConfig = struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub const Handle = struct {
|
pub const Handle = struct {
|
||||||
document: types.TextDocument,
|
|
||||||
count: usize,
|
count: usize,
|
||||||
|
uri: []const u8,
|
||||||
|
text: [:0]const u8,
|
||||||
|
tree: Ast,
|
||||||
|
document_scope: analysis.DocumentScope,
|
||||||
/// Contains one entry for every import in the document
|
/// Contains one entry for every import in the document
|
||||||
import_uris: []const []const u8,
|
import_uris: []const []const u8,
|
||||||
/// Contains one entry for every cimport in the document
|
/// Contains one entry for every cimport in the document
|
||||||
cimports: []CImportHandle,
|
cimports: []CImportHandle,
|
||||||
/// Items in this array list come from `import_uris` and `cimports`
|
/// Items in this array list come from `import_uris` and `cimports`
|
||||||
imports_used: std.ArrayListUnmanaged([]const u8),
|
imports_used: std.ArrayListUnmanaged([]const u8),
|
||||||
tree: Ast,
|
|
||||||
document_scope: analysis.DocumentScope,
|
|
||||||
|
|
||||||
associated_build_file: ?*BuildFile,
|
associated_build_file: ?*BuildFile,
|
||||||
is_build_file: ?*BuildFile,
|
is_build_file: ?*BuildFile,
|
||||||
|
|
||||||
pub fn uri(handle: Handle) []const u8 {
|
|
||||||
return handle.document.uri;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const UriToHandleMap = std.StringHashMapUnmanaged(*Handle);
|
pub const UriToHandleMap = std.StringHashMapUnmanaged(*Handle);
|
||||||
@ -462,9 +460,9 @@ fn newDocument(self: *DocumentStore, uri: []const u8, text: [:0]u8) anyerror!*Ha
|
|||||||
|
|
||||||
defer {
|
defer {
|
||||||
if (handle.associated_build_file) |build_file| {
|
if (handle.associated_build_file) |build_file| {
|
||||||
log.debug("Opened document `{s}` with build file `{s}`", .{ handle.uri(), build_file.uri });
|
log.debug("Opened document `{s}` with build file `{s}`", .{ handle.uri, build_file.uri });
|
||||||
} else {
|
} else {
|
||||||
log.debug("Opened document `{s}` without a build file", .{handle.uri()});
|
log.debug("Opened document `{s}` without a build file", .{handle.uri});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -476,17 +474,13 @@ fn newDocument(self: *DocumentStore, uri: []const u8, text: [:0]u8) anyerror!*Ha
|
|||||||
|
|
||||||
handle.* = Handle{
|
handle.* = Handle{
|
||||||
.count = 1,
|
.count = 1,
|
||||||
|
.uri = uri,
|
||||||
|
.text = text,
|
||||||
|
.tree = tree,
|
||||||
|
.document_scope = document_scope,
|
||||||
.import_uris = &.{},
|
.import_uris = &.{},
|
||||||
.cimports = &.{},
|
.cimports = &.{},
|
||||||
.imports_used = .{},
|
.imports_used = .{},
|
||||||
.document = .{
|
|
||||||
.uri = uri,
|
|
||||||
.text = text,
|
|
||||||
// Extra +1 to include the null terminator
|
|
||||||
.mem = text.ptr[0 .. text.len + 1],
|
|
||||||
},
|
|
||||||
.tree = tree,
|
|
||||||
.document_scope = document_scope,
|
|
||||||
.associated_build_file = null,
|
.associated_build_file = null,
|
||||||
.is_build_file = null,
|
.is_build_file = null,
|
||||||
};
|
};
|
||||||
@ -648,7 +642,7 @@ fn decrementCount(self: *DocumentStore, uri: []const u8) void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handle.tree.deinit(self.allocator);
|
handle.tree.deinit(self.allocator);
|
||||||
self.allocator.free(handle.document.mem);
|
self.allocator.free(handle.text);
|
||||||
|
|
||||||
for (handle.imports_used.items) |import_uri| {
|
for (handle.imports_used.items) |import_uri| {
|
||||||
self.decrementCount(import_uri);
|
self.decrementCount(import_uri);
|
||||||
@ -819,9 +813,9 @@ fn translate(self: *DocumentStore, handle: *Handle, source: []const u8) error{Ou
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn refreshDocument(self: *DocumentStore, handle: *Handle) !void {
|
fn refreshDocument(self: *DocumentStore, handle: *Handle) !void {
|
||||||
log.debug("New text for document {s}", .{handle.uri()});
|
log.debug("New text for document {s}", .{handle.uri});
|
||||||
handle.tree.deinit(self.allocator);
|
handle.tree.deinit(self.allocator);
|
||||||
handle.tree = try std.zig.parse(self.allocator, handle.document.text);
|
handle.tree = try std.zig.parse(self.allocator, handle.text);
|
||||||
|
|
||||||
handle.document_scope.deinit(self.allocator);
|
handle.document_scope.deinit(self.allocator);
|
||||||
handle.document_scope = try analysis.makeDocumentScope(self.allocator, handle.tree);
|
handle.document_scope = try analysis.makeDocumentScope(self.allocator, handle.tree);
|
||||||
@ -946,70 +940,41 @@ pub fn applySave(self: *DocumentStore, handle: *Handle) !void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn applyChanges(self: *DocumentStore, handle: *Handle, content_changes: std.json.Array, offset_encoding: offsets.Encoding) !void {
|
pub fn applyChanges(
|
||||||
const document = &handle.document;
|
self: *DocumentStore,
|
||||||
|
handle: *Handle,
|
||||||
for (content_changes.items) |change| {
|
content_changes: []const requests.TextDocumentContentChangeEvent,
|
||||||
if (change.Object.get("range")) |range| {
|
encoding: offsets.Encoding,
|
||||||
std.debug.assert(@ptrCast([*]const u8, document.text.ptr) == document.mem.ptr);
|
) !void {
|
||||||
|
var last_full_text_change: ?usize = null;
|
||||||
// TODO: add tests and validate the JSON
|
var i: usize = content_changes.len;
|
||||||
const start_obj = range.Object.get("start").?.Object;
|
while (i > 0) {
|
||||||
const start_pos = types.Position{
|
i -= 1;
|
||||||
.line = @intCast(u32, start_obj.get("line").?.Integer),
|
if (content_changes[i].range == null) {
|
||||||
.character = @intCast(u32, start_obj.get("character").?.Integer),
|
last_full_text_change = i;
|
||||||
};
|
|
||||||
const end_obj = range.Object.get("end").?.Object;
|
|
||||||
const end_pos = types.Position{
|
|
||||||
.line = @intCast(u32, end_obj.get("line").?.Integer),
|
|
||||||
.character = @intCast(u32, end_obj.get("character").?.Integer),
|
|
||||||
};
|
|
||||||
|
|
||||||
const change_text = change.Object.get("text").?.String;
|
|
||||||
const start_index = offsets.positionToIndex(document.text, start_pos, offset_encoding);
|
|
||||||
const end_index = offsets.positionToIndex(document.text, end_pos, offset_encoding);
|
|
||||||
|
|
||||||
const old_len = document.text.len;
|
|
||||||
const new_len = old_len - (end_index - start_index) + change_text.len;
|
|
||||||
if (new_len >= document.mem.len) {
|
|
||||||
// We need to reallocate memory.
|
|
||||||
// We reallocate twice the current filesize or the new length, if it's more than that
|
|
||||||
// so that we can reduce the amount of realloc calls.
|
|
||||||
// We can tune this to find a better size if needed.
|
|
||||||
const realloc_len = std.math.max(2 * old_len, new_len + 1);
|
|
||||||
document.mem = try self.allocator.realloc(document.mem, realloc_len);
|
|
||||||
}
|
|
||||||
|
|
||||||
// The first part of the string, [0 .. start_index] need not be changed.
|
|
||||||
// We then copy the last part of the string, [end_index ..] to its
|
|
||||||
// new position, [start_index + change_len .. ]
|
|
||||||
if (new_len < old_len) {
|
|
||||||
std.mem.copy(u8, document.mem[start_index + change_text.len ..][0 .. old_len - end_index], document.mem[end_index..old_len]);
|
|
||||||
} else {
|
|
||||||
std.mem.copyBackwards(u8, document.mem[start_index + change_text.len ..][0 .. old_len - end_index], document.mem[end_index..old_len]);
|
|
||||||
}
|
|
||||||
// Finally, we copy the changes over.
|
|
||||||
std.mem.copy(u8, document.mem[start_index..][0..change_text.len], change_text);
|
|
||||||
|
|
||||||
// Reset the text substring.
|
|
||||||
document.mem[new_len] = 0;
|
|
||||||
document.text = document.mem[0..new_len :0];
|
|
||||||
} else {
|
|
||||||
const change_text = change.Object.get("text").?.String;
|
|
||||||
const old_len = document.text.len;
|
|
||||||
|
|
||||||
if (change_text.len >= document.mem.len) {
|
|
||||||
// Like above.
|
|
||||||
const realloc_len = std.math.max(2 * old_len, change_text.len + 1);
|
|
||||||
document.mem = try self.allocator.realloc(document.mem, realloc_len);
|
|
||||||
}
|
|
||||||
|
|
||||||
std.mem.copy(u8, document.mem[0..change_text.len], change_text);
|
|
||||||
document.mem[change_text.len] = 0;
|
|
||||||
document.text = document.mem[0..change_text.len :0];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var text_array = std.ArrayListUnmanaged(u8){};
|
||||||
|
errdefer text_array.deinit(self.allocator);
|
||||||
|
|
||||||
|
try text_array.appendSlice(self.allocator, if (last_full_text_change) |index| content_changes[index].text else handle.text);
|
||||||
|
|
||||||
|
// don't even bother applying changes before a full text change
|
||||||
|
const changes = content_changes[if (last_full_text_change) |index| index + 1 else 0..];
|
||||||
|
|
||||||
|
for (changes) |item| {
|
||||||
|
const range = item.range.?; // every element is guaranteed to have `range` set
|
||||||
|
const text = item.text;
|
||||||
|
|
||||||
|
const loc = offsets.rangeToLoc(text_array.items, range, encoding);
|
||||||
|
try text_array.replaceRange(self.allocator, loc.start, loc.end - loc.start, text);
|
||||||
|
}
|
||||||
|
|
||||||
|
const new_text = try text_array.toOwnedSliceSentinel(self.allocator, 0);
|
||||||
|
self.allocator.free(handle.text);
|
||||||
|
handle.text = new_text;
|
||||||
|
|
||||||
try self.refreshDocument(handle);
|
try self.refreshDocument(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1039,7 +1004,7 @@ pub fn uriFromImportStr(self: *DocumentStore, allocator: std.mem.Allocator, hand
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
} else {
|
} else {
|
||||||
const base = handle.uri();
|
const base = handle.uri;
|
||||||
var base_len = base.len;
|
var base_len = base.len;
|
||||||
while (base[base_len - 1] != '/' and base_len > 0) {
|
while (base[base_len - 1] != '/' and base_len > 0) {
|
||||||
base_len -= 1;
|
base_len -= 1;
|
||||||
@ -1188,7 +1153,7 @@ pub fn deinit(self: *DocumentStore) void {
|
|||||||
while (entry_iterator.next()) |entry| {
|
while (entry_iterator.next()) |entry| {
|
||||||
entry.value_ptr.*.document_scope.deinit(self.allocator);
|
entry.value_ptr.*.document_scope.deinit(self.allocator);
|
||||||
entry.value_ptr.*.tree.deinit(self.allocator);
|
entry.value_ptr.*.tree.deinit(self.allocator);
|
||||||
self.allocator.free(entry.value_ptr.*.document.mem);
|
self.allocator.free(entry.value_ptr.*.text);
|
||||||
for (entry.value_ptr.*.import_uris) |uri| {
|
for (entry.value_ptr.*.import_uris) |uri| {
|
||||||
self.allocator.free(uri);
|
self.allocator.free(uri);
|
||||||
}
|
}
|
||||||
|
@ -274,7 +274,7 @@ fn publishDiagnostics(server: *Server, writer: anytype, handle: *DocumentStore.H
|
|||||||
.method = "textDocument/publishDiagnostics",
|
.method = "textDocument/publishDiagnostics",
|
||||||
.params = .{
|
.params = .{
|
||||||
.PublishDiagnostics = .{
|
.PublishDiagnostics = .{
|
||||||
.uri = handle.uri(),
|
.uri = handle.uri,
|
||||||
.diagnostics = diagnostics.items,
|
.diagnostics = diagnostics.items,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -298,7 +298,7 @@ fn getAstCheckDiagnostics(
|
|||||||
log.warn("Failed to spawn zig ast-check process, error: {}", .{err});
|
log.warn("Failed to spawn zig ast-check process, error: {}", .{err});
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
try process.stdin.?.writeAll(handle.document.text);
|
try process.stdin.?.writeAll(handle.text);
|
||||||
process.stdin.?.close();
|
process.stdin.?.close();
|
||||||
|
|
||||||
process.stdin = null;
|
process.stdin = null;
|
||||||
@ -329,8 +329,8 @@ fn getAstCheckDiagnostics(
|
|||||||
};
|
};
|
||||||
|
|
||||||
// zig uses utf-8 encoding for character offsets
|
// zig uses utf-8 encoding for character offsets
|
||||||
const position = offsets.convertPositionEncoding(handle.document.text, utf8_position, .utf8, server.offset_encoding);
|
const position = offsets.convertPositionEncoding(handle.text, utf8_position, .utf8, server.offset_encoding);
|
||||||
const range = offsets.tokenPositionToRange(handle.document.text, position, server.offset_encoding);
|
const range = offsets.tokenPositionToRange(handle.text, position, server.offset_encoding);
|
||||||
|
|
||||||
const msg = pos_and_diag_iterator.rest()[1..];
|
const msg = pos_and_diag_iterator.rest()[1..];
|
||||||
|
|
||||||
@ -351,7 +351,7 @@ fn getAstCheckDiagnostics(
|
|||||||
try server.arena.allocator().alloc(types.DiagnosticRelatedInformation, 1);
|
try server.arena.allocator().alloc(types.DiagnosticRelatedInformation, 1);
|
||||||
|
|
||||||
const location = types.Location{
|
const location = types.Location{
|
||||||
.uri = handle.uri(),
|
.uri = handle.uri,
|
||||||
.range = range,
|
.range = range,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -645,22 +645,20 @@ fn nodeToCompletion(
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn identifierFromPosition(pos_index: usize, handle: DocumentStore.Handle) []const u8 {
|
pub fn identifierFromPosition(pos_index: usize, handle: DocumentStore.Handle) []const u8 {
|
||||||
const text = handle.document.text;
|
if (pos_index + 1 >= handle.text.len) return "";
|
||||||
|
|
||||||
if (pos_index + 1 >= text.len) return "";
|
|
||||||
var start_idx = pos_index;
|
var start_idx = pos_index;
|
||||||
|
|
||||||
while (start_idx > 0 and isSymbolChar(text[start_idx - 1])) {
|
while (start_idx > 0 and isSymbolChar(handle.text[start_idx - 1])) {
|
||||||
start_idx -= 1;
|
start_idx -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
var end_idx = pos_index;
|
var end_idx = pos_index;
|
||||||
while (end_idx < handle.document.text.len and isSymbolChar(text[end_idx])) {
|
while (end_idx < handle.text.len and isSymbolChar(handle.text[end_idx])) {
|
||||||
end_idx += 1;
|
end_idx += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (end_idx <= start_idx) return "";
|
if (end_idx <= start_idx) return "";
|
||||||
return text[start_idx..end_idx];
|
return handle.text[start_idx..end_idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
fn isSymbolChar(char: u8) bool {
|
fn isSymbolChar(char: u8) bool {
|
||||||
@ -693,7 +691,7 @@ fn gotoDefinitionSymbol(
|
|||||||
};
|
};
|
||||||
|
|
||||||
return types.Location{
|
return types.Location{
|
||||||
.uri = handle.document.uri,
|
.uri = handle.uri,
|
||||||
.range = offsets.tokenToRange(handle.tree, name_token, server.offset_encoding),
|
.range = offsets.tokenToRange(handle.tree, name_token, server.offset_encoding),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -912,12 +910,10 @@ fn getSymbolFieldAccess(
|
|||||||
const name = identifierFromPosition(source_index, handle.*);
|
const name = identifierFromPosition(source_index, handle.*);
|
||||||
if (name.len == 0) return null;
|
if (name.len == 0) return null;
|
||||||
|
|
||||||
var held_range = handle.document.borrowNullTerminatedSlice(loc.start, loc.end);
|
var held_range = try server.arena.allocator().dupeZ(u8, offsets.locToSlice(handle.text, loc));
|
||||||
var tokenizer = std.zig.Tokenizer.init(held_range.data());
|
var tokenizer = std.zig.Tokenizer.init(held_range);
|
||||||
|
|
||||||
errdefer held_range.release();
|
|
||||||
if (try analysis.getFieldAccessType(&server.document_store, &server.arena, handle, source_index, &tokenizer)) |result| {
|
if (try analysis.getFieldAccessType(&server.document_store, &server.arena, handle, source_index, &tokenizer)) |result| {
|
||||||
held_range.release();
|
|
||||||
const container_handle = result.unwrapped orelse result.original;
|
const container_handle = result.unwrapped orelse result.original;
|
||||||
const container_handle_node = switch (container_handle.type.data) {
|
const container_handle_node = switch (container_handle.type.data) {
|
||||||
.other => |n| n,
|
.other => |n| n,
|
||||||
@ -1144,21 +1140,22 @@ fn completeFieldAccess(server: *Server, handle: *DocumentStore.Handle, source_in
|
|||||||
const tracy_zone = tracy.trace(@src());
|
const tracy_zone = tracy.trace(@src());
|
||||||
defer tracy_zone.end();
|
defer tracy_zone.end();
|
||||||
|
|
||||||
|
const allocator = server.arena.allocator();
|
||||||
|
|
||||||
var completions = std.ArrayListUnmanaged(types.CompletionItem){};
|
var completions = std.ArrayListUnmanaged(types.CompletionItem){};
|
||||||
|
|
||||||
var held_range = handle.document.borrowNullTerminatedSlice(loc.start, loc.end);
|
var held_loc = try allocator.dupeZ(u8, offsets.locToSlice(handle.text, loc));
|
||||||
defer held_range.release();
|
var tokenizer = std.zig.Tokenizer.init(held_loc);
|
||||||
var tokenizer = std.zig.Tokenizer.init(held_range.data());
|
|
||||||
|
|
||||||
const result = (try analysis.getFieldAccessType(&server.document_store, &server.arena, handle, source_index, &tokenizer)) orelse return null;
|
const result = (try analysis.getFieldAccessType(&server.document_store, &server.arena, handle, source_index, &tokenizer)) orelse return null;
|
||||||
try server.typeToCompletion(&completions, result, handle);
|
try server.typeToCompletion(&completions, result, handle);
|
||||||
if (server.client_capabilities.label_details_support) {
|
if (server.client_capabilities.label_details_support) {
|
||||||
for (completions.items) |*item| {
|
for (completions.items) |*item| {
|
||||||
try formatDetailledLabel(item, server.arena.allocator());
|
try formatDetailledLabel(item, allocator);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return completions.toOwnedSlice(server.arena.allocator());
|
return completions.toOwnedSlice(allocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn formatDetailledLabel(item: *types.CompletionItem, alloc: std.mem.Allocator) !void {
|
fn formatDetailledLabel(item: *types.CompletionItem, alloc: std.mem.Allocator) !void {
|
||||||
@ -1375,7 +1372,7 @@ fn completeFileSystemStringLiteral(allocator: std.mem.Allocator, handle: *Docume
|
|||||||
var completions = std.ArrayListUnmanaged(types.CompletionItem){};
|
var completions = std.ArrayListUnmanaged(types.CompletionItem){};
|
||||||
|
|
||||||
fsc: {
|
fsc: {
|
||||||
var document_path = try uri_utils.parse(allocator, handle.uri());
|
var document_path = try uri_utils.parse(allocator, handle.uri);
|
||||||
var document_dir_path = std.fs.openIterableDirAbsolute(std.fs.path.dirname(document_path) orelse break :fsc, .{}) catch break :fsc;
|
var document_dir_path = std.fs.openIterableDirAbsolute(std.fs.path.dirname(document_path) orelse break :fsc, .{}) catch break :fsc;
|
||||||
defer document_dir_path.close();
|
defer document_dir_path.close();
|
||||||
|
|
||||||
@ -1712,7 +1709,7 @@ fn changeDocumentHandler(server: *Server, writer: anytype, id: types.RequestId,
|
|||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
try server.document_store.applyChanges(handle, req.params.contentChanges.Array, server.offset_encoding);
|
try server.document_store.applyChanges(handle, req.params.contentChanges, server.offset_encoding);
|
||||||
try server.publishDiagnostics(writer, handle);
|
try server.publishDiagnostics(writer, handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1826,8 +1823,8 @@ fn completionHandler(server: *Server, writer: anytype, id: types.RequestId, req:
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const source_index = offsets.positionToIndex(handle.document.text, req.params.position, server.offset_encoding);
|
const source_index = offsets.positionToIndex(handle.text, req.params.position, server.offset_encoding);
|
||||||
const pos_context = try analysis.getPositionContext(server.arena.allocator(), handle.document, source_index);
|
const pos_context = try analysis.getPositionContext(server.arena.allocator(), handle.text, source_index);
|
||||||
|
|
||||||
const maybe_completions = switch (pos_context) {
|
const maybe_completions = switch (pos_context) {
|
||||||
.builtin => server.builtin_completions.items,
|
.builtin => server.builtin_completions.items,
|
||||||
@ -1888,7 +1885,7 @@ fn signatureHelpHandler(server: *Server, writer: anytype, id: types.RequestId, r
|
|||||||
if (req.params.position.character == 0)
|
if (req.params.position.character == 0)
|
||||||
return try respondGeneric(writer, id, no_signatures_response);
|
return try respondGeneric(writer, id, no_signatures_response);
|
||||||
|
|
||||||
const source_index = offsets.positionToIndex(handle.document.text, req.params.position, server.offset_encoding);
|
const source_index = offsets.positionToIndex(handle.text, req.params.position, server.offset_encoding);
|
||||||
if (try getSignatureInfo(
|
if (try getSignatureInfo(
|
||||||
&server.document_store,
|
&server.document_store,
|
||||||
&server.arena,
|
&server.arena,
|
||||||
@ -1921,8 +1918,8 @@ fn gotoHandler(server: *Server, writer: anytype, id: types.RequestId, req: reque
|
|||||||
|
|
||||||
if (req.params.position.character == 0) return try respondGeneric(writer, id, null_result_response);
|
if (req.params.position.character == 0) return try respondGeneric(writer, id, null_result_response);
|
||||||
|
|
||||||
const source_index = offsets.positionToIndex(handle.document.text, req.params.position, server.offset_encoding);
|
const source_index = offsets.positionToIndex(handle.text, req.params.position, server.offset_encoding);
|
||||||
const pos_context = try analysis.getPositionContext(server.arena.allocator(), handle.document, source_index);
|
const pos_context = try analysis.getPositionContext(server.arena.allocator(), handle.text, source_index);
|
||||||
|
|
||||||
const maybe_location = switch (pos_context) {
|
const maybe_location = switch (pos_context) {
|
||||||
.var_access => try server.gotoDefinitionGlobal(source_index, handle, resolve_alias),
|
.var_access => try server.gotoDefinitionGlobal(source_index, handle, resolve_alias),
|
||||||
@ -1965,8 +1962,8 @@ fn hoverHandler(server: *Server, writer: anytype, id: types.RequestId, req: requ
|
|||||||
|
|
||||||
if (req.params.position.character == 0) return try respondGeneric(writer, id, null_result_response);
|
if (req.params.position.character == 0) return try respondGeneric(writer, id, null_result_response);
|
||||||
|
|
||||||
const source_index = offsets.positionToIndex(handle.document.text, req.params.position, server.offset_encoding);
|
const source_index = offsets.positionToIndex(handle.text, req.params.position, server.offset_encoding);
|
||||||
const pos_context = try analysis.getPositionContext(server.arena.allocator(), handle.document, source_index);
|
const pos_context = try analysis.getPositionContext(server.arena.allocator(), handle.text, source_index);
|
||||||
|
|
||||||
const maybe_hover = switch (pos_context) {
|
const maybe_hover = switch (pos_context) {
|
||||||
.builtin => try server.hoverDefinitionBuiltin(source_index, handle),
|
.builtin => try server.hoverDefinitionBuiltin(source_index, handle),
|
||||||
@ -2013,7 +2010,7 @@ fn formattingHandler(server: *Server, writer: anytype, id: types.RequestId, req:
|
|||||||
log.warn("Failed to spawn zig fmt process, error: {}", .{err});
|
log.warn("Failed to spawn zig fmt process, error: {}", .{err});
|
||||||
return try respondGeneric(writer, id, null_result_response);
|
return try respondGeneric(writer, id, null_result_response);
|
||||||
};
|
};
|
||||||
try process.stdin.?.writeAll(handle.document.text);
|
try process.stdin.?.writeAll(handle.text);
|
||||||
process.stdin.?.close();
|
process.stdin.?.close();
|
||||||
process.stdin = null;
|
process.stdin = null;
|
||||||
|
|
||||||
@ -2022,10 +2019,10 @@ fn formattingHandler(server: *Server, writer: anytype, id: types.RequestId, req:
|
|||||||
|
|
||||||
switch (try process.wait()) {
|
switch (try process.wait()) {
|
||||||
.Exited => |code| if (code == 0) {
|
.Exited => |code| if (code == 0) {
|
||||||
if (std.mem.eql(u8, handle.document.text, stdout_bytes)) return try respondGeneric(writer, id, null_result_response);
|
if (std.mem.eql(u8, handle.text, stdout_bytes)) return try respondGeneric(writer, id, null_result_response);
|
||||||
|
|
||||||
var edits = diff.edits(server.arena.allocator(), handle.document.text, stdout_bytes) catch {
|
var edits = diff.edits(server.arena.allocator(), handle.text, stdout_bytes) catch {
|
||||||
const range = offsets.locToRange(handle.document.text, .{ .start = 0, .end = handle.document.text.len }, server.offset_encoding);
|
const range = offsets.locToRange(handle.text, .{ .start = 0, .end = handle.text.len }, server.offset_encoding);
|
||||||
// If there was an error trying to diff the text, return the formatted response
|
// If there was an error trying to diff the text, return the formatted response
|
||||||
// as the new text for the entire range of the document
|
// as the new text for the entire range of the document
|
||||||
return try send(writer, server.arena.allocator(), types.Response{
|
return try send(writer, server.arena.allocator(), types.Response{
|
||||||
@ -2148,8 +2145,8 @@ fn generalReferencesHandler(server: *Server, writer: anytype, id: types.RequestI
|
|||||||
|
|
||||||
if (req.position().character <= 0) return try respondGeneric(writer, id, null_result_response);
|
if (req.position().character <= 0) return try respondGeneric(writer, id, null_result_response);
|
||||||
|
|
||||||
const source_index = offsets.positionToIndex(handle.document.text, req.position(), server.offset_encoding);
|
const source_index = offsets.positionToIndex(handle.text, req.position(), server.offset_encoding);
|
||||||
const pos_context = try analysis.getPositionContext(server.arena.allocator(), handle.document, source_index);
|
const pos_context = try analysis.getPositionContext(server.arena.allocator(), handle.text, source_index);
|
||||||
|
|
||||||
const decl = switch (pos_context) {
|
const decl = switch (pos_context) {
|
||||||
.var_access => try server.getSymbolGlobal(source_index, handle),
|
.var_access => try server.getSymbolGlobal(source_index, handle),
|
||||||
@ -2191,7 +2188,7 @@ fn generalReferencesHandler(server: *Server, writer: anytype, id: types.RequestI
|
|||||||
.references => .{ .Locations = locations.items },
|
.references => .{ .Locations = locations.items },
|
||||||
.highlight => blk: {
|
.highlight => blk: {
|
||||||
var highlights = try std.ArrayListUnmanaged(types.DocumentHighlight).initCapacity(allocator, locations.items.len);
|
var highlights = try std.ArrayListUnmanaged(types.DocumentHighlight).initCapacity(allocator, locations.items.len);
|
||||||
const uri = handle.uri();
|
const uri = handle.uri;
|
||||||
for (locations.items) |loc| {
|
for (locations.items) |loc| {
|
||||||
if (!std.mem.eql(u8, loc.uri, uri)) continue;
|
if (!std.mem.eql(u8, loc.uri, uri)) continue;
|
||||||
highlights.appendAssumeCapacity(.{
|
highlights.appendAssumeCapacity(.{
|
||||||
|
@ -1454,18 +1454,19 @@ fn tokenLocAppend(prev: offsets.Loc, token: std.zig.Token) offsets.Loc {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getPositionContext(allocator: std.mem.Allocator, document: types.TextDocument, doc_index: usize) !PositionContext {
|
pub fn getPositionContext(allocator: std.mem.Allocator, text: []const u8, doc_index: usize) !PositionContext {
|
||||||
const line_loc = offsets.lineLocUntilIndex(document.text, doc_index);
|
const line_loc = offsets.lineLocUntilIndex(text, doc_index);
|
||||||
const line = offsets.locToSlice(document.text, line_loc);
|
const line = offsets.locToSlice(text, line_loc);
|
||||||
|
|
||||||
var stack = try std.ArrayListUnmanaged(StackState).initCapacity(allocator, 8);
|
var stack = try std.ArrayListUnmanaged(StackState).initCapacity(allocator, 8);
|
||||||
defer stack.deinit(allocator);
|
defer stack.deinit(allocator);
|
||||||
|
|
||||||
{
|
{
|
||||||
var held_line = document.borrowNullTerminatedSlice(0, line_loc.end);
|
var held_line = try allocator.dupeZ(u8, text[0..line_loc.end]);
|
||||||
defer held_line.release();
|
defer allocator.free(held_line);
|
||||||
|
|
||||||
var tokenizer: std.zig.Tokenizer = .{
|
var tokenizer: std.zig.Tokenizer = .{
|
||||||
.buffer = held_line.data(),
|
.buffer = held_line,
|
||||||
.index = line_loc.start,
|
.index = line_loc.start,
|
||||||
.pending_invalid_token = null,
|
.pending_invalid_token = null,
|
||||||
};
|
};
|
||||||
@ -1592,14 +1593,14 @@ pub fn getPositionContext(allocator: std.mem.Allocator, document: types.TextDocu
|
|||||||
|
|
||||||
if (line.len == 0) return .empty;
|
if (line.len == 0) return .empty;
|
||||||
|
|
||||||
var held_line = document.borrowNullTerminatedSlice(line_loc.start, line_loc.end);
|
var held_line = try allocator.dupeZ(u8, offsets.locToSlice(text, line_loc));
|
||||||
defer held_line.release();
|
defer allocator.free(held_line);
|
||||||
|
|
||||||
switch (line[0]) {
|
switch (line[0]) {
|
||||||
'a'...'z', 'A'...'Z', '_', '@' => {},
|
'a'...'z', 'A'...'Z', '_', '@' => {},
|
||||||
else => break :block .empty,
|
else => break :block .empty,
|
||||||
}
|
}
|
||||||
var tokenizer = std.zig.Tokenizer.init(held_line.data());
|
var tokenizer = std.zig.Tokenizer.init(held_line);
|
||||||
const tok = tokenizer.next();
|
const tok = tokenizer.next();
|
||||||
if (tok.tag == .identifier) {
|
if (tok.tag == .identifier) {
|
||||||
break :block PositionContext{ .var_access = tok.loc };
|
break :block PositionContext{ .var_access = tok.loc };
|
||||||
|
@ -22,7 +22,7 @@ pub const Builder = struct {
|
|||||||
) error{OutOfMemory}!void {
|
) error{OutOfMemory}!void {
|
||||||
const kind = DiagnosticKind.parse(diagnostic.message) orelse return;
|
const kind = DiagnosticKind.parse(diagnostic.message) orelse return;
|
||||||
|
|
||||||
const loc = offsets.rangeToLoc(builder.text(), diagnostic.range, builder.offset_encoding);
|
const loc = offsets.rangeToLoc(builder.handle.text, diagnostic.range, builder.offset_encoding);
|
||||||
|
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
.unused => |id| switch (id) {
|
.unused => |id| switch (id) {
|
||||||
@ -49,12 +49,12 @@ pub const Builder = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn createTextEditLoc(self: *Builder, loc: offsets.Loc, new_text: []const u8) types.TextEdit {
|
pub fn createTextEditLoc(self: *Builder, loc: offsets.Loc, new_text: []const u8) types.TextEdit {
|
||||||
const range = offsets.locToRange(self.text(), loc, self.offset_encoding);
|
const range = offsets.locToRange(self.handle.text, loc, self.offset_encoding);
|
||||||
return types.TextEdit{ .range = range, .newText = new_text };
|
return types.TextEdit{ .range = range, .newText = new_text };
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn createTextEditPos(self: *Builder, index: usize, new_text: []const u8) types.TextEdit {
|
pub fn createTextEditPos(self: *Builder, index: usize, new_text: []const u8) types.TextEdit {
|
||||||
const position = offsets.indexToPosition(self.text(), index, self.offset_encoding);
|
const position = offsets.indexToPosition(self.handle.text, index, self.offset_encoding);
|
||||||
return types.TextEdit{ .range = .{ .start = position, .end = position }, .newText = new_text };
|
return types.TextEdit{ .range = .{ .start = position, .end = position }, .newText = new_text };
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,18 +63,14 @@ pub const Builder = struct {
|
|||||||
try text_edits.appendSlice(self.arena.allocator(), edits);
|
try text_edits.appendSlice(self.arena.allocator(), edits);
|
||||||
|
|
||||||
var workspace_edit = types.WorkspaceEdit{ .changes = .{} };
|
var workspace_edit = types.WorkspaceEdit{ .changes = .{} };
|
||||||
try workspace_edit.changes.putNoClobber(self.arena.allocator(), self.handle.uri(), text_edits);
|
try workspace_edit.changes.putNoClobber(self.arena.allocator(), self.handle.uri, text_edits);
|
||||||
|
|
||||||
return workspace_edit;
|
return workspace_edit;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn text(self: *Builder) []const u8 {
|
|
||||||
return self.handle.document.text;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
fn handleNonCamelcaseFunction(builder: *Builder, actions: *std.ArrayListUnmanaged(types.CodeAction), loc: offsets.Loc) !void {
|
fn handleNonCamelcaseFunction(builder: *Builder, actions: *std.ArrayListUnmanaged(types.CodeAction), loc: offsets.Loc) !void {
|
||||||
const identifier_name = offsets.locToSlice(builder.text(), loc);
|
const identifier_name = offsets.locToSlice(builder.handle.text, loc);
|
||||||
|
|
||||||
if (std.mem.allEqual(u8, identifier_name, '_')) return;
|
if (std.mem.allEqual(u8, identifier_name, '_')) return;
|
||||||
|
|
||||||
@ -91,7 +87,7 @@ fn handleNonCamelcaseFunction(builder: *Builder, actions: *std.ArrayListUnmanage
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn handleUnusedFunctionParameter(builder: *Builder, actions: *std.ArrayListUnmanaged(types.CodeAction), loc: offsets.Loc) !void {
|
fn handleUnusedFunctionParameter(builder: *Builder, actions: *std.ArrayListUnmanaged(types.CodeAction), loc: offsets.Loc) !void {
|
||||||
const identifier_name = offsets.locToSlice(builder.text(), loc);
|
const identifier_name = offsets.locToSlice(builder.handle.text, loc);
|
||||||
|
|
||||||
const tree = builder.handle.tree;
|
const tree = builder.handle.tree;
|
||||||
const node_tags = tree.nodes.items(.tag);
|
const node_tags = tree.nodes.items(.tag);
|
||||||
@ -117,7 +113,7 @@ fn handleUnusedFunctionParameter(builder: *Builder, actions: *std.ArrayListUnman
|
|||||||
|
|
||||||
const block = node_datas[payload.func].rhs;
|
const block = node_datas[payload.func].rhs;
|
||||||
|
|
||||||
const indent = offsets.lineSliceUntilIndex(builder.text(), token_starts[node_tokens[payload.func]]).len;
|
const indent = offsets.lineSliceUntilIndex(builder.handle.text, token_starts[node_tokens[payload.func]]).len;
|
||||||
const new_text = try createDiscardText(builder.arena.allocator(), identifier_name, indent + 4);
|
const new_text = try createDiscardText(builder.arena.allocator(), identifier_name, indent + 4);
|
||||||
|
|
||||||
const index = token_starts[node_tokens[block]] + 1;
|
const index = token_starts[node_tokens[block]] + 1;
|
||||||
@ -141,7 +137,7 @@ fn handleUnusedFunctionParameter(builder: *Builder, actions: *std.ArrayListUnman
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn handleUnusedVariableOrConstant(builder: *Builder, actions: *std.ArrayListUnmanaged(types.CodeAction), loc: offsets.Loc) !void {
|
fn handleUnusedVariableOrConstant(builder: *Builder, actions: *std.ArrayListUnmanaged(types.CodeAction), loc: offsets.Loc) !void {
|
||||||
const identifier_name = offsets.locToSlice(builder.text(), loc);
|
const identifier_name = offsets.locToSlice(builder.handle.text, loc);
|
||||||
|
|
||||||
const tree = builder.handle.tree;
|
const tree = builder.handle.tree;
|
||||||
const token_tags = tree.tokens.items(.tag);
|
const token_tags = tree.tokens.items(.tag);
|
||||||
@ -163,7 +159,7 @@ fn handleUnusedVariableOrConstant(builder: *Builder, actions: *std.ArrayListUnma
|
|||||||
const first_token = tree.firstToken(node);
|
const first_token = tree.firstToken(node);
|
||||||
const last_token = ast.lastToken(tree, node) + 1;
|
const last_token = ast.lastToken(tree, node) + 1;
|
||||||
|
|
||||||
const indent = offsets.lineSliceUntilIndex(builder.text(), token_starts[first_token]).len;
|
const indent = offsets.lineSliceUntilIndex(builder.handle.text, token_starts[first_token]).len;
|
||||||
|
|
||||||
if (token_tags[last_token] != .semicolon) return;
|
if (token_tags[last_token] != .semicolon) return;
|
||||||
|
|
||||||
@ -180,11 +176,11 @@ fn handleUnusedVariableOrConstant(builder: *Builder, actions: *std.ArrayListUnma
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn handleUnusedIndexCapture(builder: *Builder, actions: *std.ArrayListUnmanaged(types.CodeAction), loc: offsets.Loc) !void {
|
fn handleUnusedIndexCapture(builder: *Builder, actions: *std.ArrayListUnmanaged(types.CodeAction), loc: offsets.Loc) !void {
|
||||||
const capture_locs = getCaptureLoc(builder.text(), loc, true) orelse return;
|
const capture_locs = getCaptureLoc(builder.handle.text, loc, true) orelse return;
|
||||||
|
|
||||||
// TODO support discarding without modifying the capture
|
// TODO support discarding without modifying the capture
|
||||||
// by adding a discard in the block scope
|
// by adding a discard in the block scope
|
||||||
const is_value_discarded = std.mem.eql(u8, offsets.locToSlice(builder.text(), capture_locs.value), "_");
|
const is_value_discarded = std.mem.eql(u8, offsets.locToSlice(builder.handle.text, capture_locs.value), "_");
|
||||||
if (is_value_discarded) {
|
if (is_value_discarded) {
|
||||||
// |_, i| ->
|
// |_, i| ->
|
||||||
// TODO fix formatting
|
// TODO fix formatting
|
||||||
@ -210,7 +206,7 @@ fn handleUnusedIndexCapture(builder: *Builder, actions: *std.ArrayListUnmanaged(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn handleUnusedCapture(builder: *Builder, actions: *std.ArrayListUnmanaged(types.CodeAction), loc: offsets.Loc) !void {
|
fn handleUnusedCapture(builder: *Builder, actions: *std.ArrayListUnmanaged(types.CodeAction), loc: offsets.Loc) !void {
|
||||||
const capture_locs = getCaptureLoc(builder.text(), loc, false) orelse return;
|
const capture_locs = getCaptureLoc(builder.handle.text, loc, false) orelse return;
|
||||||
|
|
||||||
// TODO support discarding without modifying the capture
|
// TODO support discarding without modifying the capture
|
||||||
// by adding a discard in the block scope
|
// by adding a discard in the block scope
|
||||||
@ -235,7 +231,7 @@ fn handleUnusedCapture(builder: *Builder, actions: *std.ArrayListUnmanaged(types
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn handlePointlessDiscard(builder: *Builder, actions: *std.ArrayListUnmanaged(types.CodeAction), loc: offsets.Loc) !void {
|
fn handlePointlessDiscard(builder: *Builder, actions: *std.ArrayListUnmanaged(types.CodeAction), loc: offsets.Loc) !void {
|
||||||
const edit_loc = getDiscardLoc(builder.text(), loc) orelse return;
|
const edit_loc = getDiscardLoc(builder.handle.text, loc) orelse return;
|
||||||
|
|
||||||
try actions.append(builder.arena.allocator(), .{
|
try actions.append(builder.arena.allocator(), .{
|
||||||
.title = "remove pointless discard",
|
.title = "remove pointless discard",
|
||||||
|
@ -212,14 +212,12 @@ fn writeCallNodeHint(builder: *Builder, arena: *std.heap.ArenaAllocator, store:
|
|||||||
const start = offsets.tokenToIndex(tree, lhsToken);
|
const start = offsets.tokenToIndex(tree, lhsToken);
|
||||||
const rhs_loc = offsets.tokenToLoc(tree, rhsToken);
|
const rhs_loc = offsets.tokenToLoc(tree, rhsToken);
|
||||||
|
|
||||||
var held_range = handle.document.borrowNullTerminatedSlice(start, rhs_loc.end);
|
var held_range = try arena.allocator().dupeZ(u8, handle.text[start..rhs_loc.end]);
|
||||||
var tokenizer = std.zig.Tokenizer.init(held_range.data());
|
var tokenizer = std.zig.Tokenizer.init(held_range);
|
||||||
|
|
||||||
// note: we have the ast node, traversing it would probably yield better results
|
// note: we have the ast node, traversing it would probably yield better results
|
||||||
// than trying to re-tokenize and re-parse it
|
// than trying to re-tokenize and re-parse it
|
||||||
errdefer held_range.release();
|
|
||||||
if (try analysis.getFieldAccessType(store, arena, handle, rhs_loc.end, &tokenizer)) |result| {
|
if (try analysis.getFieldAccessType(store, arena, handle, rhs_loc.end, &tokenizer)) |result| {
|
||||||
held_range.release();
|
|
||||||
const container_handle = result.unwrapped orelse result.original;
|
const container_handle = result.unwrapped orelse result.original;
|
||||||
switch (container_handle.type.data) {
|
switch (container_handle.type.data) {
|
||||||
.other => |container_handle_node| {
|
.other => |container_handle_node| {
|
||||||
|
@ -29,7 +29,7 @@ pub fn labelReferences(
|
|||||||
if (include_decl) {
|
if (include_decl) {
|
||||||
// The first token is always going to be the label
|
// The first token is always going to be the label
|
||||||
try locations.append(allocator, .{
|
try locations.append(allocator, .{
|
||||||
.uri = handle.uri(),
|
.uri = handle.uri,
|
||||||
.range = offsets.tokenToRange(handle.tree, first_tok, encoding),
|
.range = offsets.tokenToRange(handle.tree, first_tok, encoding),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -45,7 +45,7 @@ pub fn labelReferences(
|
|||||||
if (!std.mem.eql(u8, tree.tokenSlice(curr_tok + 2), tree.tokenSlice(first_tok))) continue;
|
if (!std.mem.eql(u8, tree.tokenSlice(curr_tok + 2), tree.tokenSlice(first_tok))) continue;
|
||||||
|
|
||||||
try locations.append(allocator, .{
|
try locations.append(allocator, .{
|
||||||
.uri = handle.uri(),
|
.uri = handle.uri,
|
||||||
.range = offsets.tokenToRange(handle.tree, curr_tok + 2, encoding),
|
.range = offsets.tokenToRange(handle.tree, curr_tok + 2, encoding),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -72,7 +72,7 @@ const Builder = struct {
|
|||||||
|
|
||||||
pub fn add(self: *Builder, handle: *DocumentStore.Handle, token_index: Ast.TokenIndex) !void {
|
pub fn add(self: *Builder, handle: *DocumentStore.Handle, token_index: Ast.TokenIndex) !void {
|
||||||
try self.locations.append(self.arena.allocator(), .{
|
try self.locations.append(self.arena.allocator(), .{
|
||||||
.uri = handle.uri(),
|
.uri = handle.uri,
|
||||||
.range = offsets.tokenToRange(handle.tree, token_index, self.encoding),
|
.range = offsets.tokenToRange(handle.tree, token_index, self.encoding),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -204,10 +204,15 @@ const TextDocumentIdentifier = struct {
|
|||||||
pub const ChangeDocument = struct {
|
pub const ChangeDocument = struct {
|
||||||
params: struct {
|
params: struct {
|
||||||
textDocument: TextDocumentIdentifier,
|
textDocument: TextDocumentIdentifier,
|
||||||
contentChanges: std.json.Value,
|
contentChanges: []TextDocumentContentChangeEvent,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const TextDocumentContentChangeEvent = struct {
|
||||||
|
range: ?types.Range,
|
||||||
|
text: []const u8,
|
||||||
|
};
|
||||||
|
|
||||||
const TextDocumentIdentifierRequest = struct {
|
const TextDocumentIdentifierRequest = struct {
|
||||||
params: struct {
|
params: struct {
|
||||||
textDocument: TextDocumentIdentifier,
|
textDocument: TextDocumentIdentifier,
|
||||||
|
@ -251,11 +251,10 @@ pub fn getSignatureInfo(document_store: *DocumentStore, arena: *std.heap.ArenaAl
|
|||||||
const last_token_slice = tree.tokenSlice(expr_last_token);
|
const last_token_slice = tree.tokenSlice(expr_last_token);
|
||||||
const expr_end = token_starts[expr_last_token] + last_token_slice.len;
|
const expr_end = token_starts[expr_last_token] + last_token_slice.len;
|
||||||
|
|
||||||
var held_expr = handle.document.borrowNullTerminatedSlice(expr_start, expr_end);
|
var held_expr = try alloc.dupeZ(u8, handle.text[expr_start..expr_end]);
|
||||||
defer held_expr.release();
|
|
||||||
|
|
||||||
// Resolve the expression.
|
// Resolve the expression.
|
||||||
var tokenizer = std.zig.Tokenizer.init(held_expr.data());
|
var tokenizer = std.zig.Tokenizer.init(held_expr);
|
||||||
if (try analysis.getFieldAccessType(
|
if (try analysis.getFieldAccessType(
|
||||||
document_store,
|
document_store,
|
||||||
arena,
|
arena,
|
||||||
|
@ -141,41 +141,6 @@ pub const Diagnostic = struct {
|
|||||||
relatedInformation: ?[]DiagnosticRelatedInformation = null,
|
relatedInformation: ?[]DiagnosticRelatedInformation = null,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const TextDocument = struct {
|
|
||||||
uri: string,
|
|
||||||
// This is a substring of mem starting at 0
|
|
||||||
text: [:0]const u8,
|
|
||||||
// This holds the memory that we have actually allocated.
|
|
||||||
mem: []u8,
|
|
||||||
|
|
||||||
const Held = struct {
|
|
||||||
document: *const TextDocument,
|
|
||||||
popped: u8,
|
|
||||||
start_index: usize,
|
|
||||||
end_index: usize,
|
|
||||||
|
|
||||||
pub fn data(self: @This()) [:0]const u8 {
|
|
||||||
return self.document.mem[self.start_index..self.end_index :0];
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn release(self: *@This()) void {
|
|
||||||
self.document.mem[self.end_index] = self.popped;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn borrowNullTerminatedSlice(self: *const @This(), start_idx: usize, end_idx: usize) Held {
|
|
||||||
std.debug.assert(end_idx >= start_idx);
|
|
||||||
const popped_char = self.mem[end_idx];
|
|
||||||
self.mem[end_idx] = 0;
|
|
||||||
return .{
|
|
||||||
.document = self,
|
|
||||||
.popped = popped_char,
|
|
||||||
.start_index = start_idx,
|
|
||||||
.end_index = end_idx,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const WorkspaceEdit = struct {
|
pub const WorkspaceEdit = struct {
|
||||||
changes: std.StringHashMapUnmanaged(std.ArrayListUnmanaged(TextEdit)),
|
changes: std.StringHashMapUnmanaged(std.ArrayListUnmanaged(TextEdit)),
|
||||||
|
|
||||||
|
@ -233,31 +233,12 @@ test "position context - empty" {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn makeDocument(uri: []const u8, text: []const u8) !types.TextDocument {
|
|
||||||
const mem = try allocator.alloc(u8, text.len + 1);
|
|
||||||
std.mem.copy(u8, mem, text);
|
|
||||||
mem[text.len] = 0;
|
|
||||||
|
|
||||||
return types.TextDocument{
|
|
||||||
.uri = uri,
|
|
||||||
.mem = mem,
|
|
||||||
.text = mem[0..text.len :0],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn freeDocument(doc: types.TextDocument) void {
|
|
||||||
allocator.free(doc.text);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn testContext(line: []const u8, tag: std.meta.Tag(analysis.PositionContext), maybe_range: ?[]const u8) !void {
|
fn testContext(line: []const u8, tag: std.meta.Tag(analysis.PositionContext), maybe_range: ?[]const u8) !void {
|
||||||
const cursor_idx = std.mem.indexOf(u8, line, "<cursor>").?;
|
const cursor_idx = std.mem.indexOf(u8, line, "<cursor>").?;
|
||||||
const final_line = try std.mem.concat(allocator, u8, &.{ line[0..cursor_idx], line[cursor_idx + "<cursor>".len ..] });
|
const final_line = try std.mem.concat(allocator, u8, &.{ line[0..cursor_idx], line[cursor_idx + "<cursor>".len ..] });
|
||||||
defer allocator.free(final_line);
|
defer allocator.free(final_line);
|
||||||
|
|
||||||
const doc = try makeDocument("", line);
|
const ctx = try analysis.getPositionContext(allocator, line, cursor_idx);
|
||||||
defer freeDocument(doc);
|
|
||||||
|
|
||||||
const ctx = try analysis.getPositionContext(allocator, doc, cursor_idx);
|
|
||||||
|
|
||||||
if (std.meta.activeTag(ctx) != tag) {
|
if (std.meta.activeTag(ctx) != tag) {
|
||||||
std.debug.print("Expected tag `{s}`, got `{s}`\n", .{ @tagName(tag), @tagName(std.meta.activeTag(ctx)) });
|
std.debug.print("Expected tag `{s}`, got `{s}`\n", .{ @tagName(tag), @tagName(std.meta.activeTag(ctx)) });
|
||||||
@ -273,7 +254,7 @@ fn testContext(line: []const u8, tag: std.meta.Tag(analysis.PositionContext), ma
|
|||||||
|
|
||||||
const expected_range = maybe_range orelse {
|
const expected_range = maybe_range orelse {
|
||||||
std.debug.print("Expected null range, got `{s}`\n", .{
|
std.debug.print("Expected null range, got `{s}`\n", .{
|
||||||
doc.text[actual_loc.start..actual_loc.end],
|
line[actual_loc.start..actual_loc.end],
|
||||||
});
|
});
|
||||||
return error.DifferentRange;
|
return error.DifferentRange;
|
||||||
};
|
};
|
||||||
@ -283,8 +264,8 @@ fn testContext(line: []const u8, tag: std.meta.Tag(analysis.PositionContext), ma
|
|||||||
|
|
||||||
if (expected_range_start != actual_loc.start or expected_range_end != actual_loc.end) {
|
if (expected_range_start != actual_loc.start or expected_range_end != actual_loc.end) {
|
||||||
std.debug.print("Expected range `{s}` ({}..{}), got `{s}` ({}..{})\n", .{
|
std.debug.print("Expected range `{s}` ({}..{}), got `{s}` ({}..{})\n", .{
|
||||||
doc.text[expected_range_start..expected_range_end], expected_range_start, expected_range_end,
|
line[expected_range_start..expected_range_end], expected_range_start, expected_range_end,
|
||||||
doc.text[actual_loc.start..actual_loc.end], actual_loc.start, actual_loc.end,
|
line[actual_loc.start..actual_loc.end], actual_loc.start, actual_loc.end,
|
||||||
});
|
});
|
||||||
return error.DifferentRange;
|
return error.DifferentRange;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user