Inconsistent completion of function parentheses when snippets are disabled
Zig Version
0.13.0
Zig Language Server Version
0.13.0
Client / Code Editor / Extensions
vscode-zig
Steps to Reproduce and Observed Behavior
I have zig.zls.enableSnippets set to false in the settings. Despite this, ZLS completes function call parentheses differently depending on the signature, sometimes inserting just the function name and other times inserting the function name followed by (). This inconsistent behavior is undesirable and hurts muscle memory. I disabled snippets because I prefer just completing the names without any automatic insertion of parentheses.
fn functionZero() void {}
fn functionOne(a: i32) void {
_ = a;
}
fn functionAnytype(a: anytype) void {
_ = a;
}
const Foo = struct {
fn method(foo: Foo) void {
_ = foo;
}
};
pub fn main() void {
const foo: Foo = .{};
_ = &foo;
// Below, '_' represents the position of the caret
// "funZ_"
// <tab>
// "functionZero()_"
// "funO_"
// <tab>
// "functionOne_"
// "funA_"
// <tab>
// "functionAnytype()_"
// "foo.m_"
// <tab>
// "foo.method()_"
}
Of note is that when snippets are enabled, completion of the anytype function places the caret after the inserted () and not inbetween, so this is a bug regardless of whether the user has enabled snippets.
Expected Behavior
When snippets are disabled, only the name should be inserted. The parentheses should never be inserted regardless of whether the call takes any arguments or not.
I fixed this problem for myself locally by making the following changes to completions.zig:
diff --git a/src/features/completions.zig b/src/features/completions.zig
index 599f781..9cc4ff9 100644
--- a/src/features/completions.zig
+++ b/src/features/completions.zig
@@ -329,7 +329,8 @@ fn functionTypeCompletion(
const new_text = switch (new_text_format) {
.only_name => func_name,
.snippet => blk: {
- if (use_snippets and builder.server.config.enable_argument_placeholders) {
+ if (!use_snippets) break :blk func_name;
+ if (builder.server.config.enable_argument_placeholders) {
break :blk try std.fmt.allocPrint(builder.arena, "{}", .{Analyser.fmtFunction(.{
.fn_proto = func,
.tree = &tree,
@@ -358,12 +359,10 @@ fn functionTypeCompletion(
}
// Non-self parameter, leave the cursor in the parentheses
- if (!use_snippets) break :blk func_name;
break :blk try std.fmt.allocPrint(builder.arena, "{s}(${{1:}})", .{func_name});
},
else => {
// Atleast one non-self parameter, leave the cursor in the parentheses
- if (!use_snippets) break :blk func_name;
break :blk try std.fmt.allocPrint(builder.arena, "{s}(${{1:}})", .{func_name});
},
}
This is enough for me but I'm not sure if it's a good general solution.
Relevant log output
No response
Appearantly, that behavior is desired:
add empty parentheses when there are no arguments even if snippets are disabled
https://github.com/zigtools/zls/pull/1763
add empty parentheses when there are no arguments even if snippets are disabled
I still have parens with enable_snippets == false, but the problem is not snippets.
Turns out, nvim adds completionItem.labelDetails.detail after completion text automatically. And in case of builtins and functions zls sets it to () here:
https://github.com/zigtools/zls/blob/706e08fc80e6c21650f54e5aab91dbe8fb441f0f/src/features/completions.zig#L434
Workaround is to remove labelDetailsSupport client capability in nvim like so:
local capabilities = require("blink.cmp").get_lsp_capabilities()
capabilities.textDocument.completion.completionItem.labelDetailsSupport = false