Skip to content

Commit

Permalink
feat: custom documentation highlighting
Browse files Browse the repository at this point in the history
closes #113
  • Loading branch information
Saghen committed Oct 15, 2024
1 parent af68874 commit 90d6394
Show file tree
Hide file tree
Showing 3 changed files with 121 additions and 26 deletions.
94 changes: 94 additions & 0 deletions lua/blink/cmp/utils.lua
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,98 @@ function utils.is_special_buffer()
return buftype ~= ''
end

function utils.split_lines(text)
local lines = {}
for s in text:gmatch('[^\r\n]+') do
table.insert(lines, s)
end
return lines
end

--- Combines adjacent paragraph lines together
--- @param lines string[]
--- @return string[]
--- TODO: Likely buggy
function utils.combine_markdown_lines(lines)
local combined_lines = {}

local special_starting_chars = { '#', '>', '-', '|' }
local in_code_block = false
local prev_is_special = false
for _, line in ipairs(lines) do
if line:match('^%s*```') then in_code_block = not in_code_block end

local is_special = line:match('^%s*[' .. table.concat(special_starting_chars) .. ']') or line:match('^%s*%d\\.$')
local is_empty = line:match('^%s*$')
local has_linebreak = line:match('%s%s$')

if #combined_lines == 0 or in_code_block or is_special or prev_is_special or is_empty or has_linebreak then
table.insert(combined_lines, line)
elseif line:match('^%s*$') then
table.insert(combined_lines, '')
else
combined_lines[#combined_lines] = combined_lines[#combined_lines] .. '' .. line
end

prev_is_special = is_special
end

return combined_lines
end

function utils.highlight_with_treesitter(bufnr, root_lang, start_line, end_line)
local Range = require('vim.treesitter._range')

local trees = vim.treesitter.get_parser(bufnr, root_lang)
trees:parse({ start_line, end_line })
if not trees then return end

trees:for_each_tree(function(tree, tstree)
local lang = tstree:lang()
local highlighter_query = vim.treesitter.query.get(lang, 'highlights')
if not highlighter_query then return end

local root_node = tree:root()
local _, _, root_end_row, _ = root_node:range()

local iter = highlighter_query:iter_captures(tree:root(), bufnr, start_line, end_line)
local line = start_line
while line < end_line do
local capture, node, metadata, _ = iter(line)
if capture == nil then break end

local range = { root_end_row + 1, 0, root_end_row + 1, 0 }
if node then range = vim.treesitter.get_range(node, bufnr, metadata and metadata[capture]) end
local start_row, start_col, end_row, end_col = Range.unpack4(range)

if capture then
local name = highlighter_query.captures[capture]
local hl = 0
if not vim.startswith(name, '_') then hl = vim.api.nvim_get_hl_id_by_name('@' .. name .. '.' .. lang) end

-- The "priority" attribute can be set at the pattern level or on a particular capture
local priority = (
tonumber(metadata.priority or metadata[capture] and metadata[capture].priority)
or vim.highlight.priorities.treesitter
)

-- The "conceal" attribute can be set at the pattern level or on a particular capture
local conceal = metadata.conceal or metadata[capture] and metadata[capture].conceal

if hl and end_row >= line then
vim.api.nvim_buf_set_extmark(bufnr, require('blink.cmp.config').highlight.ns, start_row, start_col, {
end_line = end_row,
end_col = end_col,
hl_group = hl,
priority = priority,
conceal = conceal,
})
end
end

if start_row > line then line = start_row end
end
end)
end

return utils
51 changes: 26 additions & 25 deletions lua/blink/cmp/windows/documentation.lua
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
local config = require('blink.cmp.config').windows.documentation
local utils = require('blink.cmp.utils')
local sources = require('blink.cmp.sources.lib')
local autocomplete = require('blink.cmp.windows.autocomplete')
local docs = {}
Expand All @@ -11,7 +12,6 @@ function docs.setup()
border = config.border,
winhighlight = config.winhighlight,
wrap = true,
filetype = 'markdown',
})

autocomplete.listen_on_position_update(function()
Expand Down Expand Up @@ -54,39 +54,40 @@ function docs.show_item(item)
return
end

local doc_lines = {}
if item.detail and item.detail ~= '' then
table.insert(doc_lines, '```' .. vim.bo.filetype)
for s in item.detail:gmatch('[^\r\n]+') do
table.insert(doc_lines, s)
end
table.insert(doc_lines, '```')
table.insert(doc_lines, '---')
end
local detail_lines = {}
if item.detail and item.detail ~= '' then detail_lines = utils.split_lines(item.detail) end

local doc = type(item.documentation) == 'string' and item.documentation or item.documentation.value
for s in doc:gmatch('[^\r\n]+') do
table.insert(doc_lines, s)
local doc_lines = utils.split_lines(doc)
if type(item.documentation) ~= 'string' and item.documentation.kind == 'markdown' then
-- if the rendering seems bugged, it's likely due to this function
doc_lines = utils.combine_markdown_lines(doc_lines)
end
vim.api.nvim_buf_set_lines(docs.win:get_buf(), 0, -1, true, doc_lines)

local combined_lines = vim.list_extend({}, detail_lines)
-- add a blank line for the --- separator
if #detail_lines > 0 then table.insert(combined_lines, '') end
vim.list_extend(combined_lines, doc_lines)

vim.api.nvim_buf_set_lines(docs.win:get_buf(), 0, -1, true, combined_lines)
vim.api.nvim_set_option_value('modified', false, { buf = docs.win:get_buf() })

vim.api.nvim_buf_clear_namespace(docs.win:get_buf(), require('blink.cmp.config').highlight.ns, 0, -1)
if #detail_lines > 0 then
utils.highlight_with_treesitter(docs.win:get_buf(), vim.bo.filetype, 0, #detail_lines)
vim.api.nvim_buf_set_extmark(docs.win:get_buf(), require('blink.cmp.config').highlight.ns, #detail_lines, 0, {
virt_text = { { string.rep('', docs.win.config.max_width) } },
virt_text_pos = 'overlay',
hl_eol = true,
hl_group = 'BlinkCmpDocDetail',
})
end
utils.highlight_with_treesitter(docs.win:get_buf(), 'markdown', #detail_lines + 1, #detail_lines + 1 + #doc_lines)

if autocomplete.win:get_win() then
docs.win:open()
docs.update_position()
end

-- use the built-in markdown styling
-- NOTE: according to https://github.com/Saghen/blink.cmp/pull/33#issuecomment-2400195950
-- it's possible for this to fail so we call it safely
pcall(
function()
vim.lsp.util.stylize_markdown(docs.win:get_buf(), doc_lines, {
height = vim.api.nvim_win_get_height(docs.win:get_win()),
width = vim.api.nvim_win_get_width(docs.win:get_win()),
})
end
)
end)
end

Expand Down
2 changes: 1 addition & 1 deletion lua/blink/cmp/windows/lib/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ function win:open()
col = 1,
focusable = false,
zindex = 1001,
border = self.config.border == 'padded' and { ' ', '', '', '', '', '', ' ', ' ' } or self.config.border,
border = self.config.border == 'padded' and { ' ', '', '', ' ', '', '', ' ', ' ' } or self.config.border,
})
vim.api.nvim_set_option_value('winhighlight', self.config.winhighlight, { win = self.id })
vim.api.nvim_set_option_value('wrap', self.config.wrap, { win = self.id })
Expand Down

0 comments on commit 90d6394

Please sign in to comment.