-
Notifications
You must be signed in to change notification settings - Fork 196
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add scrollbar to autocomplete menu (#259)
* feat: add scrollbar to autocomplete menu * feat: split up scrollbar code, add highlight groups, handle borders * feat: make scrollbar configurable, add for all windows --------- Co-authored-by: Liam Dyer <liamcdyer@gmail.com>
- Loading branch information
Showing
10 changed files
with
245 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
--- Helper for calculating placement of the scrollbar thumb and gutter | ||
|
||
--- @class blink.cmp.ScrollbarGeometry | ||
--- @field width number | ||
--- @field height number | ||
--- @field row number | ||
--- @field col number | ||
--- @field zindex number | ||
--- @field relative string | ||
--- @field win number | ||
|
||
local M = {} | ||
|
||
--- @param target_win number | ||
--- @return number | ||
local function get_win_buf_height(target_win) | ||
local buf = vim.api.nvim_win_get_buf(target_win) | ||
|
||
-- not wrapping, so just get the line count | ||
if not vim.wo[target_win].wrap then return vim.api.nvim_buf_line_count(buf) end | ||
|
||
local width = vim.api.nvim_win_get_width(target_win) | ||
local lines = vim.api.nvim_buf_get_lines(buf, 0, -1, false) | ||
local height = 0 | ||
for _, l in ipairs(lines) do | ||
height = height + math.max(1, (math.ceil(vim.fn.strwidth(l) / width))) | ||
end | ||
return height | ||
end | ||
|
||
--- @param target_win number | ||
--- @return { should_hide: boolean, thumb: blink.cmp.ScrollbarGeometry, gutter: blink.cmp.ScrollbarGeometry } | ||
function M.get_geometry(target_win) | ||
local width = vim.api.nvim_win_get_width(target_win) | ||
local height = vim.api.nvim_win_get_height(target_win) | ||
local zindex = vim.api.nvim_win_get_config(target_win).zindex or 1 | ||
|
||
local buf_height = get_win_buf_height(target_win) | ||
|
||
local thumb_height = math.max(1, math.floor(height * height / buf_height + 0.5) - 1) | ||
|
||
local start_line = math.max(1, vim.fn.line('w0', target_win) - 1) | ||
local pct = (start_line - 1) / buf_height | ||
local thumb_offset = math.ceil(pct * (height - thumb_height)) | ||
|
||
local common_geometry = { | ||
width = 1, | ||
row = thumb_offset, | ||
col = width, | ||
relative = 'win', | ||
win = target_win, | ||
} | ||
|
||
return { | ||
should_hide = height >= buf_height, | ||
thumb = vim.tbl_deep_extend('force', common_geometry, { height = thumb_height, zindex = zindex + 2 }), | ||
gutter = vim.tbl_deep_extend('force', common_geometry, { row = 0, height = height, zindex = zindex + 1 }), | ||
} | ||
end | ||
|
||
return M |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
--- @class blink.cmp.ScrollbarConfig | ||
--- @field enable_gutter boolean | ||
|
||
--- @class blink.cmp.Scrollbar | ||
--- @field target_win? number | ||
--- @field win? blink.cmp.ScrollbarWin | ||
--- @field autocmd? number | ||
--- | ||
--- @field new fun(opts: blink.cmp.ScrollbarConfig): blink.cmp.Scrollbar | ||
--- @field is_mounted fun(self: blink.cmp.Scrollbar): boolean | ||
--- @field mount fun(self: blink.cmp.Scrollbar, target_win: number) | ||
--- @field unmount fun(self: blink.cmp.Scrollbar) | ||
|
||
--- @type blink.cmp.Scrollbar | ||
--- @diagnostic disable-next-line: missing-fields | ||
local scrollbar = {} | ||
|
||
function scrollbar.new(opts) | ||
local self = setmetatable({}, { __index = scrollbar }) | ||
self.win = require('blink.cmp.windows.lib.scrollbar.win').new(opts) | ||
return self | ||
end | ||
|
||
function scrollbar:is_mounted() return self.autocmd ~= nil end | ||
|
||
function scrollbar:mount(target_win) | ||
-- unmount existing scrollbar if the target window changed | ||
if self.target_win ~= target_win then | ||
if not vim.api.nvim_win_is_valid(target_win) then return end | ||
self:unmount() | ||
end | ||
-- ignore if already mounted | ||
if self:is_mounted() then return end | ||
|
||
local geometry = require('blink.cmp.windows.lib.scrollbar.geometry').get_geometry(target_win) | ||
self.win:show_thumb(geometry.thumb) | ||
self.win:show_gutter(geometry.gutter) | ||
|
||
local function update() | ||
if not vim.api.nvim_win_is_valid(target_win) then return self:unmount() end | ||
|
||
local updated_geometry = require('blink.cmp.windows.lib.scrollbar.geometry').get_geometry(target_win) | ||
if updated_geometry.should_hide then return self.win:hide_thumb() end | ||
|
||
self.win:show_thumb(updated_geometry.thumb) | ||
self.win:show_gutter(updated_geometry.gutter) | ||
end | ||
-- HACK: for some reason, the autocmds don't fire on the initial mount | ||
-- so we apply after on the next event loop iteration after the windows are definitely setup | ||
vim.schedule(update) | ||
|
||
self.autocmd = vim.api.nvim_create_autocmd( | ||
{ 'WinScrolled', 'WinClosed', 'WinResized', 'CursorMoved', 'CursorMovedI' }, | ||
{ callback = update } | ||
) | ||
end | ||
|
||
function scrollbar:unmount() | ||
self.win:hide() | ||
|
||
if self.autocmd then vim.api.nvim_del_autocmd(self.autocmd) end | ||
self.autocmd = nil | ||
end | ||
|
||
return scrollbar |
Oops, something went wrong.