mirror of
https://github.com/SpaceVim/SpaceVim.git
synced 2025-01-23 22:30:04 +08:00
148 lines
3.8 KiB
Lua
148 lines
3.8 KiB
Lua
|
local util = require("cmp_dictionary.util")
|
||
|
local lfu = require("cmp_dictionary.lfu")
|
||
|
local config = require("cmp_dictionary.config")
|
||
|
local utf8 = require("cmp_dictionary.lib.utf8")
|
||
|
local Async = require("cmp_dictionary.kit.Async")
|
||
|
local Worker = require("cmp_dictionary.kit.Thread.Worker")
|
||
|
|
||
|
---@class DictionaryData
|
||
|
---@field items lsp.CompletionItem[]
|
||
|
---@field mtime integer
|
||
|
---@field path string
|
||
|
|
||
|
local Caches = {
|
||
|
---@type DictionaryData[]
|
||
|
valid = {},
|
||
|
}
|
||
|
|
||
|
local just_updated = false
|
||
|
local dictCache = lfu.init(config.get("capacity"))
|
||
|
|
||
|
---Filter to keep only dictionaries that have been updated or have not yet been cached.
|
||
|
---@return {path: string, mtime: integer}[]
|
||
|
local function need_to_load()
|
||
|
local dictionaries = util.get_dictionaries()
|
||
|
local updated_or_new = {}
|
||
|
for _, dict in ipairs(dictionaries) do
|
||
|
local path = vim.fn.expand(dict)
|
||
|
if util.bool_fn.filereadable(path) then
|
||
|
local mtime = vim.fn.getftime(path)
|
||
|
local cache = dictCache:get(path)
|
||
|
if cache and cache.mtime == mtime then
|
||
|
table.insert(Caches.valid, cache)
|
||
|
else
|
||
|
table.insert(updated_or_new, { path = path, mtime = mtime })
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
return updated_or_new
|
||
|
end
|
||
|
|
||
|
---Create dictionary data from buffers
|
||
|
---@param path string
|
||
|
---@param name string
|
||
|
---@return lsp.CompletionItem[] items
|
||
|
local read_items = Worker.new(function(path, name)
|
||
|
local buffer = require("cmp_dictionary.util").read_file_sync(path)
|
||
|
|
||
|
local items = {}
|
||
|
local detail = ("belong to `%s`"):format(name)
|
||
|
for w in vim.gsplit(buffer, "%s+") do
|
||
|
if w ~= "" then
|
||
|
table.insert(items, { label = w, detail = detail })
|
||
|
end
|
||
|
end
|
||
|
table.sort(items, function(item1, item2)
|
||
|
return item1.label < item2.label
|
||
|
end)
|
||
|
|
||
|
return items
|
||
|
end)
|
||
|
|
||
|
---@param path string
|
||
|
---@param mtime integer
|
||
|
---@return cmp_dictionary.kit.Async.AsyncTask
|
||
|
local function cache_update(path, mtime)
|
||
|
local name = vim.fn.fnamemodify(path, ":t")
|
||
|
return read_items(path, name):next(function(items)
|
||
|
local cache = {
|
||
|
items = items,
|
||
|
mtime = mtime,
|
||
|
path = path,
|
||
|
}
|
||
|
dictCache:set(path, cache)
|
||
|
table.insert(Caches.valid, cache)
|
||
|
end)
|
||
|
end
|
||
|
|
||
|
local function update()
|
||
|
local buftype = vim.api.nvim_buf_get_option(0, "buftype")
|
||
|
if buftype ~= "" then
|
||
|
return
|
||
|
end
|
||
|
|
||
|
Caches.valid = {}
|
||
|
|
||
|
Async.all(vim.tbl_map(function(n)
|
||
|
return cache_update(n.path, n.mtime)
|
||
|
end, need_to_load())):next(function()
|
||
|
just_updated = true
|
||
|
end)
|
||
|
end
|
||
|
|
||
|
function Caches.update()
|
||
|
util.debounce("update", update, 100)
|
||
|
end
|
||
|
|
||
|
---@param req string
|
||
|
---@param isIncomplete boolean
|
||
|
---@return lsp.CompletionItem[] items
|
||
|
---@return boolean isIncomplete
|
||
|
function Caches.request(req, isIncomplete)
|
||
|
local items = {}
|
||
|
isIncomplete = isIncomplete or false
|
||
|
|
||
|
local ok, offset, codepoint
|
||
|
ok, offset = pcall(utf8.offset, req, -1)
|
||
|
if not ok then
|
||
|
return items, isIncomplete
|
||
|
end
|
||
|
ok, codepoint = pcall(utf8.codepoint, req, offset)
|
||
|
if not ok then
|
||
|
return items, isIncomplete
|
||
|
end
|
||
|
|
||
|
local req_next = req:sub(1, offset - 1) .. utf8.char(codepoint + 1)
|
||
|
|
||
|
local max_items = config.get("max_items")
|
||
|
for _, cache in pairs(Caches.valid) do
|
||
|
local start = util.binary_search(cache.items, req, function(vector, index, key)
|
||
|
return vector[index].label >= key
|
||
|
end)
|
||
|
local last = util.binary_search(cache.items, req_next, function(vector, index, key)
|
||
|
return vector[index].label >= key
|
||
|
end) - 1
|
||
|
if start > 0 and last > 0 and start <= last then
|
||
|
if max_items > 0 and last >= start + max_items then
|
||
|
last = start + max_items
|
||
|
isIncomplete = true
|
||
|
end
|
||
|
for i = start, last do
|
||
|
local item = cache.items[i]
|
||
|
table.insert(items, item)
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
return items, isIncomplete
|
||
|
end
|
||
|
|
||
|
function Caches.is_just_updated()
|
||
|
if just_updated then
|
||
|
just_updated = false
|
||
|
return true
|
||
|
end
|
||
|
return false
|
||
|
end
|
||
|
|
||
|
return Caches
|