set background=dark
syntax on
filetype plugin indent on

let mapleader=','

" netrw
let g:netrw_banner = 0
let g:netrw_liststyle = 1
let g:netrw_list_hide = '^\.'
let g:netrw_winsize=25
map <leader>n <esc>:Lexplore<cr>

" fix helptags for opt/ plugins
" https://vi.stackexchange.com/questions/17210/generating-help-tags-for-packages-that-are-loaded-by-vim-8s-package-management
command! -nargs=0 -bar Helptags
    \  for p in glob('~/.vim/pack/git-plugins/opt/*', 1, 1)
    \|     exe 'packadd ' . fnamemodify(p, ':t')
    \| endfor
    \| helptags ALL

set shiftwidth=2
set shiftround
set tabstop=2
set expandtab
set smarttab
set splitbelow
set splitright
set encoding=utf-8
set hidden
set history=1000
set nowrap
set smartindent
set copyindent
set autoindent
set hlsearch
set showmatch
set wildmenu
set wildmode=list:full,full
set number
set relativenumber
set ruler
set backspace=indent,eol,start
set ignorecase
set smartcase
set incsearch
set history=1000
set undolevels=1000
set title
set novisualbell
set noerrorbells
set nobackup
set noswapfile
set ttymouse=sgr
set mouse=a
set mousemodel=popup_setpos
" https://github.com/tpope/vim-sensible/issues/78:
set lazyredraw
set timeoutlen=1000
set ballooneval
set balloonevalterm
set scrolloff=15
set dictionary=/usr/share/dict/words
set shortmess+=I
set updatetime=250
set pastetoggle=<f2>
" See :help thesaurus
set thesaurus=$HOME/Documents/thesaurus/thesaurus_pkg/thesaurus.txt
set pumheight=200
set completeopt=menu,menuone,popup,noselect
set completepopup=width:300,height:50,align:item,border:off
set complete-=i
set nrformats-=octal
set ttimeout
set ttimeoutlen=100
set formatoptions+=j
set autoread
" https://github.com/tpope/vim-sensible/issues/142:
set synmaxcol=500

" Enable 24-bit colours.
" https://github.com/alacritty/alacritty/issues/109#issuecomment-440353106
if exists('+termguicolors')
  let &t_8f="\<Esc>[38;2;%lu;%lu;%lum"
  let &t_8b="\<Esc>[48;2;%lu;%lu;%lum"
  set termguicolors
endif

" Colour scheme:
packadd! nord-vim " https://github.com/arcticicestudio/nord-vim.git
colorscheme nord

augroup vimrc
  autocmd!
  " Automatically load/save views on files.
  " https://vi.stackexchange.com/posts/13874/revisions
  autocmd BufWinLeave,BufLeave,BufWritePost,BufHidden,QuitPre ?* nested silent! mkview!
  autocmd BufWinEnter ?* silent! loadview
  " set cursor line highlight in insert mode.
  autocmd InsertEnter * set cul
  autocmd InsertLeavePre * set nocul
  " use tabs in .gitconfig
  autocmd BufEnter .gitconfig setlocal shiftwidth=2 tabstop=2 noexpandtab
  " Quickfix window is always full-width.
  " https://github.com/fatih/vim-go/issues/1757#issuecomment-565130503
  autocmd FileType qf if (getwininfo(win_getid())[0].loclist != 1) | wincmd J | endif
augroup end

" Don't remember the current directory for a given file:
set viewoptions-=curdir
set viewoptions-=options
set sessionoptions-=options

" Key mappings:
nnoremap j gj
nnoremap k gk
map <up> <nop>
map <down> <nop>
map <left> <nop>
map <right> <nop>
imap <up> <nop>
imap <down> <nop>
imap <left> <nop>
imap <right> <nop>
nmap ]q :cn<cr>
nmap [q :cp<cr>

nnoremap <silent> <leader>/ :nohlsearch<cr>
nnoremap <silent> <leader><space> :nohlsearch<cr>
" Select just-pasted text:
nnoremap <silent> <leader>0 `[v`]
" Select just-pasted text and re-indent:
nnoremap <silent> <leader>) `[v`]=
nnoremap <silent> <leader>1 :set relativenumber!<cr>
nnoremap <leader>m :marks<cr>
nnoremap <leader>v :vsplit<cr>
nnoremap <leader>s :split<cr>
" <leader>a* currently conflicts with LspCodeAction
nnoremap <leader>ab :Gblame<cr>
nnoremap <leader>as :Gstatus<cr>
nnoremap <leader>ac :Commits<cr>
nnoremap <leader>ah :GitGutterLineHighlightsToggle<cr>
" yank filename of current buffer:
nmap <leader>f :let @" = expand("%")<cr>
" and into + register:
nmap <leader>F :let @+ = expand("%")<cr>

