local M = {}

M.signature = function() ---- lsp_signature >>>
   require "lsp_signature".setup()
   cfg = {
      Gse_lspsaga = true
   }
end
-- <<<

M.lspinstall = function() ---- lspinstall >>>
   local function setup_servers()
      require'lspinstall'.setup()
      local servers = require'lspinstall'.installed_servers()
      for _, server in pairs(servers) do
         require'lspconfig'[server].setup{}
      end
   end

   setup_servers()

   -- Automatically reload after `:LspInstall <server>` so we don't have to restart neovim
   require'lspinstall'.post_install_hook = function ()
      setup_servers() -- reload installed servers
      vim.cmd("bufdo e") -- this triggers the FileType autocmd that starts the server
   end
end
-- <<<

M.treesitter = function() ---- treesitter >>>
   require('nvim-treesitter.configs').setup {
      highlight = {
         enable = true, -- false will disable the whole extension
      },
      incremental_selection = {
         enable = true,
         keymaps = {
            init_selection = 'gnn',
            node_incremental = 'grn',
            scope_incremental = 'grc',
            node_decremental = 'grm',
         },
      },
      indent = {
         enable = true,
      },
      textobjects = {
         select = {
            enable = true,
            lookahead = true, -- Automatically jump forward to textobj, similar to targets.vim
            keymaps = {
               -- You can use the capture groups defined in textobjects.scm
               ['af'] = '@function.outer',
               ['if'] = '@function.inner',
               ['ac'] = '@class.outer',
               ['ic'] = '@class.inner',
            },
         },
         move = {
            enable = true,
            set_jumps = true, -- whether to set jumps in the jumplist
            goto_next_start = {
               [']m'] = '@function.outer',
               [']]'] = '@class.outer',
            },
            goto_next_end = {
               [']M'] = '@function.outer',
               [']['] = '@class.outer',
            },
            goto_previous_start = {
               ['[m'] = '@function.outer',
               ['[['] = '@class.outer',
            },
            goto_previous_end = {
               ['[M'] = '@function.outer',
               ['[]'] = '@class.outer',
            },
         },
      },
   }

   -- require'nvim-treesitter.configs'.setup {
   --    ensure_installed = "maintained", -- one of "all", "maintained" (parsers with maintainers), or a list of languages
   --    --ignore_install = { "javascript", "java" }, -- List of parsers to ignore installing
   --    highlight = {
   --       enable = true,                     -- false will disable the whole extension
   --       -- disable = { "c", "rust" },   -- list of language that will be disabled
   --       -- Setting this to true will run `:h syntax` and tree-sitter at the same time.
   --       -- Set this to `true` if you depend on 'syntax' being enabled (like for indentation).
   --       -- Using this option may slow down your editor, and you may see some duplicate highlights.
   --       -- Instead of true it can also be a list of languages
   --       additional_vim_regex_highlighting = false,
   --    },
   --    indent = {
   --       enable = true
   --    }
   -- }
end
-- <<<

M.cmp = function() ---- cmp >>>
   -- nvim-cmp supports additional completion capabilities
   local capabilities = vim.lsp.protocol.make_client_capabilities()
   capabilities = require('cmp_nvim_lsp').update_capabilities(capabilities)

   -- luasnip setup
   local luasnip = require 'luasnip'

   -- nvim-cmp setup
   local cmp = require 'cmp'
   cmp.setup {
      snippet = {
         expand = function(args)
            require('luasnip').lsp_expand(args.body)
         end,
      },
      mapping = {
         ['<C-p>'] = cmp.mapping.select_prev_item(),
         ['<C-n>'] = cmp.mapping.select_next_item(),
         ['<C-d>'] = cmp.mapping.scroll_docs(-4),
         ['<C-f>'] = cmp.mapping.scroll_docs(4),
         ['<C-Space>'] = cmp.mapping.complete(),
         ['<C-e>'] = cmp.mapping.close(),
         ['<CR>'] = cmp.mapping.confirm {
            behavior = cmp.ConfirmBehavior.Replace,
            select = true,
         },
         ['<Tab>'] = function(fallback)
            if vim.fn.pumvisible() == 1 then
               vim.fn.feedkeys(vim.api.nvim_replace_termcodes('<C-n>', true, true, true), 'n')
            elseif luasnip.expand_or_jumpable() then
               vim.fn.feedkeys(vim.api.nvim_replace_termcodes('<Plug>luasnip-expand-or-jump', true, true, true), '')
            else
               fallback()
            end
         end,
         ['<S-Tab>'] = function(fallback)
            if vim.fn.pumvisible() == 1 then
               vim.fn.feedkeys(vim.api.nvim_replace_termcodes('<C-p>', true, true, true), 'n')
            elseif luasnip.jumpable(-1) then
               vim.fn.feedkeys(vim.api.nvim_replace_termcodes('<Plug>luasnip-jump-prev', true, true, true), '')
            else
               fallback()
            end
         end,
      },
      sources = {
         { name = 'path' },
         { name = 'buffer' },
         { name = 'calc' },
         { name = 'luasnip' },
         { name = 'nvim_lsp' },
         { name = 'nvim_lua' },
         { name = 'spell' },
         { name = 'treesitter' },
         { name = 'emoji' },
      },
      formatting = {
         format = function(entry, vim_item)
            -- fancy icons and a name of kind
            vim_item.kind = require("lspkind").presets.default[vim_item.kind] .. " " .. vim_item.kind

            -- set a name for each source
            vim_item.menu = ({
               path           = "[Path]",
               buffer         = "[Buffer]",
               calc           = "[Calc]",
               luasnip        = "[LuaSnip]",
               nvim_lsp       = "[LSP]",
               nvim_lua       = "[Lua]",
               spell          = "[Spell]",
               treesitter     = "[TS]",
            })[entry.source.name]
            return vim_item
         end,
      },
   }
