This repository was archived by the owner on Oct 13, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 74
Expand file tree
/
Copy pathcompletion.lua
More file actions
276 lines (247 loc) · 9.07 KB
/
completion.lua
File metadata and controls
276 lines (247 loc) · 9.07 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
local vim = vim
local api = vim.api
local match = require'completion.matching'
local source = require 'completion.source'
local signature = require'completion.signature_help'
local hover = require'completion.hover'
local opt = require'completion.option'
local manager = require'completion.manager'
local M = {}
------------------------------------------------------------------------
-- external commands --
------------------------------------------------------------------------
M.insertCompletionItems = function(completed_items, prefix, item)
match.matching(completed_items, prefix, item)
end
M.addCompletionSource = function(key, completed_item)
source.addCompleteItems(key, completed_item)
end
M.nextSource = function()
source.nextCompletion()
end
M.prevSource = function()
source.prevCompletion()
end
M.triggerCompletion = function()
source.triggerCompletion(true, manager)
end
M.completionToggle = function()
local enable = vim.b.completion_enable
if enable == nil then
M.on_attach()
elseif enable == 0 then
vim.b.completion_enable = 1
else
vim.b.completion_enable = 0
end
end
------------------------------------------------------------------------
-- smart tab --
------------------------------------------------------------------------
function M.smart_tab()
if vim.fn.pumvisible() ~= 0 then
api.nvim_eval([[feedkeys("\<c-n>", "n")]])
return
end
local col = vim.fn.col('.') - 1
if col == 0 or vim.fn.getline('.'):sub(col, col):match('%s') then
api.nvim_eval([[feedkeys("\<tab>", "n")]])
return
end
source.triggerCompletion(true, manager)
end
function M.smart_s_tab()
if vim.fn.pumvisible() ~= 0 then
api.nvim_eval([[feedkeys("\<c-p>", "n")]])
return
end
api.nvim_eval([[feedkeys("\<s-tab>", "n")]])
end
------------------------------------------------------------------------
-- confirm completion --
------------------------------------------------------------------------
-- I want to deprecate this...
local function autoAddParens(completed_item)
if completed_item.kind == nil then return end
if string.match(completed_item.kind, '.*Function.*') ~= nil or string.match(completed_item.kind, '.*Method.*') then
api.nvim_input("()<left>")
end
end
-- Workaround to avoid expand snippets when not confirm
-- confirmCompletion is now triggered by CompleteDone autocmd to solve issue with noselect
-- Will cause snippets to expand with not pressing confirm key
-- Add a flag completionConfirm to avoid this issue
function M.confirmCompletion(completed_item)
manager.confirmedCompletion = true
end
-- apply additionalTextEdits in LSP specs
local function applyAddtionalTextEdits(completed_item)
local lnum = api.nvim_win_get_cursor(0)[1]
if completed_item.user_data.lsp ~= nil then
local item = completed_item.user_data.lsp.completion_item
-- vim-vsnip have better additional text edits...
if vim.fn.exists('g:loaded_vsnip_integ') == 1 then
api.nvim_call_function('vsnip_integ#do_complete_done', {
{
completed_item = completed_item,
completion_item = item,
apply_additional_text_edits = true
}
})
else
if next(item.additionalTextEdits or {}) then
local bufnr = api.nvim_get_current_buf()
local edits = vim.tbl_filter(
function(x) return x.range.start.line ~= (lnum - 1) end,
item.additionalTextEdits
)
vim.lsp.util.apply_text_edits(edits, bufnr)
else
vim.lsp.buf_request(bufnr, "completionItem/resolve", item, function(err, _, result)
if err or not result then
return
end
if result.additionalTextEdits then
vim.lsp.util.apply_text_edits(result.additionalTextEdits, bufnr)
end
end)
end
end
end
end
-- handle completeDone stuff here
local function hasConfirmedCompletion()
local completed_item = api.nvim_get_vvar('completed_item')
if completed_item.user_data == nil then return end
if completed_item.user_data.lsp ~= nil then
applyAddtionalTextEdits(completed_item)
if opt.get_option('enable_snippet') == "snippets.nvim" then
require 'snippets'.expand_at_cursor(completed_item.user_data.actual_item, completed_item.word)
end
end
if opt.get_option('enable_auto_paren') == 1 then
autoAddParens(completed_item)
end
if completed_item.user_data.snippet_source == 'UltiSnips' then
api.nvim_call_function('UltiSnips#ExpandSnippet', {})
elseif completed_item.user_data.snippet_source == 'Neosnippet' then
api.nvim_input("<c-r>".."=neosnippet#expand('"..completed_item.word.."')".."<CR>")
elseif completed_item.user_data.snippet_source == 'vim-vsnip' then
api.nvim_call_function('vsnip#anonymous', {
table.concat(completed_item.user_data.snippet_body, "\n"),
{
prefix = completed_item.word
}
})
elseif completed_item.user_data.snippet_source == 'snippets.nvim' then
require'snippets'.expand_at_cursor()
end
end
------------------------------------------------------------------------
-- autocommands --
------------------------------------------------------------------------
function M.on_InsertCharPre()
manager.insertChar = true
manager.textHover = true
manager.selected = -1
end
function M.on_InsertLeave()
manager.insertLeave = true
end
-- TODO: need further refactor, very messy now:(
function M.on_InsertEnter()
local enable = vim.b.completion_enable
if enable == nil or enable == 0 then
return
end
local timer = vim.loop.new_timer()
-- setup variable
manager.init()
-- TODO: remove this
local autoChange = false
if opt.get_option('auto_change_source') == 1 then
autoChange = true
end
-- reset source
manager.chainIndex = 1
source.stop_complete = false
local l_complete_index = manager.chainIndex
local timer_cycle = opt.get_option('timer_cycle')
timer:start(100, timer_cycle, vim.schedule_wrap(function()
local l_changedTick = api.nvim_buf_get_changedtick(0)
-- complete if changes are made
if l_changedTick ~= manager.changedTick then
manager.changedTick = l_changedTick
if opt.get_option('enable_auto_popup') == 1 then
source.autoCompletion()
end
if opt.get_option('enable_auto_hover') == 1 then
hover.autoOpenHoverInPopup(manager)
end
if opt.get_option('enable_auto_signature') == 1 then
signature.autoOpenSignatureHelp()
end
end
-- change source if no item is available
if manager.changeSource and autoChange then
manager.changeSource = false
if manager.chainIndex ~= source.chain_complete_length then
manager.chainIndex = manager.chainIndex + 1
l_complete_index = manager.chainIndex
manager.insertChar = true
source.triggerCompletion(false, manager)
else
source.stop_complete = true
end
end
-- force trigger completion when manaully chaging source
if l_complete_index ~= manager.chainIndex then
-- force clear completion
if vim.api.nvim_get_mode()['mode'] == 'i' or vim.api.nvim_get_mode()['mode'] == 'ic' then
vim.fn.complete(vim.api.nvim_win_get_cursor(0)[2], {})
end
source.triggerCompletion(false, manager)
l_complete_index = manager.chainIndex
end
-- closing timer if leaving insert mode
if manager.insertLeave == true and timer:is_closing() == false then
timer:stop()
timer:close()
end
end))
end
-- handle completion confirmation and dismiss hover popup
function M.on_CompleteDone()
if manager.confirmedCompletion then
manager.confirmedCompletion = false
hasConfirmedCompletion()
-- auto trigger signature help when we confirm completion
if vim.g.completion_enable_auto_signature ~= 0 then
signature.autoOpenSignatureHelp()
end
end
if hover.winnr ~= nil and api.nvim_win_is_valid(hover.winnr) then
api.nvim_win_close(hover.winnr, true)
end
end
M.on_attach = function(option)
-- setup completion_option tables
opt.set_option_table(option)
-- setup autocommand
-- TODO: Modified this if lua callbacks for autocmd is merged
api.nvim_command("augroup CompletionCommand")
api.nvim_command("autocmd! * <buffer>")
api.nvim_command("autocmd InsertEnter <buffer> lua require'completion'.on_InsertEnter()")
api.nvim_command("autocmd InsertLeave <buffer> lua require'completion'.on_InsertLeave()")
api.nvim_command("autocmd InsertCharPre <buffer> lua require'completion'.on_InsertCharPre()")
api.nvim_command("autocmd CompleteDone <buffer> lua require'completion'.on_CompleteDone()")
api.nvim_command("augroup end")
if string.len(opt.get_option('confirm_key')) ~= 0 then
api.nvim_buf_set_keymap(0, 'i', opt.get_option('confirm_key'),
'pumvisible() ? complete_info()["selected"] != "-1" ? "\\<Plug>(completion_confirm_completion)" :'..
' "\\<c-e>\\<CR>" : "\\<CR>"',
{silent=false, noremap=false, expr=true})
end
vim.b.completion_enable = 1
end
return M