let mapleader = ","
set nocompatible              " be iMproved, required
filetype off                  " required

let plug_fpath="~/.vim/autoload/plug.vim"
if filereadable(expand(plug_fpath))
    call plug#begin()

    Plug 'scrooloose/nerdtree'
    Plug 'vim-scripts/c.vim'
    Plug 'jeetsukumaran/vim-buffergator'
    Plug 'ericcurtin/CurtineIncSw.vim'
    Plug 'tpope/vim-fugitive'
    Plug 'tpope/vim-surround'
    Plug 'ctrlpvim/ctrlp.vim'
    Plug 'rhysd/vim-clang-format'
    Plug 'godlygeek/tabular'
    Plug 'airblade/vim-gitgutter'
    Plug 'jeetsukumaran/vim-pythonsense'
    Plug 'easymotion/vim-easymotion'
    Plug 'cpiger/NeoDebug'
    Plug 'ivan-krukov/vim-snakemake'
    Plug 'nvie/vim-flake8'
    Plug 'ludovicchabant/vim-gutentags'
    Plug 'junegunn/vim-peekaboo'
    if has('python3') && empty($VIM_DISABLE_YCM)
        Plug 'ycm-core/YouCompleteMe', { 'do': './install.py' }
    endif
    Plug 'dense-analysis/ale'
    Plug 'tpope/vim-unimpaired'
    Plug 'JuliaEditorSupport/julia-vim'
    Plug 'tell-k/vim-autopep8'
    Plug 'jpalardy/vim-slime'
    Plug 'preservim/tagbar'
    Plug 'wellle/context.vim'

    call plug#end()
else
    let plug_url="https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim"
    echo "Plug not installed, type :CurlPlug to download and install plug"
    command! CurlPlug execute "!curl -fLo " . plug_fpath . " --create-dirs " .  plug_url | source $MYVIMRC | echo "Curled Plug. Do :PlugInstall"
endif

set tabstop=4 " show existing tab with 4 spaces width
set shiftwidth=4 " when indenting with '>', use 4 spaces width
set expandtab " On pressing tab, insert 4 spaces

if !exists("vimrc_autocmds_loaded")
    let vimrc_autocmds_loaded = 1

    " Set the filetype based on the file's extension, but only if
    " 'filetype' has not already been set
    au BufRead,BufNewFile .i3initrc      setfiletype sh
    au BufRead,BufNewFile *.config       setfiletype conf
    au BufRead,BufNewFile [Ss]nakefile.* setfiletype snakemake

    au BufWritePost * if search('\s\+$', 'wn') | call WhitespaceWarn() | endif

    au BufRead,BufNewFile *    setlocal textwidth=0  | setlocal colorcolumn=
    au BufRead,BufNewFile *.md setlocal textwidth=80 | setlocal colorcolumn=80
    au BufRead,BufNewFile *.py setlocal colorcolumn=100
    au FileType html setlocal shiftwidth=2 tabstop=2
    autocmd FileType javascript setlocal shiftwidth=2 tabstop=2
    autocmd FileType javascriptreact setlocal shiftwidth=2 tabstop=2
    autocmd FileType typescript setlocal shiftwidth=2 tabstop=2
    autocmd FileType typescriptreact setlocal shiftwidth=2 tabstop=2

    if exists(":NERDTree")
        " Open NERDTree if no file specified
        au StdinReadPre * let s:std_in=1
        au VimEnter * if argc() == 0 && !exists("s:std_in") | NERDTree | endif
    endif

    au BufEnter,FocusGained,InsertLeave * set rnu
    au BufLeave,FocusLost,InsertEnter   * set nornu
endif
set updatetime=1000 " Default is 4s, but reduce it to make things more real time, like git gutter

filetype plugin indent on    " required
syntax on

" These two lines will fully disable any visual or noisy bell
" on both windows and linux. >:)
set noerrorbells visualbell t_vb=
autocmd GUIEnter * set visualbell t_vb=

" Make indenting and unindenting in visual mode retain the selection so
" you don't have to re-select or type gv every time.
vnoremap > ><CR>gv
vnoremap < <<CR>gv

set mouse=a
set hlsearch
set scrolloff=5 " Don't let cursor be within 5 lines from top or bottom

" Warn for trailing whitespace. Search with wrap (w) do not move cursor (n)
function! WhitespaceWarn()
    if &ft =~ 'markdown'
        return
    endif
    echohl WarningMsg
    echo 'Found whitespace.'
    echohl None
    echon ' Type :TrailWhitespace to remove it'
endfunction
function! StripTrailingWhitespace()
    " Save cursor position
    let l:save = winsaveview()
    " Remove trailing whitespace
    %s/\s\+$//e
    " Move cursor to original position
    call winrestview(l:save)
    echo "Stripped trailing whitespace"
endfunction

command! TrailWhitespace call StripTrailingWhitespace()

" Hybrid line numbers on active buffer
set nu rnu

" Do incremental searching when it's possible to timeout.
if has('reltime')
  set incsearch
endif

" Copy to the end of line
noremap Y y$