end
-- <<<

M.lspconfig = function() ---- lspconfig >>>
   local nvim_lsp = require('lspconfig')

   -- Use an on_attach function to only map the following keys
   -- after the language server attaches to the current buffer
   local on_attach = function(client, bufnr)
      local function buf_set_keymap(...) vim.api.nvim_buf_set_keymap(bufnr, ...) end
      local function buf_set_option(...) vim.api.nvim_buf_set_option(bufnr, ...) end

      -- Enable completion triggered by <c-x><c-o>
      buf_set_option('omnifunc', 'v:lua.vim.lsp.omnifunc')

      -- Mappings.
      local opts = { noremap=true, silent=true }

      -- See `:help vim.lsp.*` for documentation on any of the below functions
      buf_set_keymap('n', 'gD', '<cmd>lua vim.lsp.buf.declaration()<CR>', opts)
      buf_set_keymap('n', 'gd', '<cmd>lua vim.lsp.buf.definition()<CR>', opts)
      buf_set_keymap('n', 'K', '<cmd>lua vim.lsp.buf.hover()<CR>', opts)
      buf_set_keymap('n', 'gi', '<cmd>lua vim.lsp.buf.implementation()<CR>', opts)
      buf_set_keymap('n', '<C-k>', '<cmd>lua vim.lsp.buf.signature_help()<CR>', opts)
      buf_set_keymap('n', '<leader>wa', '<cmd>lua vim.lsp.buf.add_workspace_folder()<CR>', opts)
      buf_set_keymap('n', '<leader>wr', '<cmd>lua vim.lsp.buf.remove_workspace_folder()<CR>', opts)
      buf_set_keymap('n', '<leader>wl', '<cmd>lua print(vim.inspect(vim.lsp.buf.list_workspace_folders()))<CR>', opts)
      buf_set_keymap('n', '<leader>D', '<cmd>lua vim.lsp.buf.type_definition()<CR>', opts)
      buf_set_keymap('n', '<leader>rn', '<cmd>lua vim.lsp.buf.rename()<CR>', opts)
      buf_set_keymap('n', '<leader>ca', '<cmd>lua vim.lsp.buf.code_action()<CR>', opts)
      buf_set_keymap('n', 'gr', '<cmd>lua vim.lsp.buf.references()<CR>', opts)
      buf_set_keymap('n', '<leader>e', '<cmd>lua vim.lsp.diagnostic.show_line_diagnostics()<CR>', opts)
      buf_set_keymap('n', '[d', '<cmd>lua vim.lsp.diagnostic.goto_prev()<CR>', opts)
      buf_set_keymap('n', ']d', '<cmd>lua vim.lsp.diagnostic.goto_next()<CR>', opts)
      buf_set_keymap('n', '<leader>q', '<cmd>lua vim.lsp.diagnostic.set_loclist()<CR>', opts)
      buf_set_keymap('n', '<leader>f', '<cmd>lua vim.lsp.buf.formatting()<CR>', opts)

   end

   -- Use a loop to conveniently call 'setup' on multiple servers and
   -- map buffer local keybindings when the language server attaches
   local servers = { 'clangd', }
   for _, lsp in ipairs(servers) do
      nvim_lsp[lsp].setup {
         on_attach = on_attach,
         flags = {
            debounce_text_changes = 150,
         }
      }
   end
end
-- <<<

return M

-- vim:fdm=marker:fmr=>>>,<<<:expandtab:tabstop=3:sw=3