(import-macros {: map!} :hibiscus.vim)
(import-macros {: setup} :macros)

(local servers
  [:eslint
   :ltex
   :pyright
   :sumneko_lua
   :tsserver])

; Mappings.
(map! [n :noremap] "<space>e" vim.diagnostic.open_float)
(map! [n :noremap] "[d" vim.diagnostic.goto_prev)
(map! [n :noremap] "]d" vim.diagnostic.goto_next)
(map! [n :noremap] "<space>q" vim.diagnostic.setloclist)

(fn on_attach [_ bufnr]
  (map! [n :noremap :buffer] :gD vim.lsp.buf.declaration)
  (map! [n :noremap :buffer] :gd vim.lsp.buf.definition)
  (map! [n :noremap :buffer] :K vim.lsp.buf.hover)
  (map! [n :noremap :buffer] :gi vim.lsp.buf.implementation)
  (map! [n :noremap :buffer] :<C-k> vim.lsp.buf.signature_help)
  (map! [n :noremap :buffer] :<space>wa vim.lsp.buf.add_workspace_folder)
  (map! [n :noremap :buffer] :<space>wr vim.lsp.buf.remove_workspace_folder)
  (map! [n :noremap :buffer] :<space>wl (fn [] (print (vim.inspect (vim.lsp.buf.list_workspace_folders)))))
  (map! [n :noremap :buffer] :<space>D vim.lsp.buf.type_definition)
  (map! [n :noremap :buffer] :<space>rn vim.lsp.buf.rename)
  (map! [n :noremap :buffer] :<space>ca vim.lsp.buf.code_action)
  (map! [n :noremap :buffer] :gr vim.lsp.buf.references)
  (map! [n :noremap :buffer] :<space>f vim.lsp.buf.formatting))

(local capabilities ((. (require :cmp_nvim_lsp) :update_capabilities) (vim.lsp.protocol.make_client_capabilities)))

(setup :mason)
(setup :mason-lspconfig
  {:ensure_installed servers})

(each [_ lsp (pairs servers)]
  (local lsp_opts
    {:on_attach on_attach
     :capabilities capabilities
     :flags {:debounce_text_changes 150}})
  (local (status config) (pcall require (.. "settings.lsp." lsp)))
  (if status
        (config.setup lsp_opts)
      ((. (require :lspconfig) lsp :setup) lsp_opts)))

; LuaSnip setup
(local luasnip (require :luasnip))
((. (require :luasnip.loaders.from_vscode) :lazy_load))

; nvim-cmp setup
(local lspkind (require :lspkind))
(local cmp (require :cmp))
(cmp.setup
  {:snippet {:expand (fn [args] (luasnip.lsp_expand args.body))}
   :mapping (cmp.mapping.preset.insert
              {:<C-d> (cmp.mapping.scroll_docs -4)
               :<C-f> (cmp.mapping.scroll_docs 4)
               :<C-Space> (cmp.mapping.complete)
               :<CR> (cmp.mapping.confirm {:behavior cmp.ConfirmBehavior.Replace
                                           :select true})
               :<Tab> (cmp.mapping
                        (fn [fallback] (if (cmp.visible)
                                             (cmp.select_next_item)
                                           (luasnip.expand_or_jumpable)
                                             (luasnip.expand_or_jump)
                                           (fallback)))
                        [:i :s])
               :<S-Tab> (cmp.mapping
                          (fn [fallback] (if (cmp.visible)
                                               (cmp.select_prev_item)
                                             (luasnip.jumpable -1)
                                               (luasnip.jump -1)
                                             (fallback)))
                          [:i :s])})
   :sources [{:name "luasnip"}
             {:name "nvim_lsp"}
             {:name "omni"}]
   :formatting {:format (lspkind.cmp_format {:mode "symbol_text"})}})
