" =============================================================================
" vdir vimrc
" =============================================================================

let g:vd_disable_default_options = get(g:, 'vd_disable_default_options', v:false)
let g:vd_disable_all_mappings = get(g:, 'vd_disable_all_mappings', v:false)
let g:vd_disable_default_mappings = get(g:, 'vd_disable_default_mappings', v:false)
let g:vd_disable_syntax_highlight = get(g:, 'vd_disable_syntax_highlight', v:false)

" =============================================================================

if !g:vd_disable_default_options
    " Turn off line number for not interferring with item index
    setlocal nonu

    " Turn off line wrap for displaying long file paths
    setlocal nowrap

    " Comment settings
    let g:tcomment#options = {'whitespace': 'no'}
    setlocal commentstring=#%s
endif


if !g:vd_disable_all_mappings
    function! VDIsLineInventoryItem (line)
        return match(a:line, '\v^[*+@#]?\d+\t') >= 0
    endfunction

    function! VDMoveToLineStart ()
        " Not a VDInventoryItem
        let line = getline('.')
        if !VDIsLineInventoryItem(line)
            return '^'
        endif

        let ret = ''

        let col = col('.')
        if col == 1
            let ret .= '^W'
        elseif col <= match(line, '\v\t') + 2
            let ret .= '^'
        else
            let ret .= '^W'
        endif

        return ret
    endfunction

    function! VDCursorMove (key)
        if empty(a:key) || a:key == '^'
            return ''
        endif

        return a:key . "\<Plug>(VDKey[^])"
    endfunction

    " Cursor movement API
    nnoremap <silent> <expr> <Plug>(VDKey[^]) VDMoveToLineStart()
    nnoremap <silent> <expr> <Plug>(VDKey[H]) VDCursorMove('H')
    nnoremap <silent> <expr> <Plug>(VDKey[M]) VDCursorMove('M')
    nnoremap <silent> <expr> <Plug>(VDKey[L]) VDCursorMove('L')
    nnoremap <silent> <expr> <Plug>(VDKey[G]) VDCursorMove('G')
    nnoremap <silent> <expr> <Plug>(VDKey[c-u]) VDCursorMove("\<C-u>")
    nnoremap <silent> <expr> <Plug>(VDKey[c-d]) VDCursorMove("\<C-d>")
    nnoremap <silent> <expr> <Plug>(VDKey[c-b]) VDCursorMove("\<C-b>")
    nnoremap <silent> <expr> <Plug>(VDKey[c-f]) VDCursorMove("\<C-f>")

    xnoremap <silent> <expr> <Plug>(VDKey[^]) VDMoveToLineStart()
    xnoremap <silent> <expr> <Plug>(VDKey[H]) VDCursorMove('H')
    xnoremap <silent> <expr> <Plug>(VDKey[M]) VDCursorMove('M')
    xnoremap <silent> <expr> <Plug>(VDKey[L]) VDCursorMove('L')
    xnoremap <silent> <expr> <Plug>(VDKey[G]) VDCursorMove('G')
    xnoremap <silent> <expr> <Plug>(VDKey[c-u]) VDCursorMove("\<C-u>")
    xnoremap <silent> <expr> <Plug>(VDKey[c-d]) VDCursorMove("\<C-d>")
    xnoremap <silent> <expr> <Plug>(VDKey[c-b]) VDCursorMove("\<C-b>")
    xnoremap <silent> <expr> <Plug>(VDKey[c-f]) VDCursorMove("\<C-f>")

    " Item editing API
    nnoremap <silent> <expr> <Plug>(VDEditWholeLine) '0' . "\<Plug>(VDKey[^])" . 'C'
    nnoremap <silent> <expr> <Plug>(VDEditAtStartOfLine) '0' . "\<Plug>(VDKey[^])" . 'i'

    function! VDToggleMark (mark)
        let line = getline('.')
        if empty(line)
            return
        endif

        if !VDIsLineInventoryItem(line)
            return
        endif

        let mark_len = len(a:mark)

        for i in range(len(a:mark))
            if line[0] == a:mark[i]
                if i == mark_len - 1
                    normal! h
                    call setline('.', strpart(line, 1))
                else
                    call setline('.', a:mark[i + 1] . strpart(line, 1))
                endif
                return
            endif
        endfor

        let m = matchlist(line, '\v^([*+@#]?)(\d+\t.*)$')
        call setline('.', a:mark[0] . m[2])
        if empty(m[1])
            normal! l
        endif
    endfunction

    " Toggle @ mark
    nnoremap <silent> <Plug>(VDToggleResolveMark) :call VDToggleMark('@')<CR>
    xnoremap <silent> <Plug>(VDToggleResolveMark) :call VDToggleMark('@')<CR>

    " Toggle + and * mark
    nnoremap <silent> <Plug>(VDToggleExpandMark) :call VDToggleMark('+*')<CR>
    xnoremap <silent> <Plug>(VDToggleExpandMark) :call VDToggleMark('+*')<CR>

    " Toggle # mark
    nnoremap <silent> <Plug>(VDToggleUntrackMark) :call VDToggleMark('#')<CR>
    xnoremap <silent> <Plug>(VDToggleUntrackMark) :call VDToggleMark('#')<CR>
