{ pkgs, lib, inputs, config, ...}:
let
  undoDir = "${config.home.homeDirectory}/.vim/undo";
in {
  programs.neovim = {
    enable = true;
    defaultEditor = true;
    viAlias = true;
    vimAlias = true;
    vimdiffAlias = true;
    plugins = with pkgs.vimPlugins; [
      lightline-vim
      vim-lightline-coc

      vim-commentary
      vim-fugitive

      nerdtree
      nerdtree-git-plugin
      vim-devicons
      telescope-nvim

      nvim-lspconfig
      nvim-treesitter

      coc-css
      coc-go
      coc-html
      coc-json
      coc-nvim

      vim-nix
      vim-puppet
    ];

    withNodeJs = true;

    extraConfig = ''
      let mapleader = ','
      set number
      set shiftwidth=2
      set tabstop=2
      set expandtab

      set undofile
      set undodir=${undoDir}
      set undolevels=1000
      set undoreload=10000

      " Integrate status with lightline
      let g:lightline = {
        \   'active': {
        \     'left': [[  'coc_info', 'coc_hints', 'coc_errors', 'coc_warnings', 'coc_ok' ], [ 'coc_status'  ]]
        \   }
        \ }

      " register components:
      call lightline#coc#register()

      " GoTo code navigation.
      nmap <silent> gd <Plug>(coc-definition)
      nmap <silent> gy <Plug>(coc-type-definition)
      nmap <silent> gi <Plug>(coc-implementation)
      nmap <silent> gr <Plug>(coc-references)

      " Use K to show documentation in preview window.
      nnoremap <silent> K :call ShowDocumentation()<CR>
      function! ShowDocumentation()
        if CocAction('hasProvider', 'hover')
          call CocActionAsync('doHover')
        else
          call feedkeys('K', 'in')
        endif
      endfunction

      " Enable syntax folding with coc
      command! -nargs=* Fold :call CocAction('fold', <f-args>)

      inoremap <silent><expr> <CR> coc#pum#visible() ? coc#pum#confirm()
                                    \: "\<C-g>u\<CR>\<c-r>=coc#on_enter()\<CR>"

      " Highlight the symbol and its references when holding the cursor.
      autocmd CursorHold * silent call CocActionAsync('highlight')

      " Symbol renaming.
      nmap <leader>rn <Plug>(coc-rename)

      " Use CTRL-S for selections ranges.
      " Requires 'textDocument/selectionRange' support of language server.
      nmap <silent> <C-s> <Plug>(coc-range-select)
      xmap <silent> <C-s> <Plug>(coc-range-select)

      " Step through diagnostics
      nmap <silent> <g <Plug>(coc-diagnostic-prev)
      nmap <silent> >g <Plug>(coc-diagnostic-next)

      " Nerdtree-settings
      " Toggle nerdtree on Ctrl+t
      nmap <silent> <C-t> :NERDTreeToggle<CR>
      " Close vim is Nerdtree is the only buffer left
      autocmd bufenter * if (winnr("$") == 1 && exists("b:NERDTree") && b:NERDTree.isTabTree()) | q | endif

      if empty($AERC_ACCOUNT)
        autocmd VimEnter * NERDTree " Autostart nerdtree on vim startup
        autocmd VimEnter * wincmd p " Unselect nerdtree window
      endif

      autocmd Filetype go setlocal expandtab tabstop=4 shiftwidth=4 softtabstop=4

      " List and switch buffers on Ctrl+k
      " nnoremap <C-k> :set nomore <Bar> :ls <Bar> :set more <CR>:b<Space>
      nnoremap <silent> <C-k> !echo "Did you mean C-a?"<CR>

      " Telescope-settings
      nnoremap <leader>ff <cmd>Telescope find_files<cr>
      nnoremap <leader>fg <cmd>Telescope live_grep<cr>
      nnoremap <leader>fb <cmd>Telescope buffers<cr>
      nnoremap <leader>fh <cmd>Telescope help_tags<cr>
      nnoremap <C-a> <cmd>Telescope buffers<cr>
      nnoremap <C-s> <cmd>Telescope find_files<cr>
      nnoremap <C-g> <cmd>Telescope live_grep<cr>

      " Don't darken the background
      autocmd VimEnter * highlight normal ctermbg=NONE guibg=NONE

      " Show trailing whitespace
      highlight ExtraWhitespace ctermbg=red guibg=red
      match ExtraWhitespace /\s\+$/

      " Disable search highlights
      map <Leader><Space> :noh<CR>

      " Start with copilot disabled
      let g:copilot_enabled = 0
    '';
  };

  # Create undo directory
  home.activation.vimUndoDir = lib.hm.dag.entryAfter ["writeBoundary"] "mkdir -p ${undoDir}";
}