" define upper case versions of :w and :q
command! -bang -range=% -complete=file -nargs=* W <line1>,<line2>write<bang> <args>
command! -bang Q quit<bang>

let g:ctrlp_map = '<c-p>'
let g:ctrlp_cmd = 'CtrlPMixed'
let g:ctrlp_working_path_mode = 'ra'  " Look for .git .hg .svn .bzr _darcs
let g:ctrlp_custom_ignore = {
      \ 'dir':  '\v[\/]\.(git|hg|svn|data|logs)$',
      \ 'file': '\v\.(exe|so|dll)$',
      \ }

" Gutentags configuration
if !executable('ctags')
    let g:gutentags_enabled = 0
else
    nmap <F1> :CtrlPTag<CR>
    nmap <F4> :TagbarToggle<CR>

    let g:gutentags_add_default_project_roots = 0
    let g:gutentags_project_root = ['.git']

    let g:gutentags_generate_on_new = 1
    let g:gutentags_generate_on_missing = 1
    let g:gutentags_generate_on_write = 1
    let g:gutentags_generate_on_empty_buffer = 0

    " Put all tags in one place
    let g:gutentags_cache_dir = expand('~/.cache/vim/ctags/')

    " Extra tag information
    let g:gutentags_ctags_extra_args = [
          \ '--tag-relative=yes',
          \ '--fields=+ailmnS',
          \ ]

    let g:gutentags_ctags_exclude = [
          \ '*.git', '*.svg', '*.hg',
          \ '*/tests/*',
          \ 'build',
          \ 'dist',
          \ '*sites/*/files/*',
          \ 'bin',
          \ 'node_modules',
          \ 'bower_components',
          \ 'cache',
          \ 'compiled',
          \ 'docs',
          \ 'example',
          \ 'bundle',
          \ 'vendor',
          \ '*.md',
          \ '*-lock.json',
          \ '*.lock',
          \ '*bundle*.js',
          \ '*build*.js',
          \ '.*rc*',
          \ '*.json',
          \ '*.min.*',
          \ '*.map',
          \ '*.bak',
          \ '*.zip',
          \ '*.pyc',
          \ '*.class',
          \ '*.sln',
          \ '*.Master',
          \ '*.csproj',
          \ '*.tmp',
          \ '*.csproj.user',
          \ '*.cache',
          \ '*.pdb',
          \ 'tags*',
          \ 'cscope.*',
          \ '*.css',
          \ '*.less',
          \ '*.scss',
          \ '*.exe', '*.dll',
          \ '*.mp3', '*.ogg', '*.flac',
          \ '*.swp', '*.swo',
          \ '*.bmp', '*.gif', '*.ico', '*.jpg', '*.png',
          \ '*.rar', '*.zip', '*.tar', '*.tar.gz', '*.tar.xz', '*.tar.bz2',
          \ '*.pdf', '*.doc', '*.docx', '*.ppt', '*.pptx',
          \ ]

endif

" YouCompleteMe Python interpreter
let g:ycm_python_interpreter_path = '~/.python-venv.kuba/bin/python'
"let g:ycm_autoclose_preview_window_after_insertion = 1 " Close after leaving insert mode
let g:ycm_autoclose_preview_window_after_completion = 1 " Close after accepting completion

" ALE
let g:ale_linters = {
            \   'python': ['flake8'],
            \   'c':      ['gcc']
            \}
let g:ale_virtualtext_cursor = 'disable'
let g:ale_set_highlights = 1
let g:ale_sign_error = '>>'
let g:ale_sign_warning = '--'
let g:ale_lint_on_text_changed = 'never'
let g:ale_lint_on_enter = 0
let g:ale_c_parse_makefile = 1
let g:ale_lint_on_insert_leave = 1
let g:ale_set_loclist = 1

" fugitive.vim looks for tags in .git
" set tags +=~/tags " Recursively move upwards in tree, searching in subfolders for tags file

" Status line
set laststatus=2
set statusline=
set statusline+=%#StatusLineTerm#
if exists('g:loaded_fugitive')
    set statusline+=%{FugitiveStatusline()}
endif
set statusline+=%#MoreMsg#
set statusline+=\ %f
set statusline+=%m\ "
set statusline+=%=
set statusline+=%#WildMenu#
set statusline+=%y
set statusline+=\ %p%%
set statusline+=\ %l:%c"
set statusline+=%#MoreMsg#
set statusline+=\ "

" Colors
" Useful for testing:
" :runtime syntax/colortest.vim
" :runtime syntax/hitest.vim
highlight SignColumn      ctermbg=NONE
highlight GitGutterAdd    ctermbg=NONE      ctermfg=DarkGreen
highlight GitGutterChange ctermbg=NONE      ctermfg=Yellow
highlight GitGutterDelete ctermbg=NONE      ctermfg=DarkRed
highlight GitGutterDelete ctermbg=NONE      ctermfg=DarkRed
highlight Search          ctermbg=Brown     ctermfg=LightRed
highlight ColorColumn     ctermbg=DarkBlue
highlight Visual          ctermbg=LightBlue
highlight DiffChange      ctermbg=black     ctermfg=lightgreen
highlight ALEInfo         ctermbg=DarkBlue  ctermfg=White
highlight ALEWarning      ctermbg=DarkBlue  ctermfg=Black
highlight ALEError        ctermbg=DarkRed   ctermfg=Black
highlight SpellCap        ctermbg=DarkBlue  ctermfg=Black
highlight SpellBad        ctermbg=DarkRed   ctermfg=Black

