Skip to content

Commit af37b9f

Browse files
authored
feat: install prebuilt nextls binaries (#153)
1 parent 4fd1c3d commit af37b9f

3 files changed

Lines changed: 96 additions & 35 deletions

File tree

lua/elixir/init.lua

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,6 @@ M.credo.default_bin = (
1818
vim.fn.fnamemodify(debug.getinfo(1).source, ":h") .. "/../../bin/credo-language-server"
1919
):gsub("^@", "")
2020

21-
M.nextls = {}
22-
23-
M.nextls.default_bin = (vim.fn.fnamemodify(debug.getinfo(1).source, ":h") .. "/../../bin/nextls"):gsub(
24-
"^@",
25-
""
26-
)
27-
2821
local enabled = function(value)
2922
return value == nil or value == true
3023
end
@@ -45,12 +38,12 @@ function M.setup(opts)
4538
end
4639

4740
if not opts.nextls.cmd then
48-
opts.nextls.cmd = M.nextls.default_bin
41+
opts.nextls.cmd = nextls.default_bin
4942
end
5043

51-
if opts.nextls.enable and not opts.nextls.version then
52-
opts.nextls.version = utils.latest_release("elixir-tools", "next-ls")
53-
end
44+
-- if opts.nextls.enable and not opts.nextls.version then
45+
-- opts.nextls.version = utils.latest_release("elixir-tools", "next-ls")
46+
-- end
5447

5548
mix.setup()
5649
projectionist.setup()
@@ -62,7 +55,7 @@ function M.setup(opts)
6255
credo.setup(opts.credo)
6356
end
6457

65-
if opts.nextls.version and opts.nextls.enable == true then
58+
if opts.nextls.enable == true then
6659
nextls.setup(opts.nextls)
6760
end
6861
end

lua/elixir/nextls/init.lua

Lines changed: 62 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
local utils = require("elixir.utils")
12
local M = {}
23

34
if not vim.uv then
@@ -8,9 +9,44 @@ if not vim.iter then
89
vim.iter = require("elixir.iter")
910
end
1011

12+
M.default_bin = vim.env.HOME .. "/.cache/elixir-tools/nextls/bin/nextls"
13+
1114
function M.setup(opts)
1215
local nextls_group = vim.api.nvim_create_augroup("elixir-tools.nextls", { clear = true })
1316

17+
vim.api.nvim_create_autocmd("User", {
18+
pattern = "ElixirToolsNextLSActivate",
19+
group = nextls_group,
20+
callback = function(event)
21+
local cmd = event.data.cmd
22+
local options = event.data.opts
23+
local root_dir = event.data.root_dir
24+
vim.lsp.start({
25+
name = "NextLS",
26+
cmd = cmd,
27+
cmd_env = {
28+
NEXTLS_VERSION = options.version,
29+
},
30+
settings = {},
31+
capabilities = options.capabilities or vim.lsp.protocol.make_client_capabilities(),
32+
workspace_folders = {
33+
{ name = root_dir, uri = vim.uri_from_fname(root_dir) },
34+
},
35+
on_attach = options.on_attach or function() end,
36+
}, {
37+
bufnr = 0,
38+
reuse_client = function(client, config)
39+
return client.name == config.name
40+
and vim.iter(client.workspace_folders or {}):any(function(client_wf)
41+
return vim.iter(config.workspace_folders):any(function(new_config_wf)
42+
return new_config_wf.name == client_wf.name and new_config_wf.uri == client_wf.uri
43+
end)
44+
end)
45+
end,
46+
})
47+
end,
48+
})
49+
1450
vim.api.nvim_create_autocmd({ "FileType" }, {
1551
group = nextls_group,
1652
pattern = { "elixir", "eelixir", "heex", "surface" },
@@ -33,30 +69,33 @@ function M.setup(opts)
3369

3470
local root_dir = vim.fs.dirname(file)
3571
assert(type(root_dir) == "string", "expected root_dir to be a string")
72+
local activate = function()
73+
vim.api.nvim_exec_autocmds("User", {
74+
pattern = "ElixirToolsNextLSActivate",
75+
data = {
76+
root_dir = root_dir,
77+
cmd = cmd,
78+
opts = opts,
79+
},
80+
})
81+
end
3682

37-
vim.lsp.start({
38-
name = "NextLS",
39-
cmd = cmd,
40-
cmd_env = {
41-
NEXTLS_VERSION = opts.version,
42-
},
43-
settings = {},
44-
capabilities = opts.capabilities or vim.lsp.protocol.make_client_capabilities(),
45-
workspace_folders = {
46-
{ name = root_dir, uri = vim.uri_from_fname(root_dir) },
47-
},
48-
on_attach = opts.on_attach or function() end,
49-
}, {
50-
bufnr = 0,
51-
reuse_client = function(client, config)
52-
return client.name == config.name
53-
and vim.iter(client.workspace_folders or {}):any(function(client_wf)
54-
return vim.iter(config.workspace_folders):any(function(new_config_wf)
55-
return new_config_wf.name == client_wf.name and new_config_wf.uri == client_wf.uri
56-
end)
57-
end)
58-
end,
59-
})
83+
if
84+
not vim.b.elixir_tools_prompted_nextls_install
85+
and type(opts.port) ~= "number"
86+
and not vim.uv.fs_stat(opts.cmd)
87+
then
88+
vim.ui.select({ "Yes", "No" }, { prompt = "Install Next LS?" }, function(choice)
89+
if choice == "Yes" then
90+
utils.download_nextls()
91+
activate()
92+
else
93+
vim.b.elixir_tools_prompted_nextls_install = true
94+
end
95+
end)
96+
else
97+
vim.schedule_wrap(activate)()
98+
end
6099
end
61100
end,
62101
})

lua/elixir/utils.lua

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,35 @@ function M.root_dir(fname)
2828
return vim.fs.dirname(maybe_umbrella_path or child_or_root_path)
2929
end
3030

31+
local arch = {
32+
["arm64"] = "arm64",
33+
["aarch64"] = "arm64",
34+
["amd64"] = "amd64",
35+
["x86-64"] = "amd64",
36+
}
37+
38+
function M.download_nextls(opts)
39+
opts = opts or {}
40+
local cache_dir = opts.cache_dir or vim.env.HOME .. "/.cache/elixir-tools/nextls/bin"
41+
local sys = vim.uv.os_uname()
42+
local curl = string.format(
43+
[[curl --fail --silent -L https://github.com/elixir-tools/next-ls/releases/latest/download/next_ls_%s_%s -o %s/nextls]],
44+
string.lower(sys.sysname),
45+
arch[string.lower(sys.machine)],
46+
cache_dir
47+
)
48+
vim.fn.mkdir(vim.fn.expand(cache_dir), "p")
49+
vim.fn.system(curl)
50+
51+
assert(vim.uv.fs_chmod(cache_dir .. "/nextls", 755), "failed to make nextls executable")
52+
53+
if not vim.v.shell_error == 0 then
54+
vim.notify(
55+
"Failed to fetch the latest release of Next LS from GitHub.\n\n" .. "Using the command `" .. curl .. "`"
56+
)
57+
end
58+
end
59+
3160
---@param owner string
3261
---@param repo string
3362
---@param opts? table

0 commit comments

Comments
 (0)