aboutsummaryrefslogtreecommitdiffstats
path: root/lua/nvim-lsp-installer/server.lua
blob: b1081d7a15e97b264ccda3e8299b7bcdf814edaf (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
local dispatcher = require "nvim-lsp-installer.dispatcher"
local fs = require "nvim-lsp-installer.fs"
local log = require "nvim-lsp-installer.log"
local installers = require "nvim-lsp-installer.installers"
local servers = require "nvim-lsp-installer.servers"
local status_win = require "nvim-lsp-installer.ui.status-win"

local M = {}

-- old, but also somewhat convenient, API
M.get_server_root_path = servers.get_server_install_path

---@alias ServerDeprecation {message:string, replace_with:string|nil}
---@alias ServerOpts {name:string, root_dir:string, homepage:string|nil, deprecated:ServerDeprecation, installer:ServerInstallerFunction|ServerInstallerFunction[], default_options:table, pre_setup:fun()|nil, post_setup:fun()|nil}

---@class Server
---@field public  name string @The server name. This is the same as lspconfig's server names.
---@field public  root_dir string @The directory where the server should be installed in.
---@field public  homepage string|nil @The homepage where users can find more information. This is shown to users in the UI.
---@field public  deprecated ServerDeprecation|nil @The existence (not nil) of this field indicates this server is depracted.
---@field private _installer ServerInstallerFunction
---@field private _default_options table @The server's default options. This is used in @see Server#setup.
---@field private _pre_setup fun()|nil @Function to be called in @see Server#setup, before trying to setup.
---@field private _post_setup fun()|nil @Function to be called in @see Server#setup, after successful setup.
M.Server = {}
M.Server.__index = M.Server

---@param opts ServerOpts
---@return Server
function M.Server:new(opts)
    return setmetatable({
        name = opts.name,
        root_dir = opts.root_dir,
        homepage = opts.homepage,
        deprecated = opts.deprecated,
        _installer = type(opts.installer) == "function" and opts.installer or installers.pipe(opts.installer),
        _default_options = opts.default_options,
        _pre_setup = opts.pre_setup,
        _post_setup = opts.post_setup,
    }, M.Server)
end

---@param opts table @User-defined options. This is directly passed to the lspconfig's setup() method.
function M.Server:setup(opts)
    if self._pre_setup then
        log.fmt_debug("Calling pre_setup for server=%s", self.name)
        self._pre_setup()
    end
    -- We require the lspconfig server here in order to do it as late as possible.
    -- The reason for this is because once a lspconfig server has been imported, it's
    -- automatically registered with lspconfig and causes it to show up in :LspInfo and whatnot.
    local lsp_server = require("lspconfig")[self.name]
    if lsp_server then
        lsp_server.setup(vim.tbl_deep_extend("force", self._default_options, opts or {}))
        if self._post_setup then
            log.fmt_debug("Calling post_setup for server=%s", self.name)
            self._post_setup()
        end
    else
        error(
            (
                "Unable to setup server %q: Could not find lspconfig server entry. Make sure you are running a recent version of lspconfig."
            ):format(self.name)
        )
    end
end

---@return table @A deep copy of this server's default options. Note that these default options are nvim-lsp-installer specific, and does not include any default options provided by lspconfig.
function M.Server:get_default_options()
    return vim.deepcopy(self._default_options)
end

---@return string[] @The list of supported filetypes.
function M.Server:get_supported_filetypes()
    local metadata = require "nvim-lsp-installer._generated.metadata"

    if metadata[self.name] then
        return metadata[self.name].filetypes
    end

    return {}
end

---@return boolean
function M.Server:is_installed()
    return servers.is_server_installed(self.name)
end

function M.Server:create_root_dir()
    fs.mkdirp(self.root_dir)
end

---Queues the server to be asynchronously installed. Also opens the UI window.
function M.Server:install()
    status_win().install_server(self)
end

---@param context ServerInstallContext
---@param callback ServerInstallCallback
function M.Server:install_attached(context, callback)
    local uninstall_ok, uninstall_err = pcall(self.uninstall, self)
    if not uninstall_ok then
        context.stdio_sink.stderr(tostring(uninstall_err) .. "\n")
        callback(false)
        return
    end

    self:create_root_dir()

    local install_ok, install_err = pcall(self._installer, self, function(success)
        if not success then
            vim.schedule(function()
                pcall(self.uninstall, self)
            end)
        else
            vim.schedule(function()
                dispatcher.dispatch_server_ready(self)
            end)
        end
        callback(success)
    end, context)
    if not install_ok then
        context.stdio_sink.stderr(tostring(install_err) .. "\n")
        callback(false)
    end
end

function M.Server:uninstall()
    log.debug("Uninstalling server", self.name)
    if fs.dir_exists(self.root_dir) then
        fs.rmrf(self.root_dir)
    end
end

return M