" flake8
let g:flake8_show_in_gutter=1

" CtrlP
let g:ctrlp_working_path_mode = 'ra'

" Find project root
let git_dir_location=finddir('.git', ';')
let git_root_location=fnamemodify(git_dir_location, ':h')

" Simulate maximize/minimize window
nnoremap <C-w>m :call ToggleMiniMaxiWin()<CR>
nnoremap <leader>wm :call ToggleMiniMaxiWin()<CR>
function! ToggleMiniMaxiWin()
    if tabpagewinnr(tabpagenr(), '$') > 1
        tab split
    elseif tabpagenr('$') > 1
        if tabpagenr() < tabpagenr('$')
            tabclose
            tabprevious
        else
            tabclose
        endif
    endif
endfunction

function! ToggleNumbersAndGutter()
    if !exists('b:numbers_and_gutter_on') || b:numbers_and_gutter_on == 1
        set nonumber
        set norelativenumber
        GitGutterBufferDisable
        let b:numbers_and_gutter_on=0
    else
        set number
        set relativenumber
        GitGutterBufferEnable
        let b:numbers_and_gutter_on=1
    endif
endfunction

nnoremap <leader>1 :call ToggleNumbersAndGutter()<CR>

" Key binds
"
command! Csc cscope find c <cword>

" Easymotion leader
map <Leader><tab> <Plug>(easymotion-prefix)
" Forwards and backwards jump and visual select
map <tab> <Plug>(easymotion-s)
map <space> <C-V><Plug>(easymotion-s)
" Forwards and backwards word jump
map <Leader>w <Plug>(easymotion-bd-w)
" Easymotion overwin line
nmap <Leader><tab>l <Plug>(easymotion-overwin-line)
" Easymotion search
nmap <S-tab> <Plug>(easymotion-sn)
nmap <S-tab> <Plug>(easymotion-tn)

" Replace the word under cursor
nnoremap <leader>* :%s/\<<c-r><c-w>\>//g<left><left>
" Replace visual selection
vnoremap <leader>* y:%sno/<c-r>"//g<left><left>

nmap <F2> :NERDTreeToggle<CR>
nmap <F3> :NERDTreeFind<CR>
map <F5> :call CurtineIncSw()<CR>

let g:context_enabled = 0
map <F6> :ContextToggle<CR>
map cp :ContextPeek<CR>

" Julialang
let g:latex_to_unicode_auto = 1

noremap <expr> <F7> LaTeXtoUnicode#Toggle()
noremap! <expr> <F7> LaTeXtoUnicode#Toggle()
autocmd FileType python noremap <buffer> <F8> :call Autopep8()<CR>

let g:slime_target = "tmux"
let g:slime_default_config = {"socket_name": "default", "target_pane": "{last}"}

nmap <Leader>cf :cd %:p:h <CR> " Change dir to parent of current file
nmap <Leader>cg :cd $git_root_location <CR> " Change dir to git root
nmap <Leader>vs :sp $HOME/.vimrc <CR>
nmap <Leader>vv :vsp $HOME/.vimrc <CR>
nmap <Leader>vt :tabnew $HOME/.vimrc <CR>
nmap <Leader>vo :e $HOME/.vimrc <CR>
nmap <Leader>v :e $HOME/.vimrc <CR>

" Match git conflict markers
nmap <Leader>/g /[<=>]\{7,}.*$<CR>
" Git-Gutter status, commit, grep, blame
nmap <Leader>gs :Gstatus<CR>
nmap <Leader>gS :!git add %<CR>
nmap <Leader>gc :Gcommit<CR>
nmap <Leader>gg :Ggrep<space>
nmap <Leader>gb :Gblame<CR>
nmap <Leader>gu :GitGutterUndoHunk<CR>

" Fugitive Conflict Resolution
nnoremap <leader>gd :Gvdiffsplit!<CR>
nnoremap gdh :diffget //2<CR>
nnoremap gdl :diffget //3<CR>

" Toggle wrapping of long lines
nmap <Leader>l :set wrap!<CR>

" Strip trailing whitespace
nmap <Leader><space> :TrailWhitespace <CR>

" Scroll window while keeping cursor on same line with shift
nmap <S-j> <c-e>
nmap <S-k> <c-y>
vmap <S-j> <c-e>
vmap <S-k> <c-y>

" Toggle paste mode
nmap <Leader>p :set paste! <CR>

" Misc.
map <Leader>n :noh<CR>
vmap <Leader>T :'<,'> Tabularize /
nnoremap <leader>c :execute "set colorcolumn=" . (&colorcolumn == "" ? "120" : "")<CR>
