saecki/crates.nvim

null-ls is archived

Closed this issue · 16 comments

null-ls.nvim has be archived citing maintenance concerns.

Commenters on the related issue have cited efm as a potential replacement, but I have not looked into that yet.

saecki commented

I know, but since we only use null-ls for code-actions, and there isn't any popular replacement for that, I don't see any reasonable path into the future yet. Since having something that still works is better than nothing at all, I think just leaving it as is for now is probably the best option.

@saecki it would be nice to, at least, remove the warning from checkhealth?

saecki commented

Do you mean this?

- Crates: cannot verify if the command is an executable.

I don't think there is any way around that one.

I mean this:

==============================================================================
crates: require("crates.health").check()

Checking required plugins ~
- OK plenary.nvim installed
- WARNING null-ls.nvim not found

Checking external dependencies ~
- OK curl installed
- OK xdg-open installed
- OK open installed
saecki commented

Ah that one, seems reasonable.

For anyone who comes across this issue, looks like null-ls got forked to none-ls. If I understand right, it's a drop-in replacement.

saecki commented

I will definitely keep an eye on that one. Maybe there should be a config option to select which one to use, similar to how nvim-cmp and coq_nvim sources work.

gh-liu commented

Maybe create in-process lsp server is another option, no other dependencies.

Just copy the code below to your config and reopen the Cargo.toml file.

local lsp = {}

---@class lsp.server.opts
---@field handlers? table<string, fun(method: string, params: any): any>
---@field on_request? fun(method: string, params)
---@field on_notify? fun(method: string, params)
---@field capabilities? table

--- Create a in-process LSP server that can be used as `cmd` with |vim.lsp.start|
--- Example:
--- <pre>lua
--- vim.lsp.start({
---   name = "my-in-process-server",
---   cmd = vim.lsp.server({
---   handlers = {
---
---   }
---   })
--- })
---
--- @param opts nil|lsp.server.opts
function lsp.server(opts)
	opts = opts or {}
	local capabilities = opts.capabilities or {}
	local on_request = opts.on_request or function(_, _) end
	local on_notify = opts.on_notify or function(_, _) end
	local handlers = opts.handlers or {}

	return function(dispatchers)
		local closing = false
		local srv = {}
		local request_id = 0

		function srv.request(method, params, callback)
			pcall(on_request, method, params)
			local handler = handlers[method]
			if handler then
				local response, err = handler(method, params)
				callback(err, response)
			elseif method == "initialize" then
				callback(nil, {
					capabilities = capabilities,
				})
			elseif method == "shutdown" then
				callback(nil, nil)
			end
			request_id = request_id + 1
			return true, request_id
		end

		function srv.notify(method, params)
			pcall(on_notify, method, params)
			if method == "exit" then
				dispatchers.on_exit(0, 15)
			end
		end

		function srv.is_closing()
			return closing
		end

		function srv.terminate()
			closing = true
		end

		return srv
	end
end

lsp.enable_crates = function()
	local actions = {
		"update_crate",
		"upgrade_crate",
		"expand_crate_to_inline_table",
		"extract_crate_into_table",
		"remove_duplicate_section",
		"remove_original_section",
		"remove_invalid_dependency_section",
		"remove_duplicate_crate",
		"remove_original_crate",
		"rename_crate",
		"remove_duplicate_feature",
		"remove_original_feature",
		"remove_invalid_feature",
		"open_documentation",
		"open_crates.io",
		"update_all_crates",
		"upgrade_all_crates",
	}
	for _, value in ipairs(actions) do
		vim.lsp.commands[value] = function(cmd, ctx)
			local actions = require("crates.actions")
			local action = actions.get_actions()[cmd.command]
			vim.api.nvim_buf_call(ctx.bufnr, action)
		end
	end

	local api = vim.api
	local server = lsp.server({
		capabilities = {
			codeActionProvider = true,
		},
		handlers = {
			---@param params lsp.CodeActionParams
			["textDocument/codeAction"] = function(_, params)
				local actions = require("crates.actions")
				local function format_title(name)
					return name:sub(1, 1):upper() .. name:gsub("_", " "):sub(2)
				end

				local code_actions = {}
				for key, action in pairs(actions.get_actions()) do
					table.insert(code_actions, {
						title = format_title(key),
						kind = "refactor.rewrite",
						command = key,
					})
				end
				return code_actions
			end,
		},
	})
	vim.lsp.start({ name = "crates-ls", cmd = server })
end

vim.api.nvim_create_autocmd("BufEnter", {
	pattern = "Cargo.toml",
	callback = function()
		lsp.enable_crates()
	end,
})
saecki commented

Ooh I like that, it seems simple enough and could probably also be used to handle completion.

@gh-liu where do you paste that code you have given? init or crates.lua? or is just a function that i can require in init?

@gh-liu where do you paste that code you have given? init or crates.lua? or is just a function that i can require in init?

Afaik the PR hasn't been merged, so the snippet won't work yet, even on 0.10.

For now you can still use null_ls or none_ls. The latter could probably be added to the documentation, but it's a drop in replacement.

Ohhhh alright thanks....and making it a lsp seems better than using null or none

Afaik the PR hasn't been merged

Yes, the lsp.server funtion hasn't been merged,

so the snippet won't work yet, even on 0.10.

But the snippet works, Because the snippet contains the lsp.server funtion.

@gh-liu where do you paste that code you have given? init or crates.lua? or is just a function that i can require in init?

You can just require in init.lua, or copy the lsp.server funtion into a lua file, and use it in the crates config.

This is my config:
lua file contains lsp.server funciton
use lsp.server function in crates config

But the snippet works, Because the snippet contains the lsp.server funtion.

Huh, I definitely misread that. I'll see when I can implement a lsp server directly😄

I guess with #100 merged, and none_ls as an alternative, this issue is pretty much resolved.