diff options
| author | Gabriel Schneider <[email protected]> | 2026-10-01 06:22:44 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-10-01 07:16:43 -0300 |
| commit | 85b60dedb6bdb192abd11b2d58ca7c0e8c944b18 (patch) | |
| tree | 13bc6a9f1f1551088c992a29cb365f5d0a63b239 /test/lspmock.zig | |
| parent | fb330ce04c4eec4de317637d26310b74e2ee5923 (diff) | |
| download | pardes-85b60dedb6bdb192abd11b2d58ca7c0e8c944b18.tar.gz pardes-85b60dedb6bdb192abd11b2d58ca7c0e8c944b18.zip | |
A Rename, references and the like tell the server of every open file of its language first, so a rename reaches files it had not seen and the preview lists them
zls renames only in the documents in its store, and syncDoc told it of
a file only when a query was asked from it, so renaming in progress.zig
left main.zig unchanged and broken, with no preview. For a query whose
answer can reach other files (rename, references, implementation,
workspace symbols, calls and type hierarchy), the host snapshots every
other open file and the client syncs those its server answers for
first. The mock server answers a rename in each document it was told
of; lsp-rename-files opens main.rs by a look, renames from lib.rs, and
its preview lists both.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Diffstat (limited to 'test/lspmock.zig')
| -rw-r--r-- | test/lspmock.zig | 31 |
1 files changed, 28 insertions, 3 deletions
diff --git a/test/lspmock.zig b/test/lspmock.zig index 7b379b49..001c3488 100644 --- a/test/lspmock.zig +++ b/test/lspmock.zig @@ -97,6 +97,20 @@ fn range(a: std.mem.Allocator, line: u32, from: u32, to: u32) []const u8 { var root_uri: [512]u8 = undefined; var root_uri_len: usize = 0; +/// The documents the editor has opened here (didOpen), as zls keeps its +/// store: a rename answers in each of them, and in no file it never saw. +var opened: [8][512]u8 = undefined; +var opened_len: [8]usize = @splat(0); +var opened_n: usize = 0; + +fn noteOpened(uri: []const u8) void { + for (opened[0..opened_n], opened_len[0..opened_n]) |*o, n| if (std.mem.eql(u8, o[0..n], uri)) return; + if (opened_n == opened.len or uri.len > opened[0].len) return; + @memcpy(opened[opened_n][0..uri.len], uri); + opened_len[opened_n] = uri.len; + opened_n += 1; +} + pub fn main(init: std.process.Init) !void { _ = init; if (getenv("LSPMOCK_MODE")) |m| { @@ -187,6 +201,7 @@ fn handle(a: std.mem.Allocator, raw: []const u8) void { notify(a, "$/progress", "{{\"token\":\"t1\",\"value\":{{\"kind\":\"end\"}}}}", .{}); return; } + if (std.mem.eql(u8, method, "textDocument/didOpen")) noteOpened(reqUri(params)); if (id == null) return; // didOpen/didChange/$/cancelRequest: nothing to say if (mode == .mute) return; // swallow every request after the handshake @@ -227,10 +242,20 @@ fn handle(a: std.mem.Allocator, raw: []const u8) void { q, root_uri[0..root_uri_len], range(a, 1, 7, 10), }); } else if (std.mem.eql(u8, method, "textDocument/rename")) { + // In every document it has seen: lib.rs's definition, main.rs's two + // calls (any other file reads as main.rs's shape). const nn = str(get(params, "newName")) orelse "renamed"; - reply(a, rid, "{{\"changes\":{{\"{s}\":[{{\"range\":{s},\"newText\":\"{s}\"}},{{\"range\":{s},\"newText\":\"{s}\"}}]}}}}", .{ - uri, range(a, 3, 12, 15), nn, range(a, 4, 12, 15), nn, - }); + var changes: std.ArrayList(u8) = .empty; + for (opened[0..opened_n], opened_len[0..opened_n], 0..) |*o, n, k| { + const doc = o[0..n]; + const edits = if (std.mem.endsWith(u8, doc, "/lib.rs")) + std.fmt.allocPrint(a, "[{{\"range\":{s},\"newText\":\"{s}\"}}]", .{ range(a, 1, 7, 10), nn }) catch return + else + std.fmt.allocPrint(a, "[{{\"range\":{s},\"newText\":\"{s}\"}},{{\"range\":{s},\"newText\":\"{s}\"}}]", .{ range(a, 3, 12, 15), nn, range(a, 4, 12, 15), nn }) catch return; + changes.print(a, "{s}\"{s}\":{s}", .{ if (k > 0) "," else "", doc, edits }) catch return; + } + if (opened_n == 0) changes.print(a, "\"{s}\":[{{\"range\":{s},\"newText\":\"{s}\"}},{{\"range\":{s},\"newText\":\"{s}\"}}]", .{ uri, range(a, 3, 12, 15), nn, range(a, 4, 12, 15), nn }) catch return; + reply(a, rid, "{{\"changes\":{{{s}}}}}", .{changes.items}); } else if (std.mem.eql(u8, method, "textDocument/formatting")) { reply(a, rid, "[{{\"range\":{s},\"newText\":\"// formatted by mock\\n\"}}]", .{range(a, 0, 0, 0)}); } else if (std.mem.eql(u8, method, "textDocument/codeAction")) { |