function! ToggleQuickFix()
  if empty(filter(getwininfo(), 'v:val.quickfix'))
    copen
  else
    cclose
  endif
endfunction
nmap <silent> <leader>q :call ToggleQuickFix()<cr>
nmap <silent> <leader>l :lclose<cr>

packadd! async.vim            " https://github.com/prabirshrestha/async.vim.git
packadd! asyncomplete.vim     " https://github.com/prabirshrestha/asyncomplete.vim.git
packadd! asyncomplete-lsp.vim " https://github.com/prabirshrestha/asyncomplete-lsp.vim.git

inoremap <expr> <Tab>   pumvisible() ? "\<C-n>" : "\<Tab>"
inoremap <expr> <S-Tab> pumvisible() ? "\<C-p>" : "\<S-Tab>"
inoremap <expr> <cr> pumvisible() ? asyncomplete#close_popup() . "\<cr>" : "\<cr>"

" vim-markdown configuration:
let g:vim_markdown_conceal = 1

" fzf configuration:
let g:fzf_action = {
  \ 'ctrl-t': 'tab split',
  \ 'ctrl-s': 'split',
  \ 'ctrl-v': 'vsplit' }
nmap <leader>t :Files<cr>
nmap <leader>T :GFiles<cr>
nmap <leader>b :Buffers<cr>
nmap <leader>gg :Rg<cr>

" Lightline configuration:
packadd! lightline.vim " https://github.com/itchyny/lightline.vim.git
set laststatus=2

function! LightlineLSPErrorText()
  let l:info = lsp#get_buffer_diagnostics_counts()
  if info.error == 0
    return ''
  endif
  let sign = get(g:lsp_diagnostics_signs_error, 'text', 'E')
  return info.error . sign
endfunction

function! LightlineLSPWarningText()
  let l:info = lsp#get_buffer_diagnostics_counts()
  if info.warning == 0
    return ''
  endif
  let sign = get(g:lsp_diagnostics_signs_warning, 'text', 'W')
  return info.warning . sign
endfunction

let g:lightline = {
      \ 'colorscheme': 'seoul256',
      \ 'active': {
      \   'left': [ [ 'mode', 'paste' ],
      \             [ 'readonly', 'filename', 'modified' ],
      \             [ 'gitbranch' ], ['lsperror', 'lspwarn'] ],
      \   'right': [ ['lineinfo'], ['percent'], ['filetype'], ['gobuild'] ],
      \ },
      \ 'component_function': {
      \   'gobuild': 'go#statusline#Show',
      \   'gitbranch': 'FugitiveStatusline',
      \ },
      \ 'component_expand': {
      \   'lsperror': 'LightlineLSPErrorText',
      \   'lspwarn': 'LightlineLSPWarningText',
      \ },
      \ 'component_type': {
      \   'lsperror': 'error',
      \   'lspwarn': 'warning',
      \ },
      \ 'mode_map': {
      \   'n' : 'N',
      \   'i' : 'I',
      \   'R' : 'R',
      \   'v' : 'V',
      \   'V' : 'V-LINE',
      \   "\<C-v>": 'V-BLOCK',
      \   'c' : 'C',
      \   's' : 'S',
      \   'S' : 'S-LINE',
      \   "\<C-s>": 'S-BLOCK',
      \   't': 'TERM',
      \ },
\ }

