Skip to content

Commit 8a7cf7e

Browse files
committed
fix(completion): use insert_snippet if candidate has tab or newline
Details: - If LSP candidate is marked as snippet but doesn't look like it (as is often the case in `gopls`), then 'mini.completion' inserts candidate's text as is. Otherwise snippet insert might "eat" next non-keyword character. The "looks like snippet" was equivalent to "contains either tabstop or variable". However, it is also beneficial to check for newlines and tabs, as `snippet_insert` might want to deal with text reindent and tab expand. Resolve #2070
1 parent ecd602f commit 8a7cf7e

File tree

4 files changed

+27
-18
lines changed

4 files changed

+27
-18
lines changed

doc/mini-completion.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,8 +118,8 @@ Notes:
118118
- To stop LSP server from suggesting snippets, disable (set to `false`) the
119119
following capability during LSP server start:
120120
`textDocument.completion.completionItem.snippetSupport`.
121-
- If snippet body doesn't contain tabstops, `lsp_completion.snippet_insert`
122-
is not called and text is inserted as is.
121+
- If snippet body doesn't contain tabstop, variable, tab, or newline,
122+
`lsp_completion.snippet_insert` is not called and text is inserted as-is.
123123

124124
# Notes ~
125125

lua/mini/completion.lua

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,8 @@
116116
--- - To stop LSP server from suggesting snippets, disable (set to `false`) the
117117
--- following capability during LSP server start:
118118
--- `textDocument.completion.completionItem.snippetSupport`.
119-
--- - If snippet body doesn't contain tabstops, `lsp_completion.snippet_insert`
120-
--- is not called and text is inserted as is.
119+
--- - If snippet body doesn't contain tabstop, variable, tab, or newline,
120+
--- `lsp_completion.snippet_insert` is not called and text is inserted as-is.
121121
---
122122
--- # Notes ~
123123
---
@@ -1243,11 +1243,14 @@ H.lsp_completion_response_items_to_complete_items = function(items)
12431243

12441244
local is_snippet_kind = item.kind == snippet_kind
12451245
local is_snippet_format = item.insertTextFormat == snippet_inserttextformat
1246-
-- Treat item as snippet only if it has tabstops or variables. This is
1247-
-- important to make "implicit" expand work with LSP servers that report
1248-
-- even regular words as `InsertTextFormat.Snippet` (like `gopls`).
1249-
local needs_snippet_insert = (is_snippet_kind or is_snippet_format)
1250-
and (word:find('[^\\]%${?%w') ~= nil or word:find('^%${?%w') ~= nil)
1246+
-- Treat item as snippet only if it has tabstop, variable, tab, or newline.
1247+
-- It is important to make "implicit" expand work with LSP servers that
1248+
-- report even regular words as `InsertTextFormat.Snippet` (like `gopls`).
1249+
-- Otherwise it will "eat" the next typed non-keyword charater.
1250+
-- Account for tabs and newline to allow `snippet_insert` to deal with
1251+
-- reindenting and tab expansion.
1252+
local has_snippet_features = (word:find('[^\\]%${?%w') or word:find('^%${?%w') or word:find('[\n\t]')) ~= nil
1253+
local needs_snippet_insert = (is_snippet_kind or is_snippet_format) and has_snippet_features
12511254

12521255
local details = item.labelDetails or {}
12531256
-- NOTE: Using `table.concat({}, ' ')` would be cleaner but less performant

tests/screenshots/tests-test_completion.lua---Snippets---are-not-inserted-if-have-no-tabstops-or-variables

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
--|---------|---------|---------|---------|---------|--
22
01|
3-
02|Just^@text Snippet
3+
02|Just text Snippet
44
03|Text with \$1 escaped dollar Snippet
55
04|Text with \$TM_FILENAME escaped dollar Snippet
66
05|Text with \${1} escaped dollar Snippet
@@ -15,9 +15,11 @@
1515
14|Has $0 tabstop Snippet S
1616
15|Has ${0} tabstop Snippet S
1717
16|Has tabstop$0 Snippet S
18-
17|~
19-
18|[No Name] 0,1
20-
19|-- INSERT --
18+
17|Has tab Snippet S
19+
18|Has^@newline Snippet S
20+
19|~
21+
20|[No Name] 0,1
22+
21|-- INSERT --
2123

2224
--|---------|---------|---------|---------|---------|--
2325
01|0000000000000000000000000000000000000000000000000000
@@ -36,6 +38,8 @@
3638
14|1111111111111111111111111111111111111111111111111112
3739
15|1111111111111111111111111111111111111111111111111112
3840
16|1111111111111111111111111111111111111111111111111112
39-
17|2222222222222222222222222222222222222222222222222222
40-
18|3333333333333333333333333333333333333333333333333333
41-
19|4444444444445555555555555555555555555555555555555555
41+
17|1111111111111111111111111111111111111111111111111112
42+
18|1111111111111111111111111111111111111111111111111112
43+
19|2222222222222222222222222222222222222222222222222222
44+
20|3333333333333333333333333333333333333333333333333333
45+
21|4444444444445555555555555555555555555555555555555555

tests/test_completion.lua

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2557,10 +2557,10 @@ T['Snippets']['are not inserted if have no tabstops or variables'] = function()
25572557
-- Treating text as snippet if there is a variable is important for a snippet
25582558
-- insert method to expand them.
25592559

2560-
child.set_size(19, 52)
2560+
child.set_size(21, 52)
25612561
local snippets = {
25622562
-- - No insert:
2563-
'Just\ntext',
2563+
'Just text',
25642564
[[Text with \$1 escaped dollar]],
25652565
[[Text with \$TM_FILENAME escaped dollar]],
25662566
[[Text with \${1} escaped dollar]],
@@ -2576,6 +2576,8 @@ T['Snippets']['are not inserted if have no tabstops or variables'] = function()
25762576
'Has $0 tabstop',
25772577
'Has ${0} tabstop',
25782578
'Has tabstop$0',
2579+
'Has\ttab',
2580+
'Has\nnewline',
25792581
}
25802582
mock_lsp_snippets(snippets)
25812583

0 commit comments

Comments
 (0)