endif


if !g:vd_disable_default_mappings
    " Cursor movement default binding
    nmap <buffer> ^ <Plug>(VDKey[^])
    nmap <buffer> H <Plug>(VDKey[H])
    nmap <buffer> M <Plug>(VDKey[M])
    nmap <buffer> L <Plug>(VDKey[L])
    nmap <buffer> G <Plug>(VDKey[G])
    nmap <buffer> <C-u> <Plug>(VDKey[c-u])
    nmap <buffer> <C-d> <Plug>(VDKey[c-d])
    nmap <buffer> <C-b> <Plug>(VDKey[c-b])
    nmap <buffer> <C-f> <Plug>(VDKey[c-f])

    xmap <buffer> ^ <Plug>(VDKey[^])
    xmap <buffer> H <Plug>(VDKey[H])
    xmap <buffer> M <Plug>(VDKey[M])
    xmap <buffer> L <Plug>(VDKey[L])
    xmap <buffer> G <Plug>(VDKey[G])

    " Item editing default binding
    nmap <buffer> cc <Plug>(VDEditWholeLine)
    nmap <buffer> S  <Plug>(VDEditWholeLine)
    nmap <buffer> I  <Plug>(VDEditAtStartOfLine)

    " Toggle @ mark
    nmap <buffer> @@ <Plug>(VDToggleResolveMark)
    xmap <buffer> @@ <Plug>(VDToggleResolveMark)

    " Toggle + and * mark
    nmap <buffer> ++ <Plug>(VDToggleExpandMark)
    xmap <buffer> ++ <Plug>(VDToggleExpandMark)

    " Toggle # mark
    nmap <buffer> ## <Plug>(VDToggleUntrackMark)
    xmap <buffer> ## <Plug>(VDToggleUntrackMark)
endif