" vim-gitgutter configuration
packadd! vim-gitgutter " https://github.com/airblade/vim-gitgutter.git
set signcolumn=yes
nmap ]h <Plug>(GitGutterNextHunk)
nmap [h <Plug>(GitGutterPrevHunk)
omap ih <Plug>(GitGutterTextObjectInnerPending)
omap ah <Plug>(GitGutterTextObjectOuterPending)
xmap ih <Plug>(GitGutterTextObjectInnerVisual)
xmap ah <Plug>(GitGutterTextObjectOuterVisual)

" vim-fugitive
packadd! vim-fugitive       " https://github.com/tpope/vim-fugitive.git

" vim-go
" Doesn't work in after/ftplugin/go.vim:
let g:go_def_mapping_enabled = 0
packadd! vim-go             " https://github.com/fatih/vim-go.git

" LSP configuration:
packadd! vim-lsp            " https://github.com/prabirshrestha/vim-lsp.git
packadd! vim-lsp-settings   " https://github.com/mattn/vim-lsp-settings.git

let g:lsp_settings = {
      \ 'gopls': {
      \   'initialization_options': {
      \     'ui.diagnostic.analyses': {
      \       'composites': v:false,
      \       'unusedparams': v:true,
      \       'unusedresult': v:true,
      \       'shadow': v:true,
      \       'nilness': v:true,
      \       'unusedwrite': v:true,
      \     },
      \     'staticcheck': v:true,
      \     'hoverKind': 'FullDocumentation',
      \     'linksInHover': v:false,
      \     'experimentalWorkspaceModule': v:false,
      \ }}}
let g:lsp_diagnostics_float_cursor = 1
let g:lsp_diagnostics_float_delay = 175
let g:lsp_diagnostics_highlight_delay = 175
let g:lsp_diagnostics_signs_delay = 175
let g:lsp_diagnostics_code_action_signs_delay = 175
let g:lsp_document_highlight_delay = 500
let g:lsp_async_completion = 1

function! s:on_lsp_buffer_enabled() abort
    setlocal omnifunc=lsp#complete
    " number may be clobbered by vim-fugitive?
    setlocal number
    setlocal signcolumn=yes

    " Jump to definitions
    nmap <buffer> gd <plug>(lsp-definition)
    nmap <buffer> gvd :vertical :LspDefinition<cr>
    nmap <buffer> gsd :belowright :LspDefinition<cr>
    nmap <buffer> gD <plug>(lsp-type-definition)
    nmap <buffer> gvD :vertical :LspTypeDefinition<cr>
    nmap <buffer> gsD :belowright :LspTypeDefinition<cr>
    " Map to leader keys too, easy typo:
    nmap <buffer> <leader>gd <plug>(lsp-definition)
    nmap <buffer> <leader>gD <plug>(lsp-type-definition)

    " Peek definitions, only on leader keys
    nmap <buffer> <leader>pd <plug>(lsp-peek-definition)
    nmap <buffer> <leader>pD <plug>(lsp-peek-type-definition)

    " Navigation
    nmap <buffer> <silent> ]e <plug>(lsp-next-error)
    nmap <buffer> <silent> [e <plug>(lsp-previous-error)
    nmap <buffer> <silent> ]d <plug>(lsp-next-diagnostic)
    nmap <buffer> <silent> [d <plug>(lsp-previous-diagnostic)
    nmap <buffer> <silent> ]r <plug>(lsp-next-reference)
    nmap <buffer> <silent> [r <plug>(lsp-previous-reference)

    " Misc actions
    nmap <buffer> <leader>ci <plug>(lsp-call-hierarchy-incoming)
    nmap <buffer> <leader>co <plug>(lsp-call-hierarchy-outgoing)
    nmap <buffer> <leader>ca <plug>(lsp-code-action)
    nmap <buffer> <leader>i <plug>(lsp-implementation)
    nmap <buffer> <leader>r <plug>(lsp-references)
    nmap <buffer> <leader>d <plug>(lsp-hover)
    nmap <buffer> <leader>o :silent LspCodeAction source.organizeImports<cr>

    nmap <buffer> <leader>e <plug>(lsp-rename)
endfunction

augroup lsp_install
    au!
    autocmd User lsp_buffer_enabled call s:on_lsp_buffer_enabled()
    autocmd User lsp_diagnostics_updated call lightline#update()
    autocmd BufWritePre *.go silent LspDocumentFormatSync
    " autocmd CursorHold <buffer> silent LspHover
augroup END

" load internal plugins:
runtime macros/matchit.vim

" load other plugins:
packadd! rust.vim          " https://github.com/rust-lang/rust.vim.git
packadd! tmux-complete.vim " https://github.com/wellle/tmux-complete.vim.git
packadd! vim-commentary    " https://github.com/tpope/vim-commentary.git

" Requires both fzf.vim plugin to be manually installed:
" https://github.com/junegunn/fzf/blob/master/plugin/fzf.vim
" and also this separate plugin, which is loaded here:
packadd! fzf.vim           " https://github.com/junegunn/fzf.vim.git
packadd! vim-surround      " https://github.com/tpope/vim-surround.git
packadd! vim-rhubarb       " https://github.com/tpope/vim-rhubarb.git
packadd! editorconfig-vim  " https://github.com/editorconfig/editorconfig-vim.git