diff options
Diffstat (limited to 'src/lsp/lsp_zls.zig')
| -rw-r--r-- | src/lsp/lsp_zls.zig | 36 |
1 files changed, 16 insertions, 20 deletions
diff --git a/src/lsp/lsp_zls.zig b/src/lsp/lsp_zls.zig index bf220c47..fb9804e6 100644 --- a/src/lsp/lsp_zls.zig +++ b/src/lsp/lsp_zls.zig @@ -1352,11 +1352,11 @@ fn codeActions( // ---------------------------------------------------------------- format -/// `=`. The seam returns ROWS, not edits — there is no channel through which a -/// backend can rewrite the buffer — so format reports rather than formats: one -/// row per line `zig fmt` would change, in the `+Lsp` buffer. That is the -/// honest shape of "format" behind a read-only seam, and it is still the -/// answer to the question the keypress asks. +/// `=`. The response is `@put` edit records (see lsp.put): one span covering +/// everything `zig fmt` would change, which the core substitutes as a single +/// undo step — so `=` FORMATS, exactly like helix. The two answers that are +/// not edits stay prose rows in `+Lsp`: a file that does not parse cannot be +/// formatted, and a file already formatted has nothing to apply. fn formatQuery(arena: std.mem.Allocator, req: lsp.Req, out: *std.Io.Writer) !void { const path = lsp.rel(req.root, req.path); var tree: Ast = try .parse(arena, req.source, .zig); @@ -1377,22 +1377,18 @@ fn formatQuery(arena: std.mem.Allocator, req: lsp.Req, out: *std.Io.Writer) !voi lsp.row(out, path, 0, 0, "already formatted"); return; } - var a = std.mem.splitScalar(u8, req.source, '\n'); - var b = std.mem.splitScalar(u8, formatted, '\n'); - var ln: usize = 0; - var n: usize = 0; - while (n < max_rows) : (ln += 1) { - const x = a.next(); - const y = b.next(); - if (x == null and y == null) break; - const xs = x orelse ""; - const ys = y orelse ""; - if (std.mem.eql(u8, xs, ys)) continue; - n += 1; - lsp.row(out, path, ln, 0, try std.fmt.allocPrint(arena, "- {s} + {s}", .{ - std.mem.trim(u8, xs, " \t"), std.mem.trim(u8, ys, " \t"), - })); + // one record, spanning only what changed: the common prefix and suffix + // stay untouched, which is also what keeps the cursor mapping tight + var lo: usize = 0; + const min_len = @min(req.source.len, formatted.len); + while (lo < min_len and req.source[lo] == formatted[lo]) lo += 1; + var src_hi = req.source.len; + var fmt_hi = formatted.len; + while (src_hi > lo and fmt_hi > lo and req.source[src_hi - 1] == formatted[fmt_hi - 1]) { + src_hi -= 1; + fmt_hi -= 1; } + lsp.put(out, lo, src_hi, formatted[lo..fmt_hi]); } // ------------------------------------------------------------------ files |
