@@ -59,14 +59,37 @@ M.accept = function(cmp_win)
59
59
end
60
60
end
61
61
62
- M .select_next = function (cmp_win )
62
+ M .select_next = function (cmp_win , doc_win )
63
+ if cmp_win .id == nil then return end
64
+
63
65
local current_line = vim .api .nvim_win_get_cursor (cmp_win .id )[1 ]
64
- vim .api .nvim_win_set_cursor (cmp_win .id , { current_line + 1 , 0 })
66
+ local item_count = # M .filtered_items
67
+ local line_count = vim .api .nvim_buf_line_count (cmp_win .buf )
68
+
69
+ -- draw a new line if we're at the end and there's more items
70
+ -- todo: this is a hack while waiting for virtual scroll
71
+ if current_line == line_count and item_count > line_count then
72
+ M .draw_item (cmp_win .buf , line_count + 1 , M .filtered_items [line_count + 1 ])
73
+ vim .api .nvim_win_set_cursor (cmp_win .id , { line_count + 1 , 0 })
74
+ -- otherwise just move the cursor, wrapping if at the bottom
75
+ else
76
+ local line = current_line == item_count and 1 or current_line + 1
77
+ vim .api .nvim_win_set_cursor (cmp_win .id , { line , 0 })
78
+ end
79
+
80
+ M .update_doc (cmp_win , doc_win )
65
81
end
66
82
67
- M .select_prev = function (cmp_win )
83
+ -- todo: how to handle overflow to the bottom? should probably just do proper virtual scroll
84
+ M .select_prev = function (cmp_win , doc_win )
85
+ if cmp_win .id == nil then return end
86
+
68
87
local current_line = vim .api .nvim_win_get_cursor (cmp_win .id )[1 ]
69
- vim .api .nvim_win_set_cursor (cmp_win .id , { current_line - 1 , 0 })
88
+ local line_count = vim .api .nvim_buf_line_count (cmp_win .buf )
89
+ local line = current_line - 1 == 0 and line_count or current_line - 1
90
+ vim .api .nvim_win_set_cursor (cmp_win .id , { line , 0 })
91
+
92
+ M .update_doc (cmp_win , doc_win )
70
93
end
71
94
72
95
M .update = function (cmp_win , doc_win , items , opts )
@@ -89,51 +112,74 @@ M.update = function(cmp_win, doc_win, items, opts)
89
112
90
113
-- update completion window
91
114
vim .api .nvim_buf_set_lines (cmp_win .buf , 0 , - 1 , true , {})
92
- for idx , item in ipairs (filtered_items ) do
93
- local max_length = 40
94
- local kind_hl = ' CmpItemKind' .. item .kind
95
- local kind_icon = M .kind_icons [item .kind ] or M .kind_icons .Field
96
- local kind = item .kind
97
-
98
- local utf8len = vim .fn .strdisplaywidth
99
- local other_content_length = utf8len (kind_icon ) + utf8len (kind ) + 5
100
- local remaining_length = math.max (0 , max_length - other_content_length - utf8len (item .abbr ))
101
- local abbr = string.sub (item .abbr , 1 , max_length - other_content_length ) .. string.rep (' ' , remaining_length )
102
-
103
- local line = string.format (' %s %s %s ' , kind_icon , abbr , kind )
104
- vim .api .nvim_buf_set_lines (cmp_win .buf , idx - 1 , idx , false , { line })
105
- vim .api .nvim_buf_add_highlight (cmp_win .buf , - 1 , kind_hl , idx - 1 , 0 , # kind_icon + 2 )
115
+ vim .api .nvim_buf_set_option (cmp_win .buf , ' modified' , false )
106
116
107
- if idx > cmp_win .config .max_height then break end
117
+ for idx , item in ipairs (filtered_items ) do
118
+ M .draw_item (cmp_win .buf , idx , item )
119
+ -- only draw until the window is full
120
+ if idx >= cmp_win .config .max_height then break end
108
121
end
109
-
110
- -- set height
111
- vim .api .nvim_win_set_height (cmp_win .id , math.min (# filtered_items , cmp_win .config .max_height ))
112
-
113
122
-- select first line
114
123
vim .api .nvim_win_set_cursor (cmp_win .id , { 1 , 0 })
124
+ cmp_win :update ()
115
125
116
126
-- documentation
117
- local first_item = filtered_items [1 ]
118
- if first_item ~= nil then
119
- M .lsp .resolve (first_item , function (_ , resolved_item )
120
- if resolved_item .detail == nil then
121
- doc_win :close ()
122
- return
123
- end
124
- local doc_lines = {}
125
- for s in resolved_item .detail :gmatch (' [^\r\n ]+' ) do
126
- table.insert (doc_lines , s )
127
- end
128
- vim .api .nvim_buf_set_lines (doc_win .buf , 0 , - 1 , true , doc_lines )
129
- doc_win :open ()
130
- end )
131
- end
127
+ M .update_doc (cmp_win , doc_win )
132
128
133
129
M .filtered_items = filtered_items
134
130
end
135
131
132
+ function M .update_doc (cmp_win , doc_win )
133
+ -- completion window isn't open
134
+ if cmp_win .id == nil then return end
135
+
136
+ local current_line = vim .api .nvim_win_get_cursor (cmp_win .id )[1 ]
137
+ local item = M .filtered_items [current_line ]
138
+ if item == nil then
139
+ doc_win :close ()
140
+ return
141
+ end
142
+
143
+ M .lsp .resolve (item , function (_ , resolved_item )
144
+ if resolved_item .detail == nil then
145
+ doc_win :close ()
146
+ return
147
+ end
148
+ local doc_lines = {}
149
+ for s in resolved_item .detail :gmatch (' [^\r\n ]+' ) do
150
+ table.insert (doc_lines , s )
151
+ end
152
+ vim .api .nvim_buf_set_lines (doc_win .buf , 0 , - 1 , true , doc_lines )
153
+ doc_win :open ()
154
+
155
+ -- set unmodified so we don't get the prompt to save
156
+ vim .api .nvim_buf_set_option (doc_win .buf , ' modified' , false )
157
+ end )
158
+ end
159
+
136
160
---- ------ UTILS ------------
161
+ M .draw_item = function (bufnr , idx , item )
162
+ -- get highlight
163
+ local kind_hl = ' CmpItemKind' .. item .kind
164
+ local kind_icon = M .kind_icons [item .kind ] or M .kind_icons .Field
165
+ local kind = item .kind
166
+
167
+ -- get line text
168
+ local max_length = 40
169
+ local utf8len = vim .fn .strdisplaywidth
170
+ local other_content_length = utf8len (kind_icon ) + utf8len (kind ) + 5
171
+ local remaining_length = math.max (0 , max_length - other_content_length - utf8len (item .abbr ))
172
+ local abbr = string.sub (item .abbr , 1 , max_length - other_content_length ) .. string.rep (' ' , remaining_length )
173
+
174
+ local line = string.format (' %s %s %s ' , kind_icon , abbr , kind )
175
+
176
+ -- draw the line
177
+ vim .api .nvim_buf_set_lines (bufnr , idx - 1 , idx , false , { line })
178
+ vim .api .nvim_buf_add_highlight (bufnr , - 1 , kind_hl , idx - 1 , 0 , # kind_icon + 2 )
179
+
180
+ -- set unmodified so we don't get the prompt to save
181
+ vim .api .nvim_buf_set_option (bufnr , ' modified' , false )
182
+ end
137
183
138
184
M .filter_items = function (query , items )
139
185
if query == ' ' then return items end
165
211
166
212
M .get_query_to_replace = function (bufnr )
167
213
local current_line = vim .api .nvim_win_get_cursor (0 )[1 ]
168
- local current_col = vim .api .nvim_win_get_cursor (0 )[2 ] + 1
214
+ local current_col = vim .api .nvim_win_get_cursor (0 )[2 ]
169
215
local line = vim .api .nvim_buf_get_lines (bufnr , current_line - 1 , current_line , false )[1 ]
170
216
171
217
-- Search forward/backward for the start/end of the word
@@ -184,7 +230,7 @@ M.get_query_to_replace = function(bufnr)
184
230
end
185
231
186
232
-- convert to 0-index
187
- return current_line - 1 , start_col - 1 , end_col - 1
233
+ return current_line - 1 , start_col - 1 , end_col
188
234
end
189
235
190
236
M .apply_additional_text_edits = function (client_id , item ) M .apply_text_edits (client_id , item .additionalTextEdits or {}) end
0 commit comments