Skip to content

Commit

Permalink
Merge pull request #135 from max397574/push-wvlnuyxtuvxn
Browse files Browse the repository at this point in the history
perf: new logic for docs and throttle
  • Loading branch information
max397574 authored Nov 11, 2024
2 parents 3b34a9f + 1e074b0 commit ab5a039
Show file tree
Hide file tree
Showing 5 changed files with 104 additions and 42 deletions.
1 change: 1 addition & 0 deletions lua/care/config.lua
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ config.defaults = {
border = "rounded",
scrollbar = { enabled = true, character = "", offset = 0 },
position = "auto",
advanced_styling = false,
},
type_icons = {
Class = "󰠱",
Expand Down
48 changes: 26 additions & 22 deletions lua/care/entry.lua
Original file line number Diff line number Diff line change
Expand Up @@ -170,33 +170,37 @@ end

function Entry:get_documentation()
local completion_item = self.completion_item
local documentation = completion_item.documentation
---@diagnostic disable-next-line: param-type-mismatch
local documentation_text = vim.trim(type(documentation) == "table" and documentation.value or documentation or "")
if (documentation_text):match("^%s*$") and (completion_item.detail or ""):match("^%s*$") then
return nil, nil

local documents = {}

if completion_item.detail and completion_item.detail ~= "" then
local ft = vim.bo.ft
table.insert(documents, {
kind = "markdown",
value = ("```%s\n%s\n```"):format(ft, vim.trim(completion_item.detail)),
})
end
local format = "markdown"
local contents
if documentation_text ~= "" then
if type(documentation) == "table" and documentation.kind == "plaintext" then
format = "plaintext"
contents = vim.split(documentation.value or "", "\n", { trimempty = true })
else
contents = vim.lsp.util.convert_input_to_markdown_lines(documentation_text)

local docs = completion_item.documentation
if type(docs) == "string" and vim.trim(docs) ~= "" then
table.insert(documents, {
kind = "plaintext",
value = vim.trim(docs),
})
elseif type(docs) == "table" and #docs.value > 0 then
if docs.value ~= "" then
table.insert(documents, {
kind = docs.kind,
value = vim.trim(docs.value),
})
end
end

if completion_item.detail and completion_item.detail ~= "" then
if not contents then
contents = {}
end
table.insert(contents, 1, vim.trim(completion_item.detail))
if documentation_text ~= "" then
table.insert(contents, 2, "---")
end
if #documents == 2 then
documents[1].value = documents[1].value .. "\n---"
end
return contents, format

return vim.lsp.util.convert_input_to_markdown_lines(documents)
end

return Entry
43 changes: 23 additions & 20 deletions lua/care/menu/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ function Menu:close()
end
end

function Menu:draw_docs(entry)
Menu.draw_docs = require("care.utils.async").throttle(function(self, entry)
if not entry or self.index == 0 or self.menu_window.winnr == nil then
if self:docs_visible() then
self.docs_window:close()
Expand Down Expand Up @@ -82,36 +82,36 @@ function Menu:draw_docs(entry)

width = width - (has_border and 2 or 0)

local contents, format = doc_entry:get_documentation()
local docs = doc_entry:get_documentation()

if contents == nil then
if docs == nil or #docs == 0 then
self.docs_window:close()
return
end

local do_stylize = format == "markdown" and vim.g.syntax_on ~= nil
if do_stylize then
contents = vim.lsp.util._normalize_markdown(
vim.split(table.concat(contents, "\n"), "\n", { trimempty = true }),
if self.config.ui.docs_view.advanced_styling then
docs = vim.lsp.util._normalize_markdown(
vim.split(table.concat(docs, "\n"), "\n", { trimempty = true }),
{ width = width }
)
vim.bo[self.docs_window.buf].filetype = "markdown"
vim.treesitter.start(self.docs_window.buf)
vim.api.nvim_buf_set_lines(self.docs_window.buf, 0, -1, false, contents)
vim.api.nvim_buf_set_lines(self.docs_window.buf, 0, -1, false, docs)
else
-- Clean up input: trim empty lines
contents = vim.split(table.concat(contents, "\n"), "\n", { trimempty = true })
docs = vim.lsp.util._normalize_markdown(
vim.split(table.concat(docs, "\n"), "\n", { trimempty = true }),
{ width = width }
)

if format then
vim.bo[self.docs_window.buf].syntax = format
end
vim.api.nvim_buf_set_lines(self.docs_window.buf, 0, -1, true, contents)
end
if #contents == 0 then
self.docs_window:close()
return
vim.api.nvim_buf_call(self.docs_window.buf, function()
vim.cmd([[syntax clear]])
vim.api.nvim_buf_set_lines(self.docs_window.buf, 0, -1, false, {})
end)

vim.lsp.util.stylize_markdown(self.docs_window.buf, docs, { max_width = width })
end
width = math.min(width, require("care.utils").longest(contents))

width = math.min(width, require("care.utils").longest(docs))

local win_offset
if position == "right" then
Expand Down Expand Up @@ -141,6 +141,9 @@ function Menu:draw_docs(entry)
})
end

vim.wo[self.docs_window.winnr][0].conceallevel = 2
vim.wo[self.docs_window.winnr][0].concealcursor = "n"

self.docs_window:set_scroll(1, 1, false)
self.docs_window:draw_scrollbar()
end
Expand All @@ -158,7 +161,7 @@ function Menu:draw_docs(entry)
else
open_docs_window(entry)
end
end
end, 10)

