-
-
Notifications
You must be signed in to change notification settings - Fork 395
Description
Zig Version
0.15.2
ZLS Version
0.15.0
Client / Code Editor / Extensions
neovim v0.11.5 with built-in LSP, no plugins
Steps to Reproduce and Observed Behavior
Start neovim with the following init.lua:
vim.lsp.set_log_level(vim.lsp.log_levels.DEBUG)
vim.lsp.config("zls", {
cmd = { "/home/jon/github/zls/zig-out/bin/zls" }, -- built with `zig build`
})
vim.lsp.enable("zls")And the following test.zig file:
const a = @import("a");
nvim --clean -u init.lua test.zig
Then run the following command in neovim to invoke the code action:
:lua vim.lsp.buf.code_action({context = {only = {"source.organizeImports"}}, apply = true})
Neovim's LSP client logs show that edits are being sent even though they don't result in any changes:
[DEBUG][2025-11-29 15:24:48] ...m/lsp/client.lua:674 "LSP[zls]" "client.request" 1 "textDocument/codeAction" { context = { diagnostics = {}, only = { "source.organizeImports" }, triggerKind = 1 }, range = { ["end"] = <1>{ character = 11, line = 2 }, start = <table 1> }, textDocument = { uri = "file:///tmp/test.zig" } } <function 1> 1
[DEBUG][2025-11-29 15:24:48] .../vim/lsp/rpc.lua:277 "rpc.send" { id = 3, jsonrpc = "2.0", method = "textDocument/codeAction", params = { context = { diagnostics = {}, only = { "source.organizeImports" }, triggerKind = 1 }, range = { ["end"] = <1>{ character = 11, line = 2 }, start = <table 1> }, textDocument = { uri = "file:///tmp/test.zig" } } }
[DEBUG][2025-11-29 15:24:48] .../vim/lsp/rpc.lua:391 "rpc.receive" { id = 3, jsonrpc = "2.0", result = { { edit = { changes = { ["file:///tmp/test.zig"] = { { newText = 'const a = @import("a");\n\n', range = { ["end"] = { character = 0, line = 0 }, start = { character = 0, line = 0 } } }, { newText = "", range = { ["end"] = { character = 0, line = 2 }, start = { character = 0, line = 0 } } } } } }, isPreferred = true, kind = "source.organizeImports", title = "organize @import" } } }
At least for Neovim, those edits still dirty the buffer and add to the undo stack. When I make a change unrelated to imports, a "change, organizeImports, undo" sequence to return to the contents of the file before the change actually requires two undos (one for the no-op organizeImports edits and one for the change I wanted to undo). It also seems to cause diagnostics displayed with virtual text to flicker when the code action is run.
Expected Behavior
When a code action's edits result in no changes, those edits should not be sent to the client. I don't see where that assumption is explicitly stated in the spec, but servers are allowed to return null from code action requests.
For one point of reference, gopls does what I expect and sends no edits in that case:
[DEBUG][2025-11-29 15:21:55] ...m/lsp/client.lua:674 "LSP[gopls]" "client.request" 1 "textDocument/codeAction" { context = { diagnostics = {}, only = { "source.organizeImports" }, triggerKind = 2 }, range = { ["end"] = <1>{ character = 0, line = 0 }, start = <table 1> }, textDocument = { uri = "file:///home/jon/github/capz/main.go" } } <function 1> 1
[DEBUG][2025-11-29 15:21:55] .../vim/lsp/rpc.lua:277 "rpc.send" { id = 5, jsonrpc = "2.0", method = "textDocument/codeAction", params = { context = { diagnostics = {}, only = { "source.organizeImports" }, triggerKind = 2 }, range = { ["end"] = <1>{ character = 0, line = 0 }, start = <table 1> }, textDocument = { uri = "file:///home/jon/github/capz/main.go" } } }
[DEBUG][2025-11-29 15:21:55] .../vim/lsp/rpc.lua:391 "rpc.receive" { id = 5, jsonrpc = "2.0" }
Log Output
info ( main ): Starting ZLS 0.15.0 @ '/home/jon/github/zls/zig-out/bin/zls'
info ( main ): Log File: /home/jon/.cache/zls/zls.log (debug)
info ( main ): Loaded config: /home/jon/.config/zls.json
info (server): Client Info: Neovim (0.11.5+v0.11.5)
debug (server): Offset Encoding: 'utf-8'
info (server): Set config option 'enable_build_on_save' to true
info (server): Set config option 'warn_style' to true
info (server): Set config option 'builtin_path' to "/home/jon/.cache/zls/builtin.zig"
info (server): Set config option 'zig_lib_path' to "/usr/lib/zig"
info (server): Set config option 'zig_exe_path' to "/usr/bin/zig"
info (server): Set config option 'build_runner_path' to "/home/jon/.cache/zls/build_runner/cf46548b062a7e79e448e80c05616097/build_runner.zig"
info (server): Set config option 'global_cache_path' to "/home/jon/.cache/zls"