aboutsummaryrefslogtreecommitdiffstats
path: root/lua/nvim-lsp-installer/ui/status-win/components/settings-schema.lua
blob: 550dcdb5237e587a6547e1eecddba9892bcb92d3 (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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
-- Here be dragons
local Ui = require "nvim-lsp-installer.ui"
local Data = require "nvim-lsp-installer.data"

local list_map = Data.list_map

local property_type_highlights = {
    ["string"] = "String",
    ["string[]"] = "String",
    ["boolean"] = "Boolean",
    ["number"] = "Number",
    ["integer"] = "Number",
}

local function resolve_type(property_schema)
    if vim.tbl_islist(property_schema.type) then
        return table.concat(property_schema.type, " | ")
    elseif property_schema.type == "array" then
        if property_schema.items then
            return ("%s[]"):format(property_schema.items.type)
        else
            return property_schema.type
        end
    end

    return property_schema.type or "N/A"
end

local function Indent(indentation, children)
    -- create a list table with as many "INDENT" entries as the numeric indentation variable
    local indent = {}
    for _ = 1, indentation do
        table.insert(indent, "INDENT")
    end
    return Ui.CascadingStyleNode(indent, children)
end

---@param server ServerState
---@param schema table
---@param key string|nil
---@param level number
---@param key_width number @The width the key should occupate in the UI to produce an even column.
---@param compound_key string|nil
local function ServerSettingsSchema(server, schema, key, level, key_width, compound_key)
    level = level or 0
    compound_key = ("%s%s"):format(compound_key or "", key or "")
    local toggle_expand_keybind = Ui.Keybind(
        "<CR>",
        "TOGGLE_SERVER_SCHEMA_SETTING",
        { name = server.name, key = compound_key }
    )
    local node_is_expanded = server.expanded_schema_properties[compound_key]
    local key_prefix = node_is_expanded and "↓ " or "→ "

    if (schema.type == "object" or schema.type == nil) and schema.properties then
        local nodes = {}
        if key then
            -- This node belongs to some parent object - render a heading for it.
            -- It'll act as the anchor for its children.
            local heading = Ui.HlTextNode {
                key_prefix .. key,
                node_is_expanded and "LspInstallerLabel" or "",
            }
            nodes[#nodes + 1] = heading
            nodes[#nodes + 1] = toggle_expand_keybind
        end

        -- All level 0 nodes are expanded by default - otherwise we'd not render anything at all
        if level == 0 or node_is_expanded then
            local max_property_length = 0
            local sorted_properties = {}
            for property in pairs(schema.properties) do
                max_property_length = math.max(max_property_length, vim.api.nvim_strwidth(property))
                sorted_properties[#sorted_properties + 1] = property
            end
            -- TODO sort at moment of insert?
            table.sort(sorted_properties)
            for _, property in ipairs(sorted_properties) do
                nodes[#nodes + 1] = Indent(level, {
                    ServerSettingsSchema(
                        server,
                        schema.properties[property],
                        property,
                        level + 1,
                        max_property_length,
                        compound_key
                    ),
                })
            end
        end
        return Ui.Node(nodes)
    elseif schema.oneOf then
        local nodes = {}
        for i, alternative_schema in ipairs(schema.oneOf) do
            nodes[#nodes + 1] = ServerSettingsSchema(
                server,
                alternative_schema,
                ("%s (alt. %d)"):format(key, i),
                level,
                key_width,
                compound_key
            )
        end
        return Ui.Node(nodes)
    else
        -- Leaf node (aka any type that isn't an object)
        local type = resolve_type(schema)
        local heading
        local label = (key_prefix .. key .. (" "):rep(key_width)):sub(1, key_width + 5) -- + 5 to account for key_prefix plus some extra whitespace
        if schema.default ~= nil then
            heading = Ui.HlTextNode {
                {
                    {
                        label,
                        node_is_expanded and "LspInstallerLabel" or "",
                    },
                    {
                        " default: ",
                        "Comment",
                    },
                    {
                        vim.json.encode(schema.default),
                        property_type_highlights[type] or "LspInstallerMuted",
                    },
                },
            }
        else
            heading = Ui.HlTextNode {
                label,
                node_is_expanded and "LspInstallerLabel" or "",
            }
        end

        return Ui.Node {
            heading,
            toggle_expand_keybind,
            Ui.When(node_is_expanded, function()
                local description = list_map(function(line)
                    return { { line, "Comment" } }
                end, vim.split(schema.description or "No description available.", "\n"))

                local type_highlight = property_type_highlights[type] or "LspInstallerMuted"

                local table_rows = {
                    { { "type", "LspInstallerMuted" }, { type, type_highlight } },
                }

                if vim.tbl_islist(schema.enum) then
                    for idx, enum in ipairs(schema.enum) do
                        local enum_description = ""
                        if schema.enumDescriptions and schema.enumDescriptions[idx] then
                            enum_description = "- " .. schema.enumDescriptions[idx]
                        end
                        table_rows[#table_rows + 1] = {
                            { idx == 1 and "possible values" or "", "LspInstallerMuted" },
                            { vim.json.encode(enum), type_highlight },
                            { enum_description, "Comment" },
                        }
                    end
                end

                return Indent(level, {
                    Ui.HlTextNode(description),
                    Ui.Table(table_rows),
                })
            end),
        }
    end
end

return ServerSettingsSchema