return {
    {
        "neovim/nvim-lspconfig",
        dependencies = {
            "williamboman/mason.nvim",
            "williamboman/mason-lspconfig.nvim",
            "hrsh7th/cmp-nvim-lsp",
            "hrsh7th/cmp-buffer",
            "hrsh7th/cmp-path",
            "hrsh7th/cmp-cmdline",
            "hrsh7th/nvim-cmp",
            "L3MON4D3/LuaSnip",
            "saadparwaiz1/cmp_luasnip",
            "nvim-telescope/telescope-ui-select.nvim",
            "nvimtools/none-ls.nvim",
            "nvimdev/lspsaga.nvim",
            'nvim-treesitter/nvim-treesitter',
            'nvim-tree/nvim-web-devicons',
        },
        config = function()
            -- setup --

            local capabilities = vim.tbl_deep_extend(
                "force",
                {},
                vim.lsp.protocol.make_client_capabilities()
            )

            -- mason --

            require("mason").setup({
                PATH = "append",
                ui = {
                    border = "rounded",
                    icons = {
                        package_installed = "✔",
                        package_pending = "➜",
                        package_uninstalled = "✘"
                    }
                }
            })

            -- mason lspconfig --

            require("mason-lspconfig").setup({
                ensure_installed = {
                    "lua_ls",
                    "clangd",
                    "rust_analyzer",
                },
                handlers = {
                    -- The first entry (without a key) will be the default handler
                    -- and will be called for each installed server that doesn't have
                    -- a dedicated handler.
                    function(server_name) -- default handler (optional)
                        require("lspconfig")[server_name].setup {
                            capabilities = capabilities
                        }
                    end,
                }
            })

            -- telescope ui for null-ls

            require("telescope").setup {
                extensions = {
                    ["ui-select"] = {
                        -- require("telescope.themes").get_dropdown {
                        --     -- even more opts
                        -- }
                    }
                }
            }
            require("telescope").load_extension("ui-select")


            -- null-ls (none-ls)

            local null_ls = require('null-ls')
            require("null-ls").setup({
                sources = {
                    null_ls.builtins.diagnostics.trail_space.with {
                        disabled_filetypes = { "lua" }
                    },
                    null_ls.builtins.code_actions.gitrebase,
                    null_ls.builtins.diagnostics.checkmake,
                    null_ls.builtins.diagnostics.cmake_lint,
                    null_ls.builtins.diagnostics.yamllint,
                    null_ls.builtins.diagnostics.sqlfluff.with({
                        extra_args = { "--dialect", "sqlite" },
                    }),
                    null_ls.builtins.formatting.sqlfluff.with({
                        extra_args = { "--dialect", "sqlite" },
                    }),
                    null_ls.builtins.formatting.asmfmt,
                    null_ls.builtins.formatting.cmake_format,

                    null_ls.builtins.formatting.yamlfmt,
                    null_ls.builtins.formatting.shfmt,
                    null_ls.builtins.formatting.shellharden,
                },
            })

            -- lspsaga (pretty lsp-windows)

            require('lspsaga').setup({
                symbol_in_winbar = {
                    enable = false,
                    show_file = false
                },
                finder = {
                    keys = {
                        toggle_or_open = "<cr>",
                        quit = { '<Esc>', 'q' }
                    }
                },
                outline = {
                    win_position = 'right',
                    win_width = 32,
                    auto_preview = true,
                },
                lightbulb = {
                    enable = false
                },
                ui = {
                    code_action = '',
                    title = true,
                    border = 'rounded',
                },
                rename = {
                    in_select = false,
                    keys = {
                        quit = { '<Esc>', 'q' },
                        select = '<Space>'
                    }
                },
                hover_doc = {
                    open_cmd = '!firefox'
                },
                code_action = {
                    keys = {
                        quit = { '<Esc>', 'q' }
                    },
                    extend_gitsigns = false,
                },
                definition = {
                    keys = {
                        quit = { '<Esc>', 'q' },
                    },
                },
                diagnostic = {
                    border_follow = true,
                    extend_relatedInformation = true,
                    keys = {
                        quit = { '<Esc>', 'q' },
                        quit_in_show = { '<Esc>', 'q' },
                    }
                }
            })

            -- autocomplete --

            local kind_icons = {
                Text = "",
                Method = "󰆧",
                Function = "󰊕",
                Constructor = "",
                Field = "󰇽",
                Variable = "󰂡",
                Class = "󰠱",
                Interface = "",
                Module = "",
                Property = "󰜢",
                Unit = "",
                Value = "󰎠",
                Enum = "",
                Keyword = "󰌋",
                Snippet = "",
                Color = "󰏘",
                File = "󰈙",
                Reference = "",
                Folder = "󰉋",
                EnumMember = "",
                Constant = "󰏿",
                Struct = "",
                Event = "",
                Operator = "󰆕",
                TypeParameter = "󰅲"
            }

            local has_words_before = function()
                unpack = unpack or table.unpack
                local line, col = unpack(vim.api.nvim_win_get_cursor(0))
                return col ~= 0 and
                    vim.api.nvim_buf_get_lines(0, line - 1, line, true)[1]:sub(col, col):match("%s") == nil
            end

            local luasnip = require("luasnip")
            local cmp = require("cmp")
            cmp.setup({
                formatting = {
                    format = function(entry, vim_item)
                        -- Kind icons
                        vim_item.kind = string.format('%s %s', kind_icons[vim_item.kind], vim_item.kind) -- This concatonates the icons with the name of the item kind
                        -- Source
                        vim_item.menu = ({
                            buffer = "",
                            nvim_lsp = "",
                            luasnip = "",
                            nvim_lua = "",
                            latex_symbols = "",
                        })[entry.source.name]
                        return vim_item
                    end
                },
                snippet = {
                    expand = function(args)
                        require('luasnip').lsp_expand(args.body) -- For `luasnip` users.
                    end,
                },
                window = {
                    completion = cmp.config.window.bordered(),
                    documentation = cmp.config.window.bordered(),
                },
                mapping = cmp.mapping.preset.insert({
                    ['<C-b>'] = cmp.mapping.scroll_docs(-4),
                    ['<C-f>'] = cmp.mapping.scroll_docs(4),
                    ['<C-e>'] = cmp.mapping(function(fallback)
                        if cmp.visible() then
                            cmp.abort()
                        else
                            cmp.complete()
                        end
                    end),
                    ['<CR>'] = cmp.mapping.confirm({ select = false }), -- Accept currently selected item. Set `select` to `false` to only confirm explicitly selected items.
                    ["<Tab>"] = cmp.mapping(function(fallback)
                        if cmp.visible() then
                            cmp.select_next_item()
                            -- You could replace the expand_or_jumpable() calls with expand_or_locally_jumpable()
                            -- they way you will only jump inside the snippet region
                        elseif luasnip.expand_or_jumpable() then
                            luasnip.expand_or_jump()
                        elseif has_words_before() then
                            cmp.complete()
                        else
                            fallback()
                        end
                    end, { "i", "s" }),
                    ["<S-Tab>"] = cmp.mapping(function(fallback)
                        if cmp.visible() then
                            cmp.select_prev_item()
                        elseif luasnip.jumpable(-1) then
                            luasnip.jump(-1)
                        else
                            fallback()
                        end
                    end, { "i", "s" }),
                }),
                sources = cmp.config.sources({
                    { name = 'nvim_lsp' },
                    { name = 'luasnip' }, -- For luasnip users.
                    {
                        name = 'buffer',
                        option = {
                            get_bufnrs = function()
                                return vim.api.nvim_list_bufs()
                            end
                        },
                    },
                }, {
                }),
                -- Set configuration for specific filetype.
                -- Use buffer source for `/` and `?` (if you enabled `native_menu`, this won't work anymore).
                cmp.setup.cmdline({ '/', '?' }, {
                    mapping = cmp.mapping.preset.cmdline(),
                    sources = {
                        { name = 'buffer' }
                    }
                }),
                -- Use cmdline & path source for ':' (if you enabled `native_menu`, this won't work anymore).
                cmp.setup.cmdline(':', {
                    mapping = cmp.mapping.preset.cmdline(),
                    sources = cmp.config.sources({
                        { name = 'path' }
                    }, {
                        { name = 'cmdline' }
                    })
                })
            })

            -- config --

            vim.diagnostic.config({
                update_in_insert = true,
                signs = { text = { [vim.diagnostic.severity.ERROR] = "✘ ", [vim.diagnostic.severity.WARN] = " ", [vim.diagnostic.severity.HINT] = " ", [vim.diagnostic.severity.INFO] = " " } },
                float = {
                    focusable = false,
                    style = "minimal",
                    border = "rounded",
                    source = "always",
                    header = "",
                    prefix = "",
                },
                virtual_text = {
                    prefix = '●', -- Could be '●', '■', 'x', '▎', or anything else
                },
            })

            -- keymaps --

            local opts = { noremap = true, silent = true }
            vim.keymap.set('n', 'gd', vim.lsp.buf.definition, opts)
            vim.keymap.set('n', 'K', function() vim.lsp.buf.hover { border = "rounded" } end, opts)
            vim.keymap.set('n', '<leader>k', function() vim.lsp.buf.hover { border = "rounded" } end, opts)
            vim.keymap.set('n', '<space>cl', "<cmd>LspInfo<cr>", opts)
            vim.keymap.set('n', '<space>cd', vim.diagnostic.open_float, opts)
            vim.keymap.set('n', '[n', vim.diagnostic.goto_prev, opts)
            vim.keymap.set('n', ']n', vim.diagnostic.goto_next, opts)
            vim.keymap.set('n', '<space>gr', vim.lsp.buf.references, opts)
            vim.keymap.set('n', '<space>cf', function() vim.lsp.buf.format { async = true } end, opts)
            vim.keymap.set('v', '<space>cf', function() vim.lsp.buf.format { async = true } end, opts)
            vim.keymap.set("n", "<leader>fws", function() vim.lsp.buf.workspace_symbol() end, opts)
            vim.keymap.set("i", "<C-s>", function() vim.lsp.buf.signature_help() end, opts)
            vim.keymap.set('n', '<C-n>', "<cmd>Lspsaga term_toggle<cr>", opts)
            vim.keymap.set('t', '<C-n>', "<cmd>Lspsaga term_toggle<cr>", opts)
            vim.keymap.set('n', '<space>so', '<cmd>Lspsaga outline<cr>', opts)
            vim.keymap.set('n', '<space>sf', '<cmd>Lspsaga finder<cr>', opts)
            vim.keymap.set('n', '<space>sd', '<cmd>Lspsaga peek_definition<cr>', opts)
            vim.keymap.set('n', '<space>cw', "<cmd>Lspsaga rename mode=n<cr>", opts)
            vim.keymap.set('n', '<space>cA', vim.lsp.buf.code_action, opts)
            vim.keymap.set('n', '<space>ca', '<cmd>Lspsaga code_action<cr>', opts)
        end,
    }
}