Preview
What
So I really needed my pylsp to use a different pyenv install, and just want to share my basic solution in hopes it’ll help someone else.
The basic gist of it is that I use vim.system()
to get the version paths through pyenv:
pyenv root
pyenv versions --bare --skip-aliases
and create a telescope picker for selection.
Then I use vim.lsp.client.notify()
with the workspace/didChangeConfiguration
lsp method to change pylsp’s settings (for which options can be found here).
Code
local pickers = require("telescope.pickers")
local finders = require("telescope.finders")
local conf = require("telescope.config").values
local actions = require("telescope.actions")
local action_state = require("telescope.actions.state")
local M = {}
M.get_pyenv_root = function()
if not vim.fn.executable('pyenv') then
vim.notify("pyenv executable not in path.", vim.log.levels.WARN)
return nil
end
local root_cmd = vim.system({
'pyenv',
'root',
}):wait()
if root_cmd.code ~= 0 then
vim.notify('"pyenv root" command returned non zero exit status.', vim.log.levels.WARN)
return nil
end
local pyenv_root = string.gsub(root_cmd.stdout, '%s+', '')
local pyenv_versions_path = vim.fs.joinpath(pyenv_root, '/versions')
if not vim.fn.isdirectory(pyenv_versions_path) then
vim.notify("Failed to find pyenv versions directory, '" .. pyenv_versions_path .. "'.", vim.log.levels.WARN)
return nil
end
return pyenv_versions_path
end
M.get_pyenv_version_paths = function()
if not vim.fn.executable('pyenv') then
vim.notify("pyenv executable not in path.", vim.log.levels.WARN)
return nil
end
local cmd = {
'pyenv',
'versions',
'--bare',
'--skip-aliases'
}
local versions_cmd = vim.system(cmd):wait()
if versions_cmd.code ~= 0 then
vim.notify('command "' .. vim.inspect(cmd) .. '" returned non zero exit status.', vim.log.levels.WARN)
return nil
end
local versions = vim.fn.split(versions_cmd.stdout, '\n')
return versions
end
M.get_pyenv_results = function()
local pyenv_versions_root = M.get_pyenv_root()
local results = {}
if pyenv_versions_root == nil then
return nil
end
local pyenv_versions = M.get_pyenv_version_paths()
if pyenv_versions == nil then
return nil
end
for _, version_path in ipairs(pyenv_versions) do
table.insert(results, {
version_path,
vim.fs.joinpath(pyenv_versions_root, version_path),
})
end
return results
end
M.set_pylsp_environment = function(python_env)
local pylsp_clients = vim.lsp.get_clients({ name = "pylsp" })
if pylsp_clients == nil or next(pylsp_clients) == nil then
vim.notify("No Pylsp clients found.", vim.log.levels.WARN)
return
end
local clients = 0
for _, client in ipairs(pylsp_clients) do
client.notify("workspace/didChangeConfiguration", {
settings = {
pylsp = {
plugins = {
jedi = {
environment = python_env
}
}
}
}
})
clients = clients + 1
end
vim.notify("Set python environment to '" .. python_env .. "' for " .. clients .. " pylsp clients.")
end
M.pyenvs = function(opts)
opts = opts or {}
local version_results = M.get_pyenv_results()
if version_results == nil then
return
end
pickers.new(opts, {
prompt_title = "pyenvs",
finder = finders.new_table({
results = version_results,
entry_maker = function(entry)
return {
value = entry,
display = entry[1],
ordinal = entry[1],
}
end,
}),
attach_mappings = function(prompt_bufnr, _)
actions.select_default:replace(function()
actions.close(prompt_bufnr)
local selection = action_state.get_selected_entry()
M.set_pylsp_environment(selection.value[2])
end)
return true
end,
sorter = conf.generic_sorter(opts)
}):find()
end
return M
And now you can easily open the picker with the M.pyenvs()
function.
Also nice way to create the keymap for it is to wait for the LspAttach
autocmd (which fires when an LSP is attached to a buffer) to fire and only create the keymap on the buffer that pylsp is attached to like so:
(don’t forget to change the ‘<module_name>’)
vim.api.nvim_create_autocmd("LspAttach", {
callback = function(args)
local client = vim.lsp.get_client_by_id(args.data.client_id)
if client and client.name == "pylsp" then
vim.keymap.set("n", "<leader>le", function()
local pylsp_picker = require("<module_name>")
pylsp_picker.pyenvs()
end, {
desc = "[e]nvironment (python)",
buffer = args.buf
})
end
end
})
You must log in or register to comment.