Skip to content

Commit

Permalink
feat(runtime): use built-in packadd and deprecate Rocks packadd
Browse files Browse the repository at this point in the history
  • Loading branch information
mrcjkb committed Apr 25, 2024
1 parent 445e1b2 commit 047b8f7
Show file tree
Hide file tree
Showing 10 changed files with 124 additions and 198 deletions.
24 changes: 14 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,10 +118,10 @@ ensures you're covered even when a plugin isn't directly available on LuaRocks.
We're revolutionizing the way Neovim users and plugin developers
interact with tree-sitter parsers.
With the introduction of the [Neovim User Rocks Repository (NURR)](https://github.com/nvim-neorocks/nurr),
we have automated the packaging and publishing of many plugins and curated[^1] tree-sitter parsers
we have automated the packaging and publishing of many plugins and curated[^2] tree-sitter parsers
for luarocks, ensuring a seamless and efficient user experience.

[^1]: We only upload parsers which we can install in the NURR CI
[^2]: We only upload parsers which we can install in the NURR CI
(tested on Linux).

When installing, rocks.nvim will also search our [rocks-binaries (dev)](https://nvim-neorocks.github.io/rocks-binaries-dev/)
Expand All @@ -134,12 +134,12 @@ If you need a tree-sitter parser for syntax highlighting or other features,
you can easily install them with rocks.nvim: `:Rocks install tree-sitter-<lang>`.

They come bundled with queries, so once installed,
all you need to do is run `vim.treesitter.start()` to enable syntax highlighting[^2].
all you need to do is run `vim.treesitter.start()` to enable syntax highlighting[^3].

Or, you can use our [`rocks-treesitter.nvim`](https://github.com/nvim-neorocks/rocks-treesitter.nvim)
module, which can automatically install parsers and enable syntax highlighting for you.

[^2]: You can put this in a `ftplugin/<filetype>.lua`, for example.
[^3]: You can put this in a `ftplugin/<filetype>.lua`, for example.
[nvim-treesitter](https://github.com/nvim-treesitter/nvim-treesitter) is
still required for tree-sitter based folding, indentation, etc.,
but you don't need to configure it to install any parsers.
Expand All @@ -161,11 +161,11 @@ module, which can automatically install parsers and enable syntax highlighting f
#### Simplifying dependencies

For plugin developers, specifying a tree-sitter parser as a dependency
is now as straightforward as including it in their project's rockspec[^3].
is now as straightforward as including it in their project's rockspec[^4].
This eliminates the need for manual parser management and ensures that
dependencies are automatically resolved and installed.

[^3]: [example](https://luarocks.org/modules/MrcJkb/neotest-haskell).
[^4]: [example](https://luarocks.org/modules/MrcJkb/neotest-haskell).

Example rockspec dependency specification:

Expand Down Expand Up @@ -380,8 +380,12 @@ version = "1.0.0"
opt = true
```

You can then load the plugin with the `:Rocks[!] packadd {rock}` command.
Or, before rocks.nvim is initialised, with `require("rocks").packadd("<rock_name>")`.
You can then load the plugin with Neovim's built-in `:packadd {rock}` command[^1].

[^1]: `rocks.nvim` maintains symlinks to installed rocks' plugin directories in
a `site/pack/luarocks/opt/{rock}` directory, so colorschemes, etc., are available
before `rocks.nvim` initializes.
See also [`:h packadd`](https://neovim.io/doc/user/repeat.html#%3Apackadd).

> [!NOTE]
>
Expand All @@ -391,9 +395,9 @@ Or, before rocks.nvim is initialised, with `require("rocks").packadd("<rock_name
> from Git repositories.
>
> Specifically, `luarocks` installs a rock's Lua API to the [`package.path`](https://neovim.io/doc/user/luaref.html#package.path)
> and the [`package.cpath`](https://neovim.io/doc/user/luaref.html#package.cpath).
> and the [`package.cpath`](https://neovim.io/doc/user/luaref.html#package.cpath)
> It does not have to be added to Neovim's runtime path
> (e.g. using `:Rocks packadd`), for it to become available.
> (e.g. using `:packadd`), for it to become available.
> This does not impact Neovim's startup time.
>
> Runtime directories ([`:h runtimepath`](https://neovim.io/doc/user/options.html#'runtimepath')),
Expand Down
35 changes: 7 additions & 28 deletions doc/rocks.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
Table of Contents *rocks.contents*

rocks.nvim ························································ |rocks.nvim|
rocks.nvim Lua API ················································· |rocks.lua|
rocks.nvim commands ··········································· |rocks.commands|
rocks.nvim configuration ········································ |rocks.config|
Lua API for rocks.nvim extensions ·································· |rocks.api|
Expand All @@ -16,24 +15,6 @@ rocks.nvim *rocks.nvim*
A luarocks plugin manager for Neovim.


==============================================================================
rocks.nvim Lua API *rocks.lua*

rocks.packadd({rock_name}, {opts}) *rocks.packadd*
Search for a rock with `opt = true`, add it to the runtimepath and source any plugin files found.

Parameters: ~
{rock_name} (string)
{opts} (rocks.PackaddOpts)


rocks.PackaddOpts *rocks.PackaddOpts*

Fields: ~
{bang?} (boolean) If `true`, rocks.nvim will only add the rock to the runtimepath, but not source any plugin or ftdetect scripts. Default: `false`.
{packadd_fallback?} (boolean) Fall back to the builtin |packadd|? Default `true`.


==============================================================================
rocks.nvim commands *rocks.commands*

Expand All @@ -45,6 +26,13 @@ rocks.nvim commands *rocks.commands*

install {rock} {version?} {args[]?} Install {rock} with optional {version} and optional {args[]}.
Example: ':Rocks install neorg 8.0.0 opt=true'
args (optional):
- opt={true|false}
Rocks that have been installed with 'opt=true'
can be sourced with |packadd|.
- pin={true|false}
Rocks that have been installed with 'pim=true'
will be ignored by ':Rocks update'.
prune {rock} Uninstall {rock} and its stale dependencies,
and remove it from rocks.toml.
sync Synchronize installed rocks with rocks.toml.
Expand All @@ -54,15 +42,6 @@ rocks.nvim commands *rocks.commands*
pin {rock} Pin {rock} to the installed version.
Pinned rocks are ignored by ':Rocks update'.
unpin {rock} Unpin {rock}.
packadd {rock} Search for an optional rock and source any plugin files found.
The rock must be installed by luarocks.
It is added to the 'runtimepath' if it wasn't there yet.
If `Rocks` is called with the optional `!`, the rock is added
to the |runtimepath| and no |plugin| or |ftdetect| scripts are
sourced.
This command aims to behave similarly to the builtin |packadd|,
and will fall back to it if no rock is found.
To make a rock optional, set `opt = true` in `rocks.toml`.
log Open the log file.


Expand Down
36 changes: 23 additions & 13 deletions lua/rocks/adapter.lua
Original file line number Diff line number Diff line change
Expand Up @@ -34,48 +34,58 @@ local rocks_parser_dir = vim.fs.joinpath(config.rocks_path, "lib", "lua", "5.1",
---@type async fun(symlink_location: string, symlink_dir_name: string, dest_dir_path: string)
local create_symlink = nio.create(function(symlink_location, symlink_dir_name, dest_dir_path)
local symlink_dir_path = vim.fs.joinpath(symlink_location, symlink_dir_name)
-- NOTE: nio.uv.fs_stat behaves differently than vim.uv.fs_stat
if not vim.uv.fs_stat(symlink_dir_path) then
local _, stat = nio.uv.fs_stat(symlink_dir_path)
if not stat then
log.info("Creating symlink directory: " .. symlink_dir_name)
nio.uv.fs_symlink(dest_dir_path, symlink_dir_path)
local err, success = nio.uv.fs_symlink(dest_dir_path, symlink_dir_path)
if not success then
log.error(("Error creating symlink directory: %s (%s)"):format(symlink_dir_name, err or "unknown error"))
end
end
end, 3)

---@param symlink_dir string
local function validate_symlink_dir(symlink_dir)
if not vim.uv.fs_stat(symlink_dir) and not vim.uv.fs_unlink(symlink_dir) then
log.error("Failed to remove symlink: " .. symlink_dir)
local _, stat = nio.uv.fs_stat(symlink_dir)
if not stat then
local err, success = nio.uv.fs_unlink(symlink_dir)
if not success then
log.error(("Failed to remove symlink: %s (%s)"):format(symlink_dir, err or "unknown error"))
end
end
end

--- @type async function
--- Check if the tree-sitter parser symlink is valid,
--- and remove it if it isn't
function adapter.validate_tree_sitter_parser_symlink()
adapter.validate_tree_sitter_parser_symlink = nio.create(function()
validate_symlink_dir(vim.fs.joinpath(rtp_link_dir, "parser"))
end
end)

--- Neovim doesn't support `:checkhealth` for luarocks plugins.
--- To work around this, we create a symlink in the `rocks_path` that
--- we add to the runtimepath, so that Neovim can find health files.
local function init_checkhealth_symlink()
local rocks_lua_dir = vim.fs.joinpath(config.rocks_path, "share", "lua", "5.1")
if vim.uv.fs_stat(rocks_lua_dir) then
local _, stat = nio.uv.fs_stat(rocks_lua_dir)
if stat then
create_symlink(rtp_link_dir, "lua", rocks_lua_dir)
end
end

--- If any tree-sitter parsers are installed,
-- initialise a symlink so that Neovim can find them.
function adapter.init_tree_sitter_parser_symlink()
if vim.uv.fs_stat(rocks_parser_dir) then
local _, stat = nio.uv.fs_stat(rocks_parser_dir)
if stat then
create_symlink(rtp_link_dir, "parser", rocks_parser_dir)
end
end

--- Check if the site symlinks are valid,
--- and remove them if they aren't
function adapter.validate_site_symlinks()
local handle = vim.uv.fs_scandir(site_link_dir)
local _, handle = nio.uv.fs_scandir(site_link_dir)
while handle do
local name, ty = vim.uv.fs_scandir_next(handle)
if not name then
Expand All @@ -90,7 +100,7 @@ end
--- @param rock Rock
local function init_site_symlink(rock)
local rock_dir = vim.fs.joinpath(config.rocks_path, "lib", "luarocks", "rocks-5.1", rock.name)
local handle = vim.uv.fs_scandir(rock_dir)
local _, handle = nio.uv.fs_scandir(rock_dir)
while handle do
local name, ty = vim.uv.fs_scandir_next(handle)
if not name then
Expand Down Expand Up @@ -136,9 +146,9 @@ local function init_site_links()
adapter.init_site_symlinks()
end

function adapter.init()
adapter.init = nio.create(function()
init_rtp_links()
init_site_links()
end
end)

return adapter
37 changes: 23 additions & 14 deletions lua/rocks/commands.lua
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
---@toc rocks.contents

---@mod rocks.nvim rocks.nvim
---
---@brief [[
---
---A luarocks plugin manager for Neovim.
---
---@brief ]]

---@mod rocks.commands rocks.nvim commands
---
---@brief [[
Expand All @@ -9,6 +19,13 @@
---
--- install {rock} {version?} {args[]?} Install {rock} with optional {version} and optional {args[]}.
--- Example: ':Rocks install neorg 8.0.0 opt=true'
--- args (optional):
--- - opt={true|false}
--- Rocks that have been installed with 'opt=true'
--- can be sourced with |packadd|.
--- - pin={true|false}
--- Rocks that have been installed with 'pim=true'
--- will be ignored by ':Rocks update'.
--- prune {rock} Uninstall {rock} and its stale dependencies,
--- and remove it from rocks.toml.
--- sync Synchronize installed rocks with rocks.toml.
Expand All @@ -18,15 +35,6 @@
--- pin {rock} Pin {rock} to the installed version.
--- Pinned rocks are ignored by ':Rocks update'.
--- unpin {rock} Unpin {rock}.
--- packadd {rock} Search for an optional rock and source any plugin files found.
--- The rock must be installed by luarocks.
--- It is added to the 'runtimepath' if it wasn't there yet.
--- If `Rocks` is called with the optional `!`, the rock is added
--- to the |runtimepath| and no |plugin| or |ftdetect| scripts are
--- sourced.
--- This command aims to behave similarly to the builtin |packadd|,
--- and will fall back to it if no rock is found.
--- To make a rock optional, set `opt = true` in `rocks.toml`.
--- log Open the log file.
---
---@brief ]]
Expand Down Expand Up @@ -214,10 +222,7 @@ local rocks_command_tbl = {
return
end
local rock_name = args[1]
require("rocks.runtime").packadd(rock_name, { bang = opts.bang })
end,
complete = function(query)
return require("rocks.runtime").complete_packadd(query)
require("rocks").packadd(rock_name, { bang = opts.bang })
end,
},
log = {
Expand Down Expand Up @@ -246,7 +251,11 @@ function commands.create_commands()
nargs = "+",
desc = "Interacts with currently installed rocks",
complete = function(arg_lead, cmdline, _)
local rocks_commands = vim.tbl_keys(rocks_command_tbl)
local rocks_commands = vim.iter(vim.tbl_keys(rocks_command_tbl))
:filter(function(subcmd)
return subcmd ~= "packadd"
end)
:totable()
local subcmd, subcmd_arg_lead = cmdline:match("^Rocks[!]*%s(%S+)%s(.*)$")
if subcmd and subcmd_arg_lead and rocks_command_tbl[subcmd] and rocks_command_tbl[subcmd].complete then
return rocks_command_tbl[subcmd].complete(subcmd_arg_lead)
Expand Down
26 changes: 4 additions & 22 deletions lua/rocks/init.lua
Original file line number Diff line number Diff line change
@@ -1,35 +1,17 @@
---@toc rocks.contents

---@mod rocks.nvim rocks.nvim
---
---@brief [[
---
---A luarocks plugin manager for Neovim.
---
---@brief ]]

-- Copyright (C) 2023 Neorocks Org.
-- Copyright (C) 2024 Neorocks Org.
--
-- Version: 0.1.0
-- License: GPLv3
-- Created: 05 Jul 2023
-- Updated: 20 Mar 2024
-- Updated: 24 Apr 2024
-- Homepage: https://github.com/nvim-neorocks/rocks.nvim
-- Maintainers: NTBBloodbath <[email protected]>, Vhyrro <[email protected]>, mrcjkb <[email protected]>

---@mod rocks.lua rocks.nvim Lua API

local rocks = {}

---Search for a rock with `opt = true`, add it to the runtimepath and source any plugin files found.
---@param rock_name string
---@param opts rocks.PackaddOpts
---@deprecated
function rocks.packadd(rock_name, opts)
vim.deprecate("rocks.packadd", "Neovim's built-in 'packadd'", "3.0.0", "rocks.nvim")
require("rocks.runtime").packadd(rock_name, opts)
end

---@class rocks.PackaddOpts
---@field bang? boolean If `true`, rocks.nvim will only add the rock to the runtimepath, but not source any plugin or ftdetect scripts. Default: `false`.
---@field packadd_fallback? boolean Fall back to the builtin |packadd|? Default `true`.

return rocks
42 changes: 23 additions & 19 deletions lua/rocks/operations/helpers.lua
Original file line number Diff line number Diff line change
Expand Up @@ -85,13 +85,15 @@ helpers.install = function(rock_spec, progress_handle)
progress_handle:report({ message = message })
end

adapter.init_tree_sitter_parser_symlink()
adapter.init_site_symlinks()
if config.dynamic_rtp and not rock_spec.opt then
runtime.packadd(name)
end

future.set(installed_rock)
nio.run(function()
adapter.init_tree_sitter_parser_symlink()
adapter.init_site_symlinks()
if config.dynamic_rtp and not rock_spec.opt then
nio.scheduler()
runtime.packadd(name)
end
future.set(installed_rock)
end)
end
end, {
servers = servers,
Expand All @@ -115,19 +117,21 @@ helpers.remove = function(name, progress_handle)
"remove",
name,
}, function(sc)
---@cast sc vim.SystemCompleted
if sc.code ~= 0 then
message = ("Failed to remove %s."):format(name)
if progress_handle then
progress_handle:report({ message = message })
nio.run(function()
adapter.validate_tree_sitter_parser_symlink()
adapter.validate_site_symlinks()
---@cast sc vim.SystemCompleted
if sc.code ~= 0 then
message = ("Failed to remove %s."):format(name)
if progress_handle then
progress_handle:report({ message = message })
end
future.set_error(sc.stderr)
else
log.info(("Uninstalled: %s"):format(name))
future.set(sc)
end
future.set_error(sc.stderr)
else
log.info(("Uninstalled: %s"):format(name))
future.set(sc)
end
adapter.validate_tree_sitter_parser_symlink()
adapter.validate_site_symlinks()
end)
end)
return future
end
Expand Down
Loading

0 comments on commit 047b8f7

Please sign in to comment.