From 371ad288544423531121c1abf0d519dda791e9f1 Mon Sep 17 00:00:00 2001 From: Lopy <70210066+lopi-py@users.noreply.github.com> Date: Sun, 10 Nov 2024 17:13:00 -0500 Subject: [PATCH] fix: handle gap for empty text (#301) * fix: handle gap for empty text fix: set kind component fill to true * refactor: minor stylistic changes --------- Co-authored-by: Liam Dyer --- README.md | 15 ++++--- lua/blink/cmp/config.lua | 17 ++++---- lua/blink/cmp/utils.lua | 6 +-- lua/blink/cmp/windows/render/column.lua | 54 +++++++++++++------------ lua/blink/cmp/windows/render/init.lua | 45 +++++++++------------ lua/blink/cmp/windows/render/types.lua | 2 +- 6 files changed, 66 insertions(+), 73 deletions(-) diff --git a/README.md b/README.md index 14ea0413..682e2075 100644 --- a/README.md +++ b/README.md @@ -429,19 +429,20 @@ MiniDeps.add({ components = { kind_icon = { ellipsis = false, - text = function(ctx) return ctx.kind_icon .. ' ' end, + text = function(ctx) return ctx.kind_icon end, highlight = function(ctx) return 'BlinkCmpKind' .. ctx.kind end, }, kind = { ellipsis = false, - text = function(ctx) return ctx.kind .. ' ' end, + width = { fill = true }, + text = function(ctx) return ctx.kind end, highlight = function(ctx) return 'BlinkCmpKind' .. ctx.kind end, }, label = { width = { fill = true, max = 60 }, - text = function(ctx) return ctx.label .. (ctx.label_detail or '') end, + text = function(ctx) return ctx.label .. ctx.label_detail end, highlight = function(ctx) -- label and label details local highlights = { @@ -452,10 +453,8 @@ MiniDeps.add({ end -- characters matched on the label by the fuzzy matcher - if ctx.label_matched_indices ~= nil then - for _, idx in ipairs(ctx.label_matched_indices) do - table.insert(highlights, { idx, idx + 1, group = 'BlinkCmpLabelMatch' }) - end + for _, idx in ipairs(ctx.label_matched_indices) do + table.insert(highlights, { idx, idx + 1, group = 'BlinkCmpLabelMatch' }) end return highlights @@ -464,7 +463,7 @@ MiniDeps.add({ label_description = { width = { max = 30 }, - text = function(ctx) return ctx.label_description or '' end, + text = function(ctx) return ctx.label_description end, highlight = 'BlinkCmpLabelDescription', }, }, diff --git a/lua/blink/cmp/config.lua b/lua/blink/cmp/config.lua index c6652e7c..1dfcb263 100644 --- a/lua/blink/cmp/config.lua +++ b/lua/blink/cmp/config.lua @@ -270,7 +270,7 @@ local config = { timeout_ms = 400, }, }, - expand_snippet = vim.snippet.expand + expand_snippet = vim.snippet.expand, }, trigger = { @@ -407,19 +407,20 @@ local config = { components = { kind_icon = { ellipsis = false, - text = function(ctx) return ctx.kind_icon .. ' ' end, + text = function(ctx) return ctx.kind_icon end, highlight = function(ctx) return 'BlinkCmpKind' .. ctx.kind end, }, kind = { ellipsis = false, - text = function(ctx) return ctx.kind .. ' ' end, + width = { fill = true }, + text = function(ctx) return ctx.kind end, highlight = function(ctx) return 'BlinkCmpKind' .. ctx.kind end, }, label = { width = { fill = true, max = 60 }, - text = function(ctx) return ctx.label .. (ctx.label_detail or '') end, + text = function(ctx) return ctx.label .. ctx.label_detail end, highlight = function(ctx) -- label and label details local label = ctx.label @@ -431,10 +432,8 @@ local config = { end -- characters matched on the label by the fuzzy matcher - if ctx.label_matched_indices ~= nil then - for _, idx in ipairs(ctx.label_matched_indices) do - table.insert(highlights, { idx, idx + 1, group = 'BlinkCmpLabelMatch' }) - end + for _, idx in ipairs(ctx.label_matched_indices) do + table.insert(highlights, { idx, idx + 1, group = 'BlinkCmpLabelMatch' }) end return highlights @@ -443,7 +442,7 @@ local config = { label_description = { width = { max = 30 }, - text = function(ctx) return ctx.label_description or '' end, + text = function(ctx) return ctx.label_description end, highlight = 'BlinkCmpLabelDescription', }, }, diff --git a/lua/blink/cmp/utils.lua b/lua/blink/cmp/utils.lua index 0cda93db..f81209ac 100644 --- a/lua/blink/cmp/utils.lua +++ b/lua/blink/cmp/utils.lua @@ -83,7 +83,7 @@ function utils.get_regex_around_cursor(range, regex, exclude_from_prefix_regex) return { start_col = start_col, length = length } end ---- @param ctx blink.cmp.CompletionRenderContext +--- @param ctx blink.cmp.DrawItemContext --- @return string|nil function utils.try_get_tailwind_hl(ctx) local doc = ctx.item.documentation @@ -91,9 +91,7 @@ function utils.try_get_tailwind_hl(ctx) local content = type(doc) == 'string' and doc or doc.value if ctx.kind == 'Color' and content and content:match('^#%x%x%x%x%x%x$') then local hl_name = 'HexColor' .. content:sub(2) - if #vim.api.nvim_get_hl(0, { name = hl_name }) == 0 then - vim.api.nvim_set_hl(0, hl_name, { fg = content }) - end + if #vim.api.nvim_get_hl(0, { name = hl_name }) == 0 then vim.api.nvim_set_hl(0, hl_name, { fg = content }) end return hl_name end end diff --git a/lua/blink/cmp/windows/render/column.lua b/lua/blink/cmp/windows/render/column.lua index b3b95af3..bf2f6e0d 100644 --- a/lua/blink/cmp/windows/render/column.lua +++ b/lua/blink/cmp/windows/render/column.lua @@ -3,11 +3,11 @@ --- @field gap number --- @field lines string[][] --- @field width number ---- @field ctxs blink.cmp.CompletionRenderContext[] +--- @field ctxs blink.cmp.DrawItemContext[] --- --- @field new fun(components: blink.cmp.DrawComponent[], gap: number): blink.cmp.DrawColumn --- @field render fun(self: blink.cmp.DrawColumn, ctxs: blink.cmp.DrawItemContext[]) ---- @field get_line_text fun(self: blink.cmp.DrawColumn, line_idx: number): string[] +--- @field get_line_text fun(self: blink.cmp.DrawColumn, line_idx: number): string --- @field get_line_highlights fun(self: blink.cmp.DrawColumn, line_idx: number): blink.cmp.DrawHighlight[] local text_lib = require('blink.cmp.windows.render.text') @@ -46,9 +46,9 @@ function column:render(ctxs) --- get the total width of the column local column_width = 0 for _, max_component_width in ipairs(max_component_widths) do - column_width = column_width + max_component_width + if max_component_width > 0 then column_width = column_width + max_component_width + self.gap end end - column_width = column_width + self.gap * (#self.components - 1) + column_width = math.max(column_width - self.gap, 0) --- find the component that will fill the empty space local fill_idx = -1 @@ -63,9 +63,10 @@ function column:render(ctxs) --- and add extra spaces until we reach the column width for _, line in ipairs(lines) do local line_width = 0 - for idx, component_text in ipairs(line) do - line_width = line_width + vim.api.nvim_strwidth(component_text) + (idx == #line and 0 or self.gap) + for _, component_text in ipairs(line) do + if #component_text > 0 then line_width = line_width + vim.api.nvim_strwidth(component_text) + self.gap end end + line_width = line_width - self.gap local remaining_width = column_width - line_width line[fill_idx] = text_lib.pad(line[fill_idx], vim.api.nvim_strwidth(line[fill_idx]) + remaining_width) end @@ -77,12 +78,12 @@ function column:render(ctxs) end function column:get_line_text(line_idx) + local text = '' local line = self.lines[line_idx] - local concatenated = '' - for idx, component in ipairs(line) do - concatenated = concatenated .. component .. string.rep(' ', idx == #line and 0 or self.gap) + for _, component in ipairs(line) do + if #component > 0 then text = text .. component .. string.rep(' ', self.gap) end end - return concatenated + return text:sub(1, -self.gap - 1) end function column:get_line_highlights(line_idx) @@ -92,24 +93,25 @@ function column:get_line_highlights(line_idx) for component_idx, component in ipairs(self.components) do local text = self.lines[line_idx][component_idx] - - local column_highlights = type(component.highlight) == 'function' and component.highlight(ctx, text) - or component.highlight - - if type(column_highlights) == 'string' then - table.insert(highlights, { offset, offset + #text, group = column_highlights }) - elseif type(column_highlights) == 'table' then - for _, highlight in ipairs(column_highlights) do - table.insert(highlights, { - offset + highlight[1], - offset + highlight[2], - group = highlight.group, - params = highlight.params, - }) + if #text > 0 then + local column_highlights = type(component.highlight) == 'function' and component.highlight(ctx, text) + or component.highlight + + if type(column_highlights) == 'string' then + table.insert(highlights, { offset, offset + #text, group = column_highlights }) + elseif type(column_highlights) == 'table' then + for _, highlight in ipairs(column_highlights) do + table.insert(highlights, { + offset + highlight[1], + offset + highlight[2], + group = highlight.group, + params = highlight.params, + }) + end end - end - offset = offset + #text + self.gap + offset = offset + #text + self.gap + end end return highlights diff --git a/lua/blink/cmp/windows/render/init.lua b/lua/blink/cmp/windows/render/init.lua index 32f7f2ee..1b42e7f7 100644 --- a/lua/blink/cmp/windows/render/init.lua +++ b/lua/blink/cmp/windows/render/init.lua @@ -64,10 +64,11 @@ function renderer:draw(bufnr, items) local line = '' if self.padding[1] > 0 then line = string.rep(' ', self.padding[1]) end - for column_idx, column in ipairs(self.columns) do - line = line .. column:get_line_text(idx) - if column_idx ~= #self.columns then line = line .. string.rep(' ', self.gap) end + for _, column in ipairs(self.columns) do + local text = column:get_line_text(idx) + if #text > 0 then line = line .. text .. string.rep(' ', self.gap) end end + line = line:sub(1, -self.gap - 1) if self.padding[2] > 0 then line = line .. string.rep(' ', self.padding[2]) end @@ -81,31 +82,25 @@ function renderer:draw(bufnr, items) -- like nvim-cmp does, which breaks on UIs like neovide vim.api.nvim_set_decoration_provider(ns, { on_win = function(_, _, win_bufnr) return bufnr == win_bufnr end, - on_line = function(_, _, _, line_number) + on_line = function(_, _, _, line) local offset = self.padding[1] - local highlights = {} - for _, column in ipairs(self.columns) do - local highlights_for_column = column:get_line_highlights(line_number + 1) - for _, highlight in ipairs(highlights_for_column) do - table.insert(highlights, { - offset + highlight[1], - offset + highlight[2], - group = highlight.group, - params = highlight.params, - }) + local text = column:get_line_text(line + 1) + if #text > 0 then + local highlights = column:get_line_highlights(line + 1) + for _, highlight in ipairs(highlights) do + local col = offset + highlight[1] + local end_col = offset + highlight[2] + vim.api.nvim_buf_set_extmark(bufnr, ns, line, col, { + end_col = end_col, + hl_group = highlight.group, + hl_mode = 'combine', + hl_eol = true, + ephemeral = true, + }) + end + offset = offset + #text + self.gap end - offset = offset + #column:get_line_text(line_number + 1) + self.gap - end - - for _, highlight in ipairs(highlights) do - vim.api.nvim_buf_set_extmark(bufnr, ns, line_number, highlight[1], { - end_col = highlight[2], - hl_group = highlight.group, - hl_mode = 'combine', - hl_eol = true, - ephemeral = true, - }) end end, }) diff --git a/lua/blink/cmp/windows/render/types.lua b/lua/blink/cmp/windows/render/types.lua index 2ff9fa04..0f7a8443 100644 --- a/lua/blink/cmp/windows/render/types.lua +++ b/lua/blink/cmp/windows/render/types.lua @@ -19,5 +19,5 @@ --- @class blink.cmp.DrawComponent --- @field width? blink.cmp.DrawWidth --- @field ellipsis? boolean Whether to add an ellipsis when truncating the text ---- @field text fun(ctx: blink.cmp.DrawItemContext): string Renders the text of the component +--- @field text fun(ctx: blink.cmp.DrawItemContext): string? Renders the text of the component --- @field highlight? string | fun(ctx: blink.cmp.DrawItemContext, text: string): string | blink.cmp.DrawHighlight[] Renders the highlights of the component