Skip to content

Commit

Permalink
perf: populate luarocks.org state cache at startup (#53)
Browse files Browse the repository at this point in the history
* refactor(commands): extract cache module + move completion functions

* perf: populate luarocks.org state cache at startup

* refactor: index cached rocks by name
  • Loading branch information
mrcjkb authored Dec 9, 2023
1 parent 4a677ee commit 3b1b5c2
Show file tree
Hide file tree
Showing 8 changed files with 129 additions and 110 deletions.
7 changes: 4 additions & 3 deletions doc/rocks.txt
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,10 @@ rocks.nvim configuration *rocks.config*
RocksOpts *RocksOpts*

Fields: ~
{rocks_path?} (string) Local path in your filesystem to install rocks. Defaults to a `rocks` directory in `vim.fn.stdpath("data")`.
{config_path?} (string) Rocks declaration file path. Defaults to `rocks.toml` in `vim.fn.stdpath("config")`.
{luarocks_binary?} (string) Luarocks binary path. Defaults to `luarocks`.
{rocks_path?} (string) Local path in your filesystem to install rocks. Defaults to a `rocks` directory in `vim.fn.stdpath("data")`.
{config_path?} (string) Rocks declaration file path. Defaults to `rocks.toml` in `vim.fn.stdpath("config")`.
{luarocks_binary?} (string) Luarocks binary path. Defaults to `luarocks`.
{lazy?} (boolean) Whether to query luarocks.org lazily. Defaults to `false`. Setting this to `true` may improve startup time, but features like auto-completion will lag initially.


vim:tw=78:ts=8:noet:ft=help:norl:
74 changes: 74 additions & 0 deletions lua/rocks/cache.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
---@mod rocks.cache rocks.nvim luarocks cache
---
---@brief [[
---
---Cached luarocks state.
---
---@brief ]]

-- Copyright (C) 2023 Neorocks Org.
--
-- Version: 0.1.0
-- License: GPLv3
-- Created: 07 Dec 2023
-- Updated: 07 Dec 2023
-- Homepage: https://github.com/nvim-neorocks/rocks.nvim
-- Maintainer: NTBBloodbath <bloodbathalchemist@protonmail.com>

local cache = {}

local luarocks = require("rocks.luarocks")
local nio = require("nio")

---@type { [string]: Rock[] } | nil
local _cached_rocks = nil

---Query luarocks packages and populate the cache.
---@async
cache.populate_cached_rocks = nio.create(function()
if _cached_rocks then
return
end
_cached_rocks = vim.empty_dict()
---@cast _cached_rocks Rock[]
local future = nio.control.future()
luarocks.cli({ "search", "--porcelain", "--all" }, function(obj)
---@cast obj vim.SystemCompleted
future.set(obj)
end, { text = true })
---@type vim.SystemCompleted
local obj = future.wait()
local result = obj.stdout
if obj.code ~= 0 or not result then
-- set cache back to nil so that we can retry again
_cached_rocks = nil
return
end
for name, version in result:gmatch("(%S+)%s+(%S+)%srockspec%s+[^\n]+") do
if name ~= "lua" then
local rock_list = _cached_rocks[name] or vim.empty_dict()
---@cast rock_list Rock[]
table.insert(rock_list, { name = name, version = version })
_cached_rocks[name] = rock_list
end
end
if vim.tbl_isempty(_cached_rocks) then
_cached_rocks = nil
end
end)

---Tries to get the cached rocks.
---Returns an empty list if the cache is not ready,
---and triggers an async task to populate the cache.
---@return { [string]: Rock[] } rocks indexed by name
function cache.try_get_rocks()
if not _cached_rocks then
nio.run(cache.populate_cached_rocks)
local rocks = vim.empty_dict()
---@cast rocks { [string]: Rock[] }
return rocks
end
return _cached_rocks
end

return cache
45 changes: 40 additions & 5 deletions lua/rocks/commands.lua
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,44 @@

local commands = {}

local fzy = require("rocks.fzy")
local cache = require("rocks.cache")

---@param name string
---@param query string | nil
---@return string[]
local function complete_versions(name, query)
local rocks = cache.try_get_rocks()[name] or vim.empty_dict()
local matching_rocks = vim.tbl_filter(function(rock)
---@cast rock Rock
if not query then
return true
end
return rock.name == name and vim.startswith(rock.version, query)
end, rocks)
local unique_versions = {}
for _, rock in pairs(matching_rocks) do
unique_versions[rock.version] = rock
end

local unique_keys = vim.tbl_keys(unique_versions)
table.sort(unique_keys, function(a, b)
return a > b
end)
return unique_keys
end

---@param query string | nil
---@return string[]
local function complete_names(query)
local rocks = cache.try_get_rocks()
if not query then
return {}
end
local rock_names = vim.tbl_keys(rocks)
return fzy.fuzzy_filter_sort(query, rock_names)
end

---@type { [string]: fun(args:string[]) }
local rocks_command_tbl = {
update = function(_)
Expand Down Expand Up @@ -75,22 +113,19 @@ function commands.create_commands()
nargs = "+",
desc = "Interacts with currently installed rocks",
complete = function(arg_lead, cmdline, _)
local fzy = require("rocks.fzy")
local search = require("rocks.search")

local rocks_commands = vim.tbl_keys(rocks_command_tbl)

local name, version_query = cmdline:match("^Rocks install%s([^%s]+)%s(.+)$")
-- name followed by space, but no version?
name = name or cmdline:match("^Rocks install%s([^%s]+)%s$")
if version_query or name then
local version_list = search.complete_versions(name, version_query)
local version_list = complete_versions(name, version_query)
if #version_list > 0 then
return version_list
end
end
local name_query = cmdline:match("^Rocks install%s(.*)$")
local rocks_list = search.complete_names(name_query)
local rocks_list = complete_names(name_query)
if #rocks_list > 0 then
return rocks_list
end
Expand Down
1 change: 1 addition & 0 deletions lua/rocks/config/check.lua
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ function check.validate(cfg)
rocks_path = { cfg.rocks_path, "string" },
config_path = { cfg.config_path, "string" },
luarocks_binary = { cfg.luarocks_binary, "string" },
lazy = { cfg.lazy, "boolean" },
})
if not ok then
return false, err
Expand Down
1 change: 1 addition & 0 deletions lua/rocks/config/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ local config = {}
---@field rocks_path? string Local path in your filesystem to install rocks. Defaults to a `rocks` directory in `vim.fn.stdpath("data")`.
---@field config_path? string Rocks declaration file path. Defaults to `rocks.toml` in `vim.fn.stdpath("config")`.
---@field luarocks_binary? string Luarocks binary path. Defaults to `luarocks`.
---@field lazy? boolean Whether to query luarocks.org lazily. Defaults to `false`. Setting this to `true` may improve startup time, but features like auto-completion will lag initially.

---@type RocksOpts | fun():RocksOpts
vim.g.rocks_nvim = vim.g.rocks_nvim
Expand Down
2 changes: 2 additions & 0 deletions lua/rocks/config/internal.lua
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
---@field rocks_path string Local path in your filesystem to install rocks
---@field config_path string Rocks declaration file path
---@field luarocks_binary string Luarocks binary path
---@field lazy boolean Whether to query luarocks.org lazily.
---@field debug_info RocksConfigDebugInfo

---@class (exact) RocksConfigDebugInfo
Expand All @@ -33,6 +34,7 @@ local default_config = {
---@diagnostic disable-next-line: param-type-mismatch
config_path = vim.fs.joinpath(vim.fn.stdpath("config"), "rocks.toml"),
luarocks_binary = "luarocks",
lazy = false,
debug_info = {
was_g_rocks_nvim_sourced = vim.g.rocks_nvim ~= nil,
unrecognized_configs = {},
Expand Down
102 changes: 0 additions & 102 deletions lua/rocks/search.lua

This file was deleted.

7 changes: 7 additions & 0 deletions plugin/rocks.lua
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,10 @@ require("rocks").init()

-- Set up the Rocks user command
require("rocks.commands").create_commands()

---@type RocksConfig
local config = require("rocks.config.internal")

if not config.lazy then
require("nio").run(require("rocks.cache").populate_cached_rocks)
end

0 comments on commit 3b1b5c2

Please sign in to comment.