" designed for vim 7+ (and inspired by rwxrob) 
" tested with vim 7.4.629
" https://github.com/starr-dusT/dotfiles

"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" general 
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""

set autowrite " automatically write files on close

" tabs and spaces and stuff
set tabstop=4
set softtabstop=4
set shiftwidth=4
set expandtab

" undos
if !isdirectory($HOME."/.vim")
    call mkdir($HOME."/.vim", "", 0770)
endif
if !isdirectory($HOME."/.vim/undo-dir")
    call mkdir($HOME."/.vim/undo-dir", "", 0700)
endif
set undodir=~/.vim/undo-dir
set undofile

" map leader to Space
let mapleader = " " 

" clipboard
set clipboard=unnamedplus

"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" ui
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""

syntax enable
set number
set colorcolumn=79
set updatetime=50
set scrolloff=8
set smartindent
set incsearch " hilight search matches while typing


" maximize focused split vertically creating almost 'tabs' 
let g:max_lock=0
autocmd WinEnter * if !g:max_lock | call MaxSplit(&buftype) | endif

"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" wildmenu
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""

" ignore compiled files
set wildignore=*.o,*~,*.pyc
if has("win16") || has("win32")
    set wildignore+=.git\*,.hg\*,.svn\*
else
    set wildignore+=*/.git/*,*/.hg/*,*/.svn/*,*/.DS_Store
endif

" enable fuzzy finding in the vim command line
set path=$PWD/**        
set nowildmenu
set wildmode=list:full

"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" netrw
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""

let g:netrw_banner = 0 " disable dumb banner

" use l and h for up/down dir
augroup netrw_setup | au!
    au FileType netrw nmap <buffer> l <CR>
    au FileType netrw nmap <buffer> h -
augroup END

map <leader>e :Ex <cr> " open explorer

"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" marks
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""

" automatically update marks with helper function
au CursorHold,CursorHoldI,CursorMoved,CursorMovedI,TextChanged * silent! call UpdateMarkSigns()

" allow only global marks
noremap <silent> <expr> ' "'".toupper(nr2char(getchar()))
noremap <silent> <expr> m "m".toupper(nr2char(getchar()))
sunmap '
sunmap m

" list marks
map <leader>mm :marks<cr>

" clear marks
map <leader>md :delmarks A-Z0-9 <cr>                   

"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" grep
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""

set grepprg=grep\ --exclude-dir=\".git\"\ -snH\ $* " use system grep
command! -nargs=+ -complete=file_in_path -bar Grep  cgetexpr Grep(<f-args>)
command! -nargs=+ -complete=file_in_path -bar LGrep lgetexpr Grep(<f-args>)

" open quickfix
augroup quickfix
	autocmd!
	autocmd QuickFixCmdPost cgetexpr bot cwindow
	autocmd QuickFixCmdPost lgetexpr bot lwindow
augroup END

" grep into quickfix/location list
map <leader>fq :Grep -r<space>
map <leader>fl :LGrep -r<space>

" next/last location
map <leader>ln :lnext<CR>
map <leader>lp :lprev<CR>

" next/last quickfix
map <leader>cn :cnext<CR>
map <leader>cp :cnext<CR>

"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" notes 
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""

command! Ill call InsertLocationLink()

" copy quick/location selection to clipboard
nnoremap <Leader>nl :Ill<CR>

"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" misc keys
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""

" yank and paste from system clipboard
map <leader>y :"+y <cr>
map <leader>p :"+p <cr>p

" open help with word under cursor 
map <leader>oh :execute "help " . expand("<cword>")<CR>

" move between splits with hjkl
map <leader>j <C-W>j
map <leader>k <C-W>k
map <leader>h <C-W>h
map <leader>l <C-W>l

" find
map <leader>ff :find *

" change directories
map <leader>cc :cd<space>
map <leader>cd :cd ~/.local/share/chezmoi  <cr>

" open common files
map <leader>ov :e ~/.local/share/chezmoi/home/dot_vimrc <cr>

" functions keys
map <F1> :set number!<CR> :set relativenumber!<CR>
map <F2> :set list!<CR>
map <F3> :set cursorline!<CR>
map <F4> :set spell!<CR>

" better use of arrow keys, number increment/decrement
nnoremap <up> <C-a>
nnoremap <down> <C-x>

"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" helpers
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""

" maximize current vertical split (and handle quick/location list)
" OG baby!
"
function! MaxSplit(b)
    let g:max_lock=1 " prevent multiple autocmds at the same time
    let curr_win = winnr()
    if a:b !=# 'quickfix' && a:b !=# 'locationlist' 
        exe "normal! z99\<CR>"
        for i in range(winnr(), winnr('$'))
            let b = getwinvar(i, '&buftype')
            if b == 'quickfix' || b == 'locationlist' 
                exe "normal! z10\<CR>"
            endif
            wincmd j
        endfor
        exe curr_win . "wincmd w"
    endif
    let g:max_lock=0
endfunction

" better grep wrapper 
" https://gist.github.com/romainl/56f0c28ef953ffc157f36cc495947ab3
"
function! Grep(...)
	return system(join([&grepprg] + [expand(join(a:000, ' '))], ' '))
endfunction

" Check if file is valid and exists
" ChatGippity 
"
function! IsValidFilename(filename)
  let expanded_filename = expand(a:filename)
  if !empty(expanded_filename) && filereadable(expanded_filename)
    return 1
  else
    return 0
  endif
endfunction

" Place sign with particular symbol at line
" ChatGippity 
"
function! PlaceSign(id, symbol, line_number)
  let buff = bufnr('')
  " For compatibility with vim7 can't use nice sign functions  
  exe "sign define " . a:symbol . " text=" . a:symbol
  exe "sign place " . a:id . " line=" . a:line_number . " name=" . a:symbol . " buffer=" . buff
endfunction

" Use signs to visualize marks and update for current buffer
" OG baby!
"
function! UpdateMarkSigns()
    " Reserved unique IDs for marks in case we want to remove in future
    " without wiping out all signs
    let resvIDs = range(1000, 1027)
    
   " wipe out all signs (might improve in future)
    execute "sign unplace *"

    " get all marks
    let lines = ""
    redir => lines 
    :silent marks
    redir END

    let linesList = split(lines, "\n")[1:]
    for i in range(len(linesList))
        let line = linesList[i]
        let id = resvIDs[i]

        let splitLine = split(line)
        let name = splitLine[0] 
        let row = splitLine[1]
        let col = splitLine[2]
        try " empty lines at marks will break things
            let file = splitLine[3]
        catch
            let file = ""
        endtry

        " If marks is in another file we don't need to display it
        if !IsValidFilename(file)
            call PlaceSign(id, name, row)
        endif
    endfor
endfunction

" Create markdown link for current location list selection
" OG baby!
"
function! InsertLocationLink()
    let loc_idx = line('.') - 1
    let loc_list = getloclist(0)
    let link = bufname(l:loc_list[l:loc_idx].bufnr)
    call setreg('l', link)
    :lcl
    let title = input("Link name: ")
    let curr_path = substitute(expand('%:p:h'), finddir('.git/..', expand('%:p:h').';'), '', "g")
    let nest_count = count(curr_path, "/")
    let file_path = getreg('l')
    if nest_count < 1
        let file_path = join(['./', file_path], '')
    else
        while nest_count > 0
            let file_path = join(['../', file_path], '')
            let nest_count -= 1
        endwhile
    endif
    let link = join(['[', title, '](', file_path, ')'], "")
    exe "normal! a" . link . "\<Esc>"
endfunction