if !g:vd_disable_syntax_highlight
    if v:version >= 900
        setlocal listchars=tab:\\x20│\\x20
    else
        setlocal listchars=tab:\ │
    endif

    syntax region VDComment start=/^#/ end=/$/ oneline keepend
    highlight link VDComment Comment

    " Parse $LS_COLORS for basic highlighting
    let s:ls_colors = {}
    for s:entry in split($LS_COLORS, ':')
        let s:m = matchlist(s:entry, '\v^(\w+)\=([0-9;]+)$')
        let [s:unused, s:glob, s:code; s:unused] = s:m

        let s:code_list = split(s:code, ';')
        call map(s:code_list, 'str2nr(v:val, 10)')

        while !empty(s:code_list)
            if s:code_list[0] == 1
                let s:attr = 'bold'

            elseif 30 <= s:code_list[0] && s:code_list[0] <= 37
                let s:fg = (s:code_list[0] - 30)

            elseif 40 <= s:code_list[0] && s:code_list[0] <= 47
                let s:bg = (s:code_list[0] - 40)

            elseif s:code_list[0:1] == [38, 5]
                let s:code_list = s:code_list[2:]
                let s:fg = s:code_list[0]

            elseif s:code_list[0:1] == [48, 5]
                let s:code_list = s:code_list[2:]
                let s:bg = s:code_list[0]

            endif

            call remove(s:code_list, 0)
        endwhile

        let s:cterm = exists('s:attr') ? ('cterm='. s:attr) : ''
        let s:ctermfg = exists('s:fg') ? ('ctermfg='. string(s:fg)) : ''
        let s:ctermbg = exists('s:bg') ? ('ctermbg='. string(s:bg)) : ''

        let s:ls_colors[s:glob] = [s:cterm, s:ctermfg, s:ctermbg]
    endfor

    syntax region VDInventoryItem start=/^\v[+*@]?\d+/ end=/$/ oneline keepend

    highlight link VDIII Number
    syntax match VDIII /\v(^\D?)@<=\zs(\d+)\ze\t/ contained containedin=VDInventoryItem
                \ nextgroup=VDFileItem,VDDirItem,VDExecFileItem,VDLinkItem,VDDeadLinkItem,VDFileItem,VDErrorItem

    syntax match VDFileItem     /\v(^\D?\d+0\t)@<=\zs(.+)\ze$/ contained containedin=VDInventoryItem
    syntax match VDDirItem      /\v(^\D?\d+1\t)@<=\zs(.+)\ze$/ contained containedin=VDInventoryItem
    syntax match VDExecFileItem /\v(^\D?\d+2\t)@<=\zs(.+)\ze$/ contained containedin=VDInventoryItem
    syntax match VDLinkItem     /\v(^\D?\d+3\t)@<=\zs(.+)\ze$/ contained containedin=VDInventoryItem
    syntax match VDDeadLinkItem /\v(^\D?\d+4\t)@<=\zs(.+)\ze$/ contained containedin=VDInventoryItem
    syntax match VDFifoItem     /\v(^\D?\d+5\t)@<=\zs(.+)\ze$/ contained containedin=VDInventoryItem
    syntax match VDErrorItem    /\v(^\D?\d+9\t)@<=\zs(.+)\ze$/ contained containedin=VDInventoryItem

    syntax match VDFilePath /\v\t@<=.+$/ contained containedin=VDFileItem

    syntax match VDDirPath /\v\t@<=.+$/ contained containedin=VDDirItem
    if has_key(s:ls_colors, 'di')
        exec join(['highlight', 'VDDirPath', ] + s:ls_colors['di'])
    endif

    syntax match VDExecFilePath /\v\t@<=.+$/ contained containedin=VDExecFileItem
    if has_key(s:ls_colors, 'ex')
        exec join(['highlight', 'VDExecFilePath', ] + s:ls_colors['ex'])
    endif

    syntax match VDLinkArrow /\v *\V->\v */ containedin=VDLinkItem,VDDeadLinkItem
    highlight VDLinkArrow ctermfg=240 " TBD

    syntax match VDLinkPath /\v\t@<=\zs.*[^ ]\ze( *\V->\v)@=/ contained containedin=VDLinkItem,VDDeadLinkItem
    highlight VDLinkPath ctermfg=220 " TBD
    if has_key(s:ls_colors, 'ln')
        exec join(['highlight', 'VDLinkPath', ] + s:ls_colors['ln'])
    endif

    syntax match VDLinkTarget /\v(\t.+ *\V->\v *)@<=[^ ].+$/ contained containedin=VDLinkItem

    syntax match VDDeadLinkPath /\v\t@<=\zs.+[^ ]\ze( *\V->\v)@=/ contained containedin=VDDeadLinkItem
    if has_key(s:ls_colors, 'ln')
        exec join(['highlight', 'VDDeadLinkPath', ] + s:ls_colors['ln'])
    endif

    syntax match VDDeadLinkTarget /\v(\t.+ *\V->\v *)@<=[^ ].+$/ contained containedin=VDDeadLinkItem
    highlight VDDeadLinkTarget ctermfg=9

    syntax match VDFifoPath /\v\t@<=.+[^|]/ contained containedin=VDFifoItem
    if has_key(s:ls_colors, 'pi')
        exec join(['highlight', 'VDFifoPath', ] + s:ls_colors['pi'])
    endif

    syntax match VDFifoSymbol /|$/ contained containedin=VDFifoItem
    highlight VDFifoSymbol ctermfg=3

    syntax match VDErrorFilePath /\v\t@<=.+$/ contained containedin=VDErrorItem
    highlight VDErrorFilePath ctermfg=black ctermbg=red
endif