local function preselect(menu)
if not menu.config.preselect then
Expand Down
4 changes: 4 additions & 0 deletions lua/care/types/config.lua
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,10 @@
--- Position of docs view.
--- Auto will prefer right if there is enough space
---@field position? "auto"|"left"|"right"
--- Use advanced styling for the documentation.
--- This will use treesitter to make the menu prettier which comes with quite a big
--- performance cost though.
---@field advanced_styling? boolean

--- Additional data passed to format function to allow more advanced formatting
---@class care.format_data
Expand Down
50 changes: 50 additions & 0 deletions lua/care/utils/async.lua
Original file line number Diff line number Diff line change
@@ -1,12 +1,62 @@
-- some parts are adapted from https://github.com/folke/trouble.nvim
local async = {}

local uv = vim.loop or vim.uv

local Queue = {}
Queue.queue = {}
Queue.checker = uv.new_check()

function Queue.step()
local budget = 1 * 1e6
local start = uv.hrtime()
while #Queue.queue > 0 and uv.hrtime() - start < budget do
local a = table.remove(Queue.queue, 1)
a:step()
if a.running then
table.insert(Queue._queue, a)
end
end
if #Queue.queue == 0 then
return Queue.checker:stop()
end
end

function Queue.add(a)
table.insert(Queue.queue, a)
if not Queue.checker:is_active() then
Queue.checker:start(vim.schedule_wrap(Queue.step))
end
end

local AsyncTask = {}

function AsyncTask.new(fn)
local self = setmetatable({}, { __index = AsyncTask })
self.callbacks = {}
self.running = true
self.thread = coroutine.create(fn)
Queue.add(self)
return self
end

function AsyncTask:step()
local ok, res = coroutine.resume(self.thread)
if not ok then
return self:_done(nil, res)
elseif res == "abort" then
return self:_done(nil, "abort")
elseif coroutine.status(self.thread) == "dead" then
return self:_done(res)
end
end

--- Returns a function which can be called to execute the callback
--- After the first time executes earliest after `timeout` ms again
---@param fn function
---@param timeout integer
---@return table?
---@overload fun(...): any?
function async.throttle(fn, timeout)
local timer = vim.uv.new_timer()
local last_executed = nil
Expand Down

0 comments on commit ab5a039

Please sign in to comment.