From cfd1f9817f8e612d04d1f35561f72659f59d1900 Mon Sep 17 00:00:00 2001 From: Lee Cannon Date: Fri, 14 Jul 2023 20:18:39 +0100 Subject: [PATCH] completion: handle cursor placement Correctly handles cursor placement after a completion when placeholders are disabled but snippets are not. --- src/features/completions.zig | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/src/features/completions.zig b/src/features/completions.zig index 05c0461a9..62a0b568f 100644 --- a/src/features/completions.zig +++ b/src/features/completions.zig @@ -181,16 +181,33 @@ fn nodeToCompletion( const func = tree.fullFnProto(&buf, node).?; if (func.name_token) |name_token| { const use_snippets = server.config.enable_snippets and server.client_capabilities.supports_snippets; - const use_placeholders = server.config.enable_argument_placeholders and server.client_capabilities.supports_snippets; - const insert_text = if (use_snippets) blk: { - if (use_placeholders) { - const skip_self_param = !(parent_is_type_val orelse true) and - try server.analyser.hasSelfParam(handle, func); - break :blk try Analyser.getFunctionSnippet(allocator, tree, func, skip_self_param); - } else { - break :blk try std.fmt.allocPrint(allocator, "{s}()", .{tree.tokenSlice(func.name_token.?)}); + + const insert_text = blk: { + const func_name = tree.tokenSlice(func.name_token.?); + + if (!use_snippets) break :blk func_name; + + const skip_self_param = !(parent_is_type_val orelse true) and try server.analyser.hasSelfParam(handle, func); + + const use_placeholders = server.config.enable_argument_placeholders; + if (use_placeholders) break :blk try Analyser.getFunctionSnippet(allocator, tree, func, skip_self_param); + + switch (func.ast.params.len) { + // No arguments, leave cursor at the end + 0 => break :blk try std.fmt.allocPrint(allocator, "{s}()", .{func_name}), + 1 => { + if (skip_self_param) { + // The one argument is a self parameter, leave cursor at the end + break :blk try try std.fmt.allocPrint(allocator, "{s}()", .{func_name}); + } + + // Non-self parameter, leave the cursor in the parentheses + break :blk try try std.fmt.allocPrint(allocator, "{s}(${{1:}})", .{func_name}); + }, + // Atleast one non-self parameter, leave the cursor in the parentheses + else => break :blk try std.fmt.allocPrint(allocator, "{s}(${{1:}})", .{func_name}), } - } else tree.tokenSlice(func.name_token.?); + }; const is_type_function = Analyser.isTypeFunction(handle.tree, func);