Skip to content

Commit

Permalink
feat: rocks.api module for use by external rocks.nvim extensions (#54)
Browse files Browse the repository at this point in the history
- Query luarocks rocks
- Query installed rocks
- Fuzzy-filter rocks tables
- Get `rocks.toml` file
- Register `:Rocks` subcommands
  • Loading branch information
mrcjkb authored Dec 10, 2023
1 parent 3b1b5c2 commit 20dc8ce
Show file tree
Hide file tree
Showing 15 changed files with 383 additions and 135 deletions.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,11 @@ that are no longer needed, run the `:Rocks prune [rock]` command.
The `:Rocks edit` command opens the `rocks.toml` file for manual editing.
Make sure to run `:Rocks sync` when you are done.

## :waning_crescent_moon: Lua API

This plugin provides a Lua API for extensibility.
See [`:h rocks.api`](./doc/rocks.txt) for details.

## :book: License

`rocks.nvim` is licensed under [GPLv3](./LICENSE).
Expand Down
93 changes: 93 additions & 0 deletions doc/rocks.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ Table of Contents *rocks.contents*
rocks.nvim ····························································· |rocks|
rocks.nvim commands ··········································· |rocks.commands|
rocks.nvim configuration ········································ |rocks.config|
rocks.nvim Lua API ················································· |rocks.api|

==============================================================================
rocks.nvim *rocks*
Expand Down Expand Up @@ -50,4 +51,96 @@ RocksOpts *RocksOpts*
{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.


==============================================================================
rocks.nvim Lua API *rocks.api*


The Lua API for rocks.nvim.
Intended for use by modules that extend this plugin.


Rock *Rock*

Fields: ~
{name} (string)
{version} (string)


rock_name *rock_name*

Type: ~
string


api.try_get_cached_rocks() *api.try_get_cached_rocks*
Tries to get the cached rocks.
Returns an empty list if the cache has not been populated
or no connection to luarocks.org can be established.
Will spawn an async task to attempt to populate the cache
if it is not ready.

Returns: ~
(table<rock_name,Rock[]>) rocks


api.query_luarocks_rocks({callback}) *api.query_luarocks_rocks*
Queries luarocks.org for rocks and passes the rocks
to a callback. Invokes the callback with an empty table
if no rocks are found or no connection to luarocks.org can be established.

Parameters: ~
{callback} (fun(rocks:table<rock_name,Rock[]>)) @async


FuzzyFilterOpts *FuzzyFilterOpts*

Fields: ~
{sort?} (boolean) Whether to sort the results (default: `true`).


*api.fuzzy_filter_rock_tbl*
api.fuzzy_filter_rock_tbl({rock_tbl}, {query}, {opts?})
@generic T

Parameters: ~
{rock_tbl} (table<rock_name,T>)
{query} (string)
{opts?} (FuzzyFilterOpts)

Returns: ~
(table<rock_name,T>)


api.query_installed_rocks({callback}) *api.query_installed_rocks*
Query for installed rocks.
Passes the installed rocks (table indexed by name) to a callback when done.

Parameters: ~
{callback} (fun(rocks:table<rock_name,Rock>)) @async


api.get_rocks_toml() *api.get_rocks_toml*
Gets the rocks.toml file path.
Note that the file may not have been created yet.

Returns: ~
(string) rocks_toml_file


RocksCmd *RocksCmd*

Fields: ~
{impl} (fun(args:string[])) The command implementation
{complete?} (fun(subcmd_arg_lead:string):string[]) Command completions callback, taking the lead of the subcommand's arguments


*api.register_rocks_subcommand*
api.register_rocks_subcommand({name}, {cmd})
Register a `:Rocks` subcommand.

Parameters: ~
{name} (string) The name of the subcommand to register
{cmd} (RocksCmd)


vim:tw=78:ts=8:noet:ft=help:norl:
110 changes: 110 additions & 0 deletions lua/rocks/api.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
---@mod rocks.api rocks.nvim Lua API
---
---@brief [[
---
---The Lua API for rocks.nvim.
---Intended for use by modules that extend this plugin.
---
---@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>

---@class Rock
---@field name string
---@field version string

---@alias rock_name string

local api = {}

local nio = require("nio")
local cache = require("rocks.cache")
local luarocks = require("rocks.luarocks")
local fzy = require("rocks.fzy")
local state = require("rocks.state")
local commands = require("rocks.commands")
local config = require("rocks.config.internal")

---Tries to get the cached rocks.
---Returns an empty list if the cache has not been populated
---or no connection to luarocks.org can be established.
---Will spawn an async task to attempt to populate the cache
---if it is not ready.
---@return table<rock_name, Rock[]> rocks
function api.try_get_cached_rocks()
return cache.try_get_rocks()
end

---Queries luarocks.org for rocks and passes the rocks
---to a callback. Invokes the callback with an empty table
---if no rocks are found or no connection to luarocks.org can be established.
---@param callback fun(rocks: table<rock_name, Rock[]>)
---@async
function api.query_luarocks_rocks(callback)
nio.run(luarocks.search_all, function(success, rocks)
if success then
callback(rocks)
end
end)
end

---@class FuzzyFilterOpts
---@field sort? boolean Whether to sort the results (default: `true`).

---@generic T
---@param rock_tbl table<rock_name, T>
---@param query string
---@param opts? FuzzyFilterOpts
---@return table<rock_name, T>
function api.fuzzy_filter_rock_tbl(rock_tbl, query, opts)
vim.validate({ query = { query, "string" } })
if opts then
vim.validate({ sort = { opts.sort, "boolean", true } })
end
local matching_names = fzy.fuzzy_filter(query, vim.tbl_keys(rock_tbl), opts)
local result = vim.empty_dict()
---@cast result table<rock_name, Rock[]>
for _, match in pairs(matching_names) do
result[match] = rock_tbl[match]
end
return result
end

---Query for installed rocks.
---Passes the installed rocks (table indexed by name) to a callback when done.
---@param callback fun(rocks: table<rock_name, Rock>)
---@async
function api.query_installed_rocks(callback)
nio.run(state.installed_rocks, function(success, rocks)
if success then
callback(rocks)
end
end)
end

---Gets the rocks.toml file path.
---Note that the file may not have been created yet.
---@return string rocks_toml_file
function api.get_rocks_toml()
return config.config_path
end

---@class RocksCmd
---@field impl fun(args:string[]) The command implementation
---@field complete? fun(subcmd_arg_lead: string): string[] Command completions callback, taking the lead of the subcommand's arguments

---Register a `:Rocks` subcommand.
---@param name string The name of the subcommand to register
---@param cmd RocksCmd
function api.register_rocks_subcommand(name, cmd)
commands.register_subcommand(name, cmd)
end

return api
31 changes: 5 additions & 26 deletions lua/rocks/cache.lua
Original file line number Diff line number Diff line change
Expand Up @@ -24,37 +24,16 @@ local nio = require("nio")
local _cached_rocks = nil

---Query luarocks packages and populate the cache.
---@async
---@type async fun()
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
luarocks.search_all(function(rocks)
if not vim.tbl_isempty(rocks) then
_cached_rocks = rocks
end
end
if vim.tbl_isempty(_cached_rocks) then
_cached_rocks = nil
end
end)
end)

---Tries to get the cached rocks.
Expand Down
Loading

0 comments on commit 20dc8ce

Please sign in to comment.