Skip to content

Commit 4f3aa60

Browse files
committed
feat: config.view.entries.vertical_positioning = 'auto'|'above'|'below'
'above' works best with vim.opt.scrolloff = 999. Fixes: #495 Helped-by: Thanatermesis <thanatermesis@gmail.com>
1 parent 5dce1b7 commit 4f3aa60

3 files changed

Lines changed: 20 additions & 10 deletions

File tree

lua/cmp/config/default.lua

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ return function()
9494
entries = {
9595
name = 'custom',
9696
selection_order = 'top_down',
97+
vertical_positioning = 'below',
9798
},
9899
docs = {
99100
auto_open = true,

lua/cmp/types/cmp.lua

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@ cmp.ItemField = {
176176
---@class cmp.CustomEntriesViewConfig
177177
---@field name 'custom'
178178
---@field selection_order 'top_down'|'near_cursor'
179+
---@field vertical_positioning 'auto'|'above'|'below'
179180

180181
---@class cmp.NativeEntriesViewConfig
181182
---@field name 'native'

lua/cmp/view/custom_entries_view.lua

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,8 @@ custom_entries_view.is_direction_top_down = function(self)
117117
end
118118

119119
custom_entries_view.open = function(self, offset, entries)
120-
local completion = config.get().window.completion
120+
local c = config.get()
121+
local completion = c.window.completion
121122
self.offset = offset
122123
self.entries = {}
123124
self.column_width = { abbr = 0, kind = 0, menu = 0 }
@@ -161,12 +162,25 @@ custom_entries_view.open = function(self, offset, entries)
161162
local border_info = window.get_border_info({ style = completion })
162163
local border_offset_row = border_info.top + border_info.bottom
163164
local border_offset_col = border_info.left + border_info.right
164-
if math.floor(vim.o.lines * 0.5) <= row + border_offset_row and vim.o.lines - row - border_offset_row <= math.min(DEFAULT_HEIGHT, height) then
165+
166+
local prefers_above = c.view.entries.vertical_positioning == 'above'
167+
local prefers_auto = c.view.entries.vertical_positioning == 'auto'
168+
local cant_fit_at_bottom = vim.o.lines - row - border_offset_row <= math.min(DEFAULT_HEIGHT, height)
169+
local cant_fit_at_top = row - border_offset_row <= math.min(DEFAULT_HEIGHT, height)
170+
local is_in_top_half = math.floor(vim.o.lines * 0.5) > row + border_offset_row
171+
local should_position_above =
172+
cant_fit_at_bottom or
173+
(prefers_above and not cant_fit_at_top) or
174+
(prefers_auto and is_in_top_half)
175+
if should_position_above then
176+
self.bottom_up = true
165177
height = math.min(height, row - 1)
166178
row = row - height - border_offset_row - 1
167179
if row < 0 then
168180
height = height + row
169181
end
182+
else
183+
self.bottom_up = false
170184
end
171185
if math.floor(vim.o.columns * 0.5) <= col + border_offset_col and vim.o.columns - col - border_offset_col <= width then
172186
width = math.min(width, vim.o.columns - 1)
@@ -176,12 +190,6 @@ custom_entries_view.open = function(self, offset, entries)
176190
end
177191
end
178192

179-
if pos[1] > row then
180-
self.bottom_up = true
181-
else
182-
self.bottom_up = false
183-
end
184-
185193
if not self:is_direction_top_down() then
186194
local n = #self.entries
187195
for i = 1, math.floor(n / 2) do
@@ -208,9 +216,9 @@ custom_entries_view.open = function(self, offset, entries)
208216
})
209217
-- always set cursor when starting. It will be adjusted on the call to _select
210218
vim.api.nvim_win_set_cursor(self.entries_win.win, { 1, 0 })
211-
if preselect_index > 0 and config.get().preselect == types.cmp.PreselectMode.Item then
219+
if preselect_index > 0 and c.preselect == types.cmp.PreselectMode.Item then
212220
self:_select(preselect_index, { behavior = types.cmp.SelectBehavior.Select, active = false })
213-
elseif not string.match(config.get().completion.completeopt, 'noselect') then
221+
elseif not string.match(c.completion.completeopt, 'noselect') then
214222
if self:is_direction_top_down() then
215223
self:_select(1, { behavior = types.cmp.SelectBehavior.Select, active = false })
216224
else

0 commit comments

Comments
 (0)