diff options
| author | Adam Stankiewicz <sheerun@sher.pl> | 2015-02-11 11:29:11 -0800 | 
|---|---|---|
| committer | Adam Stankiewicz <sheerun@sher.pl> | 2015-02-11 11:29:11 -0800 | 
| commit | 4541e98466b11376cddee5d7cd84c61a90d5d382 (patch) | |
| tree | 9182596e48c9b3d309495c3d94fa23c7151a916c /ftplugin | |
| parent | 6cd2d5417d728ea96c5c52b34629c944a89eec60 (diff) | |
| download | vim-polyglot-4541e98466b11376cddee5d7cd84c61a90d5d382.tar.gz vim-polyglot-4541e98466b11376cddee5d7cd84c61a90d5d382.zip | |
Remove CSV syntax (it is ugly and not useful)v1.12.0
Diffstat (limited to 'ftplugin')
| -rw-r--r-- | ftplugin/csv.vim | 2668 | 
1 files changed, 0 insertions, 2668 deletions
| diff --git a/ftplugin/csv.vim b/ftplugin/csv.vim deleted file mode 100644 index e7455cb1..00000000 --- a/ftplugin/csv.vim +++ /dev/null @@ -1,2668 +0,0 @@ -" Filetype plugin for editing CSV files. "{{{1 -" Author:  Christian Brabandt <cb@256bit.org> -" Version: 0.31 -" Script:  http://www.vim.org/scripts/script.php?script_id=2830 -" License: VIM License -" Last Change: Thu, 15 Jan 2015 21:05:10 +0100 -" Documentation: see :help ft-csv.txt -" GetLatestVimScripts: 2830 30 :AutoInstall: csv.vim -" -" Some ideas are taken from the wiki http://vim.wikia.com/wiki/VimTip667 -" though, implementation differs. - -" Plugin folklore "{{{2 -fu! <sid>DetermineSID() -    let s:SID = matchstr(expand('<sfile>'), '<SNR>\zs\d\+\ze_DetermineSID$') -endfu -call s:DetermineSID() -delf s:DetermineSID - -fu! CSVArrangeCol(first, last, bang, limit) range "{{{2 -    if &ft =~? 'csv' -        call <sid>ArrangeCol(a:first, a:last, a:bang, a:limit) -    else -        finish -    endif -endfu - -if v:version < 700 || exists('b:did_ftplugin') -  finish -endif -let b:did_ftplugin = 1 - -let s:cpo_save = &cpo -set cpo&vim - -" Function definitions: "{{{2 -" Script specific functions "{{{2 -fu! <sid>Warn(mess) "{{{3 -    echohl WarningMsg -    echomsg "CSV: " . a:mess -    echohl Normal -endfu - -fu! <sid>Init(startline, endline, ...) "{{{3 -    " if a:1 is set, keep the b:delimiter -    let keep = exists("a:1") && a:1 -    " Hilight Group for Columns -    if exists("g:csv_hiGroup") -        let s:hiGroup = g:csv_hiGroup -    else -        let s:hiGroup="WildMenu" -    endif -    if !exists("g:csv_hiHeader") -        let s:hiHeader = "Title" -    else -        let s:hiHeader = g:csv_hiHeader -    endif -    exe "hi link CSVHeaderLine" s:hiHeader - -    " Determine default Delimiter -    if !keep -        if !exists("g:csv_delim") -            let b:delimiter=<SID>GetDelimiter(a:startline, a:endline) -        else -            let b:delimiter=g:csv_delim -        endif -    endif - -    " Define custom commentstring -    if !exists("g:csv_comment") -        let b:csv_cmt = split(&cms, '%s') -    else -        let b:csv_cmt = split(g:csv_comment, '%s') -    endif - -    if empty(b:delimiter) && !exists("b:csv_fixed_width") -        call <SID>Warn("No delimiter found. See :h csv-delimiter to set it manually!") -        " Use a sane default as delimiter: -        let b:delimiter = ',' -    endif - -    let s:del='\%(' . b:delimiter . '\|$\)' -    let s:del_noend='\%(' . b:delimiter . '\)' -    " Pattern for matching a single column -    if !exists("g:csv_strict_columns") && !exists("g:csv_col") -        \ && !exists("b:csv_fixed_width") -        " - Allow double quotes as escaped quotes only insides double quotes -        " - Allow linebreaks only, if g:csv_nl isn't set (this is -        "   only allowed in double quoted strings see RFC4180), though this -        "   does not work with :WhatColumn and might mess up syntax -        "   highlighting. -        " - optionally allow whitespace in front of the fields (to make it -        "   work with :ArrangeCol (that is actually not RFC4180 valid)) -        " - Should work with most ugly solutions that are available -        let b:col='\%(\%(\%(' . (b:delimiter !~ '\s' ? '\s*' : '') . -                \ '"\%(' . (exists("g:csv_nl") ? '\_' : '' ) . -                \ '[^"]\|""\)*"\s*\)' . s:del . '\)\|\%(' . -                \  '[^' .  b:delimiter . ']*' . s:del . '\)\)' -        let b:col_end='\%(\%(\%(' . (b:delimiter !~ '\s' ? '\s*' : '') . -                \ '"\%(' . (exists("g:csv_nl") ? '\_' : '' ) . -                \ '[^"]\|""\)*"\)' . s:del_noend . '\)\|\%(' . -                \  '[^' .  b:delimiter . ']*' . s:del_noend . '\)\)' -    elseif !exists("g:csv_col") && exists("g:csv_strict_columns") -        " strict columns -        let b:col='\%([^' . b:delimiter . ']*' . s:del . '\)' -        let b:col_end='\%([^' . b:delimiter . ']*' . s:del_noend . '\)' -    elseif exists("b:csv_fixed_width") -        " Fixed width column -        let b:col='' -        " Check for sane default -        if b:csv_fixed_width =~? '[^0-9,]' -            call <sid>Warn("Please specify the list of character columns" . -                \ "like this: '1,3,5'. See also :h csv-fixedwidth") -            return -        endif -        let b:csv_fixed_width_cols=split(b:csv_fixed_width, ',') -        " Force evaluating as numbers -        call map(b:csv_fixed_width_cols, 'v:val+0') -    else -        " User given column definition -        let b:col = g:csv_col -        let b:col_noend = g:csv_col -    endif - -    " set filetype specific options -    call <sid>LocalSettings('all') - -    " define buffer-local commands -    call <SID>CommandDefinitions() - -    " Check Header line -    " Defines which line is considered to be a header line -    call <sid>CheckHeaderLine() - -    " CSV specific mappings -    call <SID>CSVMappings() - -    " force reloading CSV Syntax Highlighting -    if exists("b:current_syntax") -        unlet b:current_syntax -        " Force reloading syntax file -    endif -    call <sid>DoAutoCommands() -    " enable CSV Menu -    call <sid>Menu(1) -    call <sid>DisableFolding() -    silent do Syntax -    unlet! b:csv_start b:csv_end - -    " Remove configuration variables -    let b:undo_ftplugin .=  "| unlet! b:delimiter b:col" -        \ . "| unlet! b:csv_fixed_width_cols b:csv_filter" -        \ . "| unlet! b:csv_fixed_width b:csv_list b:col_width" -        \ . "| unlet! b:csv_SplitWindow b:csv_headerline b:csv_cmt" -        \ . "| unlet! b:csv_thousands_sep b:csv_decimal_sep" -        \. " | unlet! b:browsefilter b:csv_cmt" -        \. " | unlet! b:csv_arrange_leftalign" - - " Delete all functions - " disabled currently, because otherwise when switching ft - "          I think, all functions need to be read in again and this - "          costs time. - " - " let b:undo_ftplugin .= "| delf <sid>Warn | delf <sid>Init | - " \ delf <sid>GetPat | delf <sid>SearchColumn | delf <sid>DelColumn | - " \ delf <sid>HiCol | delf <sid>GetDelimiter | delf <sid>WColumn | - " \ delf <sid>MaxColumns | delf <sid>ColWidth | delf <sid>ArCol | - " \ delf <sid>PrepUnArCol | delf <sid>UnArCol | - " \ delf <sid>CalculateColumnWidth | delf <sid>Columnize | - " \ delf <sid>GetColPat | delf <sid>SplitHeaderLine | - " \ delf <sid>SplitHeaderToggle | delf <sid>MoveCol | - " \ delf <sid>SortComplete | delf <sid>SortList | delf <sid>Sort | - " \ delf CSV_WCol | delf <sid>CopyCol | delf <sid>MoveColumn | - " \ delf <sid>SumColumn csv#EvalColumn | delf <sid>DoForEachColumn | - " \ delf <sid>PrepareDoForEachColumn | delf <sid>CSVMappings | - " \ delf <sid>Map | delf <sid>EscapeValue | delf <sid>FoldValue | - " \ delf <sid>PrepareFolding | delf <sid>OutputFilters | - " \ delf <sid>SortFilter | delf <sid>GetColumn | - " \ delf <sid>RemoveLastItem | delf <sid>DisableFolding | - " \ delf <sid>CheckHeaderLine | - " \ delf <sid>AnalyzeColumn | delf <sid>Vertfold | - " \ delf <sid>InitCSVFixedWidth | delf <sid>LocalCmd | - " \ delf <sid>CommandDefinitions | delf <sid>NumberFormat | - " \ delf <sid>NewRecord | delf <sid>MoveOver | delf <sid>Menu | - " \ delf <sid>NewDelimiter | delf <sid>DuplicateRows | delf <sid>IN | - " \ delf <sid>SaveOptions | delf <sid>CheckDuplicates | - " \ delf <sid>CompleteColumnNr | delf <sid>CSVPat | delf <sid>Transpose | - " \ delf <sid>LocalSettings() | delf <sid>AddColumn | delf <sid>SubstituteInColumn - " \ delf <sid>SetupAutoCmd() | delf CSV_CloseBuffer -endfu - -fu! <sid>LocalSettings(type) "{{{3 -    if a:type == 'all' -        " CSV local settings -        setl nostartofline tw=0 nowrap - -        " undo when setting a new filetype -        let b:undo_ftplugin = "setlocal sol& tw< wrap<" - -        " Set browsefilter -        let b:browsefilter="CSV Files (*.csv, *.dat)\t*.csv;*.dat\n". -                 \ "All Files\t*.*\n" - -        if has("conceal") -            setl cole=2 cocu=nc -            let b:undo_ftplugin .= '| setl cole< cocu< ' -        endif - -    elseif a:type == 'fold' -        let s:fdt = &l:fdt -        let s:fcs = &l:fcs - -        if a:type == 'fold' -            " Be sure to also fold away single screen lines -            setl fen fdm=expr -            setl fdl=0 fml=0 fdc=2 -            if !get(g:, 'csv_disable_fdt',0) -                let &l:foldtext=strlen(v:folddashes) . ' lines hidden' -                let &fcs=substitute(&fcs, 'fold:.,', '', '') -                if !exists("b:csv_did_foldsettings") -                    let b:undo_ftplugin .= printf("|set fdt<|setl fcs=%s", escape(s:fcs, '\\| ')) -                endif -            endif -            if !exists("b:csv_did_foldsettings") -                let b:undo_ftplugin .= -                \ "| setl fen< fdm< fdl< fdc< fml< fde<" -                let b:csv_did_foldsettings = 1 -                let b:undo_ftplugin .= "| unlet! b:csv_did_foldsettings" -            endif -        endif -    endif -endfu - -fu! <sid>DoAutoCommands() "{{{3 -    " Highlight column, on which the cursor is? -    if exists("g:csv_highlight_column") && g:csv_highlight_column =~? 'y' && -        \ !exists("#CSV_HI#CursorMoved") -        aug CSV_HI -            au! -            au CursorMoved <buffer> HiColumn -        aug end -        " Set highlighting for column, on which the cursor is currently -        HiColumn -    elseif exists("#CSV_HI#CursorMoved") -        aug CSV_HI -            au! CursorMoved <buffer> -        aug end -        aug! CSV_HI -        " Remove any existing highlighting -        HiColumn! -    endif -    " undo autocommand: -    let b:undo_ftplugin .= '| exe "sil! au! CSV_HI CursorMoved <buffer> "' -    let b:undo_ftplugin .= '| exe "sil! aug! CSV_HI" |exe "sil! HiColumn!"' - -    if has("gui_running") && !exists("#CSV_Menu#FileType") -        augroup CSV_Menu -            au! -            au FileType * call <sid>Menu(&ft=='csv') -            au BufEnter <buffer> call <sid>Menu(1) " enable -            au BufLeave <buffer> call <sid>Menu(0) " disable -            au BufNewFile,BufNew * call <sid>Menu(0) -        augroup END -    endif -endfu - -fu! <sid>GetPat(colnr, maxcolnr, pat) "{{{3 -    if a:colnr > 1 && a:colnr < a:maxcolnr -        if !exists("b:csv_fixed_width_cols") -            return '^' . <SID>GetColPat(a:colnr-1,0) . '\%([^' . -                \ b:delimiter . ']\{-}\)\?\zs' . a:pat . '\ze' . -                \ '\%([^' . b:delimiter .']\{-}\)\?' . -                \ b:delimiter . <SID>GetColPat(a:maxcolnr - a:colnr, 0) . -                \ '$' -        else -            return '\%' . b:csv_fixed_width_cols[(a:colnr - 1)] . 'c\zs' -                \ . a:pat . '.\{-}\ze\%' -                \ . (b:csv_fixed_width_cols[a:colnr]) . 'c\ze' -        endif -    elseif a:colnr == a:maxcolnr -        if !exists("b:csv_fixed_width_cols") -            return '^' . <SID>GetColPat(a:colnr - 1,0) . -                \ '\%([^' . b:delimiter . -                \ ']\{-}\)\?\zs' . a:pat . '\ze' -        else -            return '\%' . b:csv_fixed_width_cols[-1] . -                \ 'c\zs' . a:pat . '\ze' -        endif -    else " colnr = 1 -        if !exists("b:csv_fixed_width_cols") -            return '^' . '\%([^' . b:delimiter . ']\{-}\)\?\zs' . a:pat . -            \ '\ze\%([^' . b:delimiter . ']*\)\?' . b:delimiter . -            \ <SID>GetColPat(a:maxcolnr -1 , 0) . '$' -        else -            return a:pat . '\ze.\{-}\%' . b:csv_fixed_width_cols[1] . 'c' -        endif -    endif -    return '' -endfu - -fu! <sid>SearchColumn(arg) "{{{3 -    try -        let arglist=split(a:arg) -        if len(arglist) == 1 -            let colnr=<SID>WColumn() -            let pat=substitute(arglist[0], '^\(.\)\(.*\)\1$', '\2', '') -            if pat == arglist[0] -                throw "E684" -            endif -        else -            " Determine whether the first word in the argument is a number -            " (of the column to search). -            let colnr = substitute( a:arg, '^\s*\(\d\+\)\s.*', '\1', '' ) -            " If it is _not_ a number, -            if colnr == a:arg -                " treat the whole argument as the pattern. -                let pat = substitute(a:arg, -                    \ '^\s*\(\S\)\(.*\)\1\s*$', '\2', '' ) -                if pat == a:arg -                    throw "E684" -                endif -                let colnr = <SID>WColumn() -            else -                " if the first word tells us the number of the column, -                " treat the rest of the argument as the pattern. -                let pat = substitute(a:arg, -                    \ '^\s*\d\+\s*\(\S\)\(.*\)\1\s*$', '\2', '' ) -                if pat == a:arg -                    throw "E684" -                endif -            endif -        endif -    "catch /^Vim\%((\a\+)\)\=:E684/ -    catch /E684/	" catch error index out of bounds -        call <SID>Warn("Error! Usage :SearchInColumn [<colnr>] /pattern/") -        return 1 -    endtry -    let maxcolnr = <SID>MaxColumns() -    if colnr > maxcolnr -        call <SID>Warn("There exists no column " . colnr) -        return 1 -    endif -    let @/ = <sid>GetPat(colnr, maxcolnr, '\%('.pat. '\)') -    try -        " force redraw, so that the search pattern isn't shown -        exe "norm! n\<c-l>" -    catch /^Vim\%((\a\+)\)\=:E486/ -        " Pattern not found -        echohl Error -        echomsg "E486: Pattern not found in column " . colnr . ": " . pat -        if &vbs > 0 -            echomsg substitute(v:exception, '^[^:]*:', '','') -        endif -        echohl Normal -    endtry -endfu - - -fu! <sid>DeleteColumn(arg) "{{{3 -    let _wsv = winsaveview() -    if a:arg =~ '^[/]' -        let i = 0 -        let pat = a:arg[1:] -        call cursor(1,1) -        while search(pat, 'cW') -            " Delete matching column -            sil call <sid>DelColumn('') -            let i+=1 -        endw -    else -        let i = 1 -        sil call <sid>DelColumn(a:arg) -    endif -    if i > 1 -        call <sid>Warn(printf("%d columns deleted", i)) -    else -        call <sid>Warn("1 column deleted") -    endif -    call winrestview(_wsv) -endfu - -fu! <sid>DelColumn(colnr) "{{{3 -    let maxcolnr = <SID>MaxColumns() -    let _p = getpos('.') - -    if empty(a:colnr) -       let colnr=<SID>WColumn() -    else -       let colnr=a:colnr -    endif - -    if colnr > maxcolnr -        call <SID>Warn("There exists no column " . colnr) -        return -    endif - -    if colnr != '1' -        if !exists("b:csv_fixed_width_cols") -            let pat= '^' . <SID>GetColPat(colnr-1,1) . b:col -        else -            let pat= <SID>GetColPat(colnr,0) -        endif -    else -        " distinction between csv and fixed width does not matter here -        let pat= '^' . <SID>GetColPat(colnr,0) -    endif -    if &ro -        let ro = 1 -        setl noro -    else -        let ro = 0 -    endif -    exe ':%s/' . escape(pat, '/') . '//' -    call setpos('.', _p) -    if ro -        setl ro -    endif -endfu - -fu! <sid>HiCol(colnr, bang) "{{{3 -    if a:colnr > <SID>MaxColumns() && !a:bang -        call <SID>Warn("There exists no column " . a:colnr) -        return -    endif -    if !a:bang -        if empty(a:colnr) -            let colnr=<SID>WColumn() -        else -            let colnr=a:colnr -        endif - -        if colnr==1 -            let pat='^'. <SID>GetColPat(colnr,0) -        elseif !exists("b:csv_fixed_width_cols") -            let pat='^'. <SID>GetColPat(colnr-1,1) . b:col -        else -            let pat=<SID>GetColPat(colnr,0) -        endif -    endif - -    if exists("*matchadd") -        if exists("s:matchid") -            " ignore errors, that come from already deleted matches -            sil! call matchdelete(s:matchid) -        endif -        " Additionally, filter all matches, that could have been used earlier -        let matchlist=getmatches() -        call filter(matchlist, 'v:val["group"] !~ s:hiGroup') -        call setmatches(matchlist) -        if a:bang -            return -        endif -        let s:matchid=matchadd(s:hiGroup, pat, 0) -    elseif !a:bang -        exe ":2match " . s:hiGroup . ' /' . pat . '/' -    endif -endfu - -fu! <sid>GetDelimiter(first, last) "{{{3 -    if !exists("b:csv_fixed_width_cols") -        let _cur = getpos('.') -        let _s   = @/ -        let Delim= {0: ';', 1:  ',', 2: '|', 3: '	', 4: '\^'} -        let temp = {} -        " :silent :s does not work with lazyredraw -        let _lz  = &lz -        set nolz -        for i in  values(Delim) -            redir => temp[i] -            exe "silent! ". a:first. ",". a:last. "s/" . i . "/&/nge" -            redir END -        endfor -        let &lz = _lz -        let Delim = map(temp, 'matchstr(substitute(v:val, "\n", "", ""), "^\\d\\+")') -        let Delim = filter(temp, 'v:val=~''\d''') -        let max   = max(values(temp)) - -        let result=[] -        call setpos('.', _cur) -        let @/ = _s -        for [key, value] in items(Delim) -            if value == max -                return key -            endif -        endfor -        return '' -    else -        " There is no delimiter for fixedwidth files -        return '' -    endif -endfu - -fu! <sid>WColumn(...) "{{{3 -    " Return on which column the cursor is -    let _cur = getpos('.') -    if !exists("b:csv_fixed_width_cols") -        if line('.') > 1 && mode('') != 'n' -            " in insert mode, get line from above, just in case the current -            " line is empty -            let line = getline(line('.')-1) -        else -            let line=getline('.') -        endif -        " move cursor to end of field -        "call search(b:col, 'ec', line('.')) -        call search(b:col, 'ec') -        let end=col('.')-1 -        let fields=(split(line[0:end],b:col.'\zs')) -        let ret=len(fields) -        if exists("a:1") && a:1 > 0 -            " bang attribute: Try to get the column name -            let head  = split(getline(1),b:col.'\zs') -            " remove preceeding whitespace -            if len(head) < ret -                call <sid>Warn("Header has no field ". ret) -            else -                let ret   = substitute(head[ret-1], '^\s\+', '', '') -                " remove delimiter -                let ret   = substitute(ret, b:delimiter. '$', '', '') -            endif -        endif -    else -        let temp=getpos('.')[2] -        let j=1 -        let ret = 1 -        for i in sort(b:csv_fixed_width_cols, "<sid>SortList") -            if temp >= i -                let ret = j -            endif -            let j += 1 -        endfor -    endif -    call setpos('.',_cur) -    return ret -endfu - -fu! <sid>MaxColumns(...) "{{{3 -    if exists("a:0") && a:0 == 1 -        let this_col = 1 -    else -        let this_col = 0 -    endif -    "return maximum number of columns in first 10 lines -    if !exists("b:csv_fixed_width_cols") -        if this_col -            let i = a:1 -        else -            let i = 1 -        endif -        while 1 -            let l = getline(i, i+10) - -            " Filter comments out -            let pat = '^\s*\V'. escape(b:csv_cmt[0], '\\') -            call filter(l, 'v:val !~ pat') -            if !empty(l) || this_col -                break -            else -                let i+=10 -            endif -        endw - -        if empty(l) -            throw 'csv:no_col' -        endif -        let fields=[] -        let result=0 -        for item in l -            let temp=len(split(item, b:col.'\zs')) -            let result=(temp>result ? temp : result) -        endfor -        return result -    else -        return len(b:csv_fixed_width_cols) -    endif -endfu - -fu! <sid>ColWidth(colnr) "{{{3 -    " Return the width of a column -    " Internal function -    let width=20 "Fallback (wild guess) -    let tlist=[] - -    if !exists("b:csv_fixed_width_cols") -        if !exists("b:csv_list") -            " only check first 10000 lines, to be faster -            let last = line('$') -            if !get(b:, 'csv_arrange_use_all_rows', 0) -                if last > 10000 -                    let last = 10000 -                    call <sid>Warn('File too large, only checking the first 10000 rows for the width') -                endif -            endif -            let b:csv_list=getline(1,last) -            let pat = '^\s*\V'. escape(b:csv_cmt[0], '\\') -            call filter(b:csv_list, 'v:val !~ pat') -            call filter(b:csv_list, '!empty(v:val)') -            call map(b:csv_list, 'split(v:val, b:col.''\zs'')') -        endif -        try -            for item in b:csv_list -                call add(tlist, item[a:colnr-1]) -            endfor -            " we have a list of the first 10 rows -            " Now transform it to a list of field a:colnr -            " and then return the maximum strlen -            " That could be done in 1 line, but that would look ugly -            "call map(list, 'split(v:val, b:col."\\zs")[a:colnr-1]') -            call map(tlist, 'substitute(v:val, ".", "x", "g")') -            call map(tlist, 'strlen(v:val)') -            return max(tlist) -        catch -            throw "ColWidth-error" -            return width -        endtry -    else -        let cols = len(b:csv_fixed_width_cols) -        if a:colnr == cols -            return strlen(substitute(getline('$'), '.', 'x', 'g')) - -                \ b:csv_fixed_width_cols[cols-1] + 1 -        elseif a:colnr < cols && a:colnr > 0 -            return b:csv_fixed_width_cols[a:colnr] - -                \ b:csv_fixed_width_cols[(a:colnr - 1)] -        else -            throw "ColWidth-error" -            return 0 -        endif -    endif -endfu - -fu! <sid>ArrangeCol(first, last, bang, limit) range "{{{3 -    " explicitly give the range as argument to the function -    if exists("b:csv_fixed_width_cols") -        " Nothing to do -        call <sid>Warn("ArrangeColumn does not work with fixed width column!") -        return -    endif -    let cur=winsaveview() -    if a:bang -        if a:bang -            " Force recalculating the Column width -            unlet! b:csv_list b:col_width -        endif -    elseif a:limit > -1 && a:limit < getfsize(fnamemodify(bufname(''), ':p')) -        return -    endif - -    if !exists("b:col_width") -        " Force recalculation of Column width -        call <sid>CalculateColumnWidth() -    endif - -    if &ro -       " Just in case, to prevent the Warning -       " Warning: W10: Changing read-only file -       let ro = 1 -       setl noro -    else -       let ro = 0 -    endif -    let s:count = 0 -    let _stl  = &stl -    let s:max   = (a:last - a:first + 1) * len(b:col_width) -    let s:temp  = 0 -    try -        exe "sil". a:first . ',' . a:last .'s/' . (b:col) . -        \ '/\=<SID>Columnize(submatch(0))/' . (&gd ? '' : 'g') -    finally -        " Clean up variables, that were only needed for <sid>Columnize() function -        unlet! s:columnize_count s:max_cols s:prev_line s:max s:count s:temp s:val -        if ro -            setl ro -            unlet ro -        endif -        let &stl = _stl -        call winrestview(cur) -    endtry -endfu - -fu! <sid>ProgressBar(cnt, max) "{{{3 -    if get(g:, 'csv_no_progress', 0) -        return -    endif -    let width = 40 " max width of progressbar -    if width > &columns -        let width = &columns -    endif -    let s:val = a:cnt * width / a:max -    if (s:val > s:temp || a:cnt==1) -        let &stl='%#DiffAdd#['.repeat('=', s:val).'>'. repeat(' ', width-s:val).']'. -                \ (width < &columns  ? ' '.100*s:val/width. '%%' : '') -        redrawstatus -        let s:temp = s:val -    endif -endfu - -fu! <sid>PrepUnArrangeCol(first, last) "{{{3 -    " Because of the way, Vim works with -    " a:firstline and a:lastline parameter, -    " explicitly give the range as argument to the function -    if exists("b:csv_fixed_width_cols") -        " Nothing to do -        call <sid>Warn("UnArrangeColumn does not work with fixed width column!") -        return -    endif -    let cur=winsaveview() - -    if &ro -       " Just in case, to prevent the Warning -       " Warning: W10: Changing read-only file -       setl noro -    endif -    exe a:first . ',' . a:last .'s/' . (b:col) . -    \ '/\=<SID>UnArrangeCol(submatch(0))/' . (&gd ? '' : 'g') -    " Clean up variables, that were only needed for <sid>Columnize() function -    call winrestview(cur) -endfu - -fu! <sid>UnArrangeCol(match) "{{{3 -    " Strip leading white space, also trims empty records: -    if get(b:, 'csv_arrange_leftalign',0) -        return substitute(a:match, '\s\+\ze'. b:delimiter. '\?$', '', '') -    else -        return substitute(a:match, '^\s\+', '', '') -    endif -    " only strip leading white space, if a non-white space follows: -    "return substitute(a:match, '^\s\+\ze\S', '', '') -endfu - -fu! <sid>CalculateColumnWidth() "{{{3 -    " Internal function, not called from external, -    " does not work with fixed width columns -    let b:col_width=[] -    try -        let s:max_cols=<SID>MaxColumns(line('.')) -        for i in range(1,s:max_cols) -            call add(b:col_width, <SID>ColWidth(i)) -        endfor -    catch /csv:no_col/ -        call <sid>Warn("Error: getting Column numbers, aborting!") -    catch /ColWidth/ -        call <sid>Warn("Error: getting Column Width, using default!") -    endtry -    " delete buffer content in variable b:csv_list, -    " this was only necessary for calculating the max width -    unlet! b:csv_list s:columnize_count s:decimal_column -endfu - -fu! <sid>Columnize(field) "{{{3 -    " Internal function, not called from external, -    " does not work with fixed width columns -    if !exists("s:columnize_count") -        let s:columnize_count = 0 -    endif - -    if !exists("s:max_cols") -        let s:max_cols = len(b:col_width) -    endif - -    if exists("s:prev_line") && s:prev_line != line('.') -        let s:columnize_count = 0 -    endif -    let s:count+=1 - -    let s:prev_line = line('.') -    " convert zero based indexed list to 1 based indexed list, -    " Default: 20 width, in case that column width isn't defined -    " Careful: Keep this fast! Using -    " let width=get(b:col_width,<SID>WColumn()-1,20) -    " is too slow, so we are using: -    let colnr = s:columnize_count % s:max_cols -    let width = get(b:col_width, colnr, 20) -    let align = 'r' -    if exists('b:csv_arrange_align') -        let align_list=split(get(b:, 'csv_arrange_align', " "), '\zs') -        try -            let align = align_list[colnr] -        catch -            let align = 'r' -        endtry -    endif -    if ((align isnot? 'r' && align isnot? 'l' && -       \ align isnot? 'c' && align isnot? '.') || get(b:, 'csv_arrange_leftalign', 0)) -       let align = 'r' -    endif -    call <sid>ProgressBar(s:count,s:max) - -    let s:columnize_count += 1 -    let has_delimiter = (a:field[-1:] is? b:delimiter) -    if align is? 'l' -        " left-align content -        return printf("%-*S%s", width+1 ,  -            \ (has_delimiter ? a:field[:-2] : a:field), -            \ (has_delimiter ? b:delimiter : ' ')) -    elseif align is? 'c' -        " center the column -        let t = width - len(split(a:field, '\zs')) -        let leftwidth = t/2 -        " uneven width, add one -        let rightwidth = (t%2 ? leftwidth+1 : leftwidth) -        let field = (has_delimiter ?  a:field[:-2] : a:field).  repeat(' ', rightwidth) -        return printf("%*S%s", width , field, (has_delimiter ? b:delimiter : ' ')) -    elseif align is? '.' -        if !exists("s:decimal_column") -            let s:decimal_column = {} -        endif -        if get(s:decimal_column, colnr, 0) == 0 -            call <sid>CheckHeaderLine() -            call <sid>NumberFormat() -            let data = <sid>CopyCol('', colnr+1, '')[s:csv_fold_headerline : -1] -            let pat1 = escape(s:nr_format[1], '.').'\zs[^'.s:nr_format[1].']*\ze'. -                        \ (has_delimiter ? b:delimiter : '').'$' -            let pat2 = '\d\+\ze\%(\%('.escape(s:nr_format[1], '.'). '\d\+\)\|'. -                        \ (has_delimiter ? b:delimiter : '').'$\)' -            let data1 = map(copy(data), 'matchstr(v:val, pat1)') -            let data2 = map(data, 'matchstr(v:val, pat2)') -            " strlen should be okay for decimals... -            let data1 = map(data1, 'strlen(v:val)') -            let data2 = map(data2, 'strlen(v:val)') -            let dec = max(data1) -            let scal = max(data2) -            if dec + scal + 1 + (has_delimiter ? 1 : 0) > width -                let width = dec + scal + 1 + (has_delimiter ? 1 :0) -                let b:col_width[colnr] = width -            endif - -            let s:decimal_column[colnr] = dec -        else -            let dec = get(s:decimal_column, colnr) -        endif -        let field = (has_delimiter ?  a:field[:-2] : a:field) -        let fmt = printf("%%%d.%df", width+1, dec) -        try -            if s:nr_format[1] isnot '.' -                let field = substitute(field, s:nr_format[1], '.', 'g') -                let field = substitute(field, s:nr_format[0], '', 'g') -            endif -            if field =~? '\h' " text in the column, can't be converted to float -                throw "no decimal" -            endif -            let result = printf(fmt, str2float(field)). (has_delimiter ? b:delimiter : ' ') -        catch -            let result = printf("%*S", width+2, a:field) -        endtry -        return result -    else -        " right align -        return printf("%*S", width+1 ,  a:field) -    endif -endfun - -fu! <sid>GetColPat(colnr, zs_flag) "{{{3 -    " Return Pattern for given column -    if a:colnr > 1 -        if !exists("b:csv_fixed_width_cols") -            let pat=b:col . '\{' . (a:colnr) . '\}' -        else -            if a:colnr >= len(b:csv_fixed_width_cols) -            " Get last column -                let pat='\%' . b:csv_fixed_width_cols[-1] . 'v.*' -            else -            let pat='\%' . b:csv_fixed_width_cols[(a:colnr - 1)] . -            \ 'c.\{-}\%' .   b:csv_fixed_width_cols[a:colnr] . 'v' -            endif -        endif -    elseif !exists("b:csv_fixed_width_cols") -        let pat=b:col -    else -        let pat='\%' . b:csv_fixed_width_cols[0] . 'v.\{-}' . -            \ (len(b:csv_fixed_width_cols) > 1 ? -            \ '\%' . b:csv_fixed_width_cols[1] . 'v' : -            \ '') -    endif -    return pat . (a:zs_flag ? '\zs' : '') -endfu - -fu! <sid>SetupAutoCmd(window,bufnr) "{{{3 -    " Setup QuitPre autocommand to quit cleanly -    aug CSV_QuitPre -        au! -        exe "au QuitPre * call CSV_CloseBuffer(".winbufnr(a:window).")" -        exe "au CursorHold <buffer=".a:bufnr."> call CSV_SetSplitOptions(".a:window.")" -    aug END -endfu - -fu! <sid>SplitHeaderLine(lines, bang, hor) "{{{3 -    if exists("b:csv_fixed_width_cols") -        call <sid>Warn("Header does not work with fixed width column!") -        return -    endif -    " Check that there exists a header line -    call <sid>CheckHeaderLine() -    if !a:bang -        " A Split Header Window already exists, -        " first close the already existing Window -        if exists("b:csv_SplitWindow") -            call <sid>SplitHeaderLine(a:lines, 1, a:hor) -        endif -        " Split Window -        let _stl = &l:stl -        let _sbo = &sbo -        let a = [] -        let b=b:col -        let bufnr = bufnr('.') -        if a:hor -            setl scrollopt=hor scrollbind cursorbind -            let _fdc = &l:fdc -            let lines = empty(a:lines) ? s:csv_fold_headerline : a:lines -            let a = getline(1,lines) -            " Does it make sense to use the preview window? -            " sil! pedit % -            above sp +enew -            call setline(1, a) -            " Needed for syntax highlighting -            "let b:col=b -            "setl syntax=csv -            sil! doautocmd FileType csv -            noa 1 -            sil! sign unplace * -            exe "resize" . lines -            setl scrollopt=hor winfixheight nowrap cursorbind -            let &l:stl="%#Normal#".repeat(' ',winwidth(0)) -            let s:local_stl = &l:stl -            " set the foldcolumn to the same of the other window -            let &l:fdc = _fdc -        else -            setl scrollopt=ver scrollbind cursorbind -            noa 0 -            if a:lines[-1:] is? '!' -                let a=<sid>CopyCol('',a:lines,'') -            else -                let a=<sid>CopyCol('',1, a:lines-1) -            endif -            " Does it make sense to use the preview window? -            "vert sil! pedit |wincmd w | enew! -            above vsp +enew -            call append(0, a) -            $d _ -            let b:col = b -            sil! doautocmd FileType csv -            " remove leading delimiter -            exe "sil :%s/^". b:delimiter. "//e" -            " remove trailing delimiter -            exe "sil :%s/". b:delimiter. "\s*$//e" -            syn clear -            noa 0 -            let b:csv_SplitWindow = winnr() -            sil :call <sid>ArrangeCol(1,line('$'), 1, -1) -            sil! sign unplace * -            exe "vert res" . len(split(getline(1), '\zs')) -            call matchadd("CSVHeaderLine", b:col) -            setl scrollopt=ver winfixwidth cursorbind nonu nornu fdc=0 -        endif -        call <sid>SetupAutoCmd(winnr(),bufnr) -        " disable airline -        let w:airline_disabled = 1 -        let win = winnr() -        setl scrollbind buftype=nowrite bufhidden=wipe noswapfile nobuflisted -        noa wincmd p -        let b:csv_SplitWindow = win -        aug CSV_Preview -            au! -            au BufWinLeave <buffer> call <sid>SplitHeaderLine(0, 1, 0) -        aug END -    else -        " Close split window -        if !exists("b:csv_SplitWindow") -            return -        endif -        exe b:csv_SplitWindow . "wincmd w" -        if exists("_stl") -            let &l:stl = _stl -        endif -        if exists("_sbo") -            let &sbo = _sbo -        endif -        setl noscrollbind nocursorbind -        try -            noa wincmd c -        catch /^Vim\%((\a\+)\)\=:E444/	" cannot close last window -        catch /^Vim\%((\a\+)\)\=:E517/	" buffer already wiped -            " no-op -        endtry -        "pclose! -        unlet! b:csv_SplitWindow -        aug CSV_Preview -            au! -        aug END -        aug! CSV_Preview -    endif -endfu - -fu! <sid>SplitHeaderToggle(hor) "{{{3 -    if !exists("b:csv_SplitWindow") -        :call <sid>SplitHeaderLine(1,0,a:hor) -    else -        :call <sid>SplitHeaderLine(1,1,a:hor) -    endif -endfu - -" TODO: from here on add logic for fixed-width csv files! -fu! <sid>MoveCol(forward, line, ...) "{{{3 -    " Move cursor position upwards/downwards left/right -    " a:1 is there to have some mappings move in the same -    " direction but still stop at a different position -    " see :h csv-mapping-H -    let colnr=<SID>WColumn() -    let maxcol=<SID>MaxColumns() -    let cpos=getpos('.')[2] -    if !exists("b:csv_fixed_width_cols") -        call search(b:col, 'bc', line('.')) -    endif -    let spos=getpos('.')[2] - -    " Check for valid column -    " a:forward == 1 : search next col -    " a:forward == -1: search prev col -    " a:forward == 0 : stay in col -    if colnr - v:count1 >= 1 && a:forward == -1 -        let colnr -= v:count1 -    elseif colnr - v:count1 < 1 && a:forward == -1 -        let colnr = 0 -    elseif colnr + v:count1 <= maxcol && a:forward == 1 -        let colnr += v:count1 -    elseif colnr + v:count1 > maxcol && a:forward == 1 -        let colnr = maxcol + 1 -    endif - -    let line=a:line -    if line < 1 -        let line=1 -    elseif line > line('$') -        let line=line('$') -    endif -    if foldclosed(line) != -1 -        let line = line > line('.') ? foldclosedend(line) : foldclosed(line) -    endif - -    " Generate search pattern -    if colnr == 1 -        let pat = '^' . <SID>GetColPat(colnr-1,0) -        "let pat = pat . '\%' . line . 'l' -    elseif (colnr == 0) || (colnr == maxcol + 1) -        if !exists("b:csv_fixed_width_cols") -            let pat=b:col -        else -            if a:forward > 0 -                " Move forwards -                let pat=<sid>GetColPat(1, 0) -            else -                " Move backwards -                let pat=<sid>GetColPat(maxcol, 0) -            endif -        endif -    else -        if !exists("b:csv_fixed_width_cols") -            let pat='^'. <SID>GetColPat(colnr-1,1) . b:col -        else -            let pat=<SID>GetColPat(colnr,0) -        endif -        "let pat = pat . '\%' . line . 'l' -    endif - -    " Search -    " move left/right -    if a:forward > 0 -        call search(pat, 'W') -    elseif a:forward < 0 -        if colnr > 0 || cpos == spos -            call search('.\ze'.pat, 'bWe') -            let stime=localtime() -            while getpos('.')[2] == cpos && <sid>Timeout(stime) " make sure loop terminates -                " cursor didn't move, move cursor one cell to the left -                norm! h -                if colnr > 0 -                    call <sid>MoveCol(-1, line('.')) -                else -                    norm! 0 -                endif -            endw -            if (exists("a:1") && a:1) -                " H also stops at the beginning of the content -                " of a field. -                let epos = getpos('.') -                if getline('.')[col('.')-1] == ' ' -                    call search('\S', 'W', line('.')) -                    if getpos('.')[2] > spos -                        call setpos('.', epos) -                    endif -                endif -            endif -        else -            norm! 0 -        endif -        " Moving upwards/downwards -    elseif line >= line('.') -        call search(pat . '\%' . line . 'l', '', line) -        " Move to the correct screen column -        " This is a best effort approach, we might still -        " leave the column (if the next column is shorter) -        if !exists("b:csv_fixed_width_cols") -            let a    = getpos('.') -            let a[2]+= cpos-spos -        else -            let a    = getpos('.') -            let a[2] = cpos -        endif -        call setpos('.', a) -    elseif line < line('.') -        call search(pat . '\%' . line . 'l', 'b', line) -        " Move to the correct screen column -        if !exists("b:csv_fixed_width_cols") -            let a    = getpos('.') -            let a[2]+= cpos-spos -        else -            let a    = getpos('.') -            let a[2] = cpos -        endif -        call setpos('.', a) -    endif -endfun - -fu! <sid>SortComplete(A,L,P) "{{{3 -    return join(range(1,<sid>MaxColumns()),"\n") -endfun - -fu! <sid>SortList(a1, a2) "{{{3 -    return a:a1+0 == a:a2+0 ? 0 : a:a1+0 > a:a2+0 ? 1 : -1 -endfu - -fu! <sid>Sort(bang, line1, line2, colnr) range "{{{3 -    let wsv=winsaveview() -    if a:colnr =~? 'n' -        let numeric = 1 -    else -        let numeric = 0 -    endif -    let col = (empty(a:colnr) || a:colnr !~? '\d\+') ? <sid>WColumn() : a:colnr+0 -    if col != 1 -        if !exists("b:csv_fixed_width_cols") -            let pat= '^' . <SID>GetColPat(col-1,1) . b:col -        else -            let pat= <SID>GetColPat(col,0) -        endif -    else -        let pat= '^' . <SID>GetColPat(col,0) -    endif -    exe a:line1. ','. a:line2. "sort". (a:bang ? '!' : '') . -        \' r ' . (numeric ? 'n' : '') . ' /' . pat . '/' -    call winrestview(wsv) -endfun - -fu! <sid>CopyCol(reg, col, cnt) "{{{3 -    " Return Specified Column into register reg -    let col = a:col == "0" ? <sid>WColumn() : a:col+0 -    let mcol = <sid>MaxColumns() -    if col == '$' || col > mcol -        let col = mcol -    endif -    " The number of columns to return -    " by default (value of zero, will only return that specific column) -    let cnt_cols = col - 1 -    if !empty(a:cnt) && a:cnt > 0 && col + a:cnt <= mcol -        let cnt_cols = col + a:cnt - 1 -    endif -    let a = [] -    " Don't get lines, that are currently filtered away -    if !exists("b:csv_filter") || empty(b:csv_filter) -        let a=getline(1, '$') -    else -        for line in range(1, line('$')) -            if foldlevel(line) -                continue -            else -                call add(a, getline(line)) -            endif -        endfor -    endif -    " Filter comments out -    let pat = '^\s*\V'. escape(b:csv_cmt[0], '\\') -    call filter(a, 'v:val !~ pat') - -    if !exists("b:csv_fixed_width_cols") -        call map(a, 'split(v:val, ''^'' . b:col . ''\zs'')[col-1:cnt_cols]') -    else -        call map(a, 'matchstr(v:val, <sid>GetColPat(col, 0)).*<sid>GetColPat(col+cnt_cols, 0)') -    endif -    if type(a[0]) == type([]) -        call map(a, 'join(v:val, "")') -    endif -    if a:reg =~ '[-"0-9a-zA-Z*+]' -        "exe  ':let @' . a:reg . ' = "' . join(a, "\n") . '"' -        " set the register to blockwise mode -        call setreg(a:reg, join(a, "\n"), 'b') -    else -        return a -    endif -endfu - -fu! <sid>MoveColumn(start, stop, ...) range "{{{3 -    " Move column behind dest -    " Explicitly give the range as argument, -    " cause otherwise, Vim would move the cursor -    let wsv = winsaveview() - -    let col = <sid>WColumn() -    let max = <sid>MaxColumns() - -    " If no argument is given, move current column after last column -    let source=(exists("a:1") && a:1 > 0 && a:1 <= max ? a:1 : col) -    let dest  =(exists("a:2") && a:2 > 0 && a:2 <= max ? a:2 : max) - -    " translate 1 based columns into zero based list index -    let source -= 1 -    let dest   -= 1 - -    if source >= dest -        call <sid>Warn("Destination column before source column, aborting!") -        return -    endif - -    " Swap line by line, instead of reading the whole range into memory - -    for i in range(a:start, a:stop) -        let content = getline(i) -        if content =~ '^\s*\V'. escape(b:csv_cmt[0], '\\') -            " skip comments -            continue -        endif -        if !exists("b:csv_fixed_width_cols") -            let fields=split(content, b:col . '\zs') -            " Add delimiter to destination column, in case there was none, -            " remove delimiter from source, in case destination did not have one -            if matchstr(fields[dest], '.$') !~? b:delimiter -                let fields[dest] = fields[dest] . b:delimiter -                if matchstr(fields[source], '.$') =~? b:delimiter -                let fields[source] = substitute(fields[source], -                    \ '^\(.*\).$', '\1', '') -                endif -            endif -        else -            let fields=[] -            " this is very inefficient! -            for j in range(1, max, 1) -                call add(fields, matchstr(content, <sid>GetColPat(j,0))) -            endfor -        endif - -        let fields= (source == 0 ? [] : fields[0 : (source-1)]) -                \ + fields[ (source+1) : dest ] -                \ + [ fields[source] ] + fields[(dest+1):] - -        call setline(i, join(fields, '')) -    endfor - -    call winrestview(wsv) - -endfu - -fu! <sid>AddColumn(start, stop, ...) range "{{{3 -    " Add new empty column -    " Explicitly give the range as argument, -    " cause otherwise, Vim would move the cursor -    if exists("b:csv_fixed_width_cols") -        call <sid>Warn("Adding Columns only works for delimited files") -        return -    endif - -    let wsv = winsaveview() - -    let col = <sid>WColumn() -    let max = <sid>MaxColumns() - -    " If no argument is given, add column after current column -    if exists("a:1") -        if a:1 == '$' || a:1 >= max -            let pos = max -        elseif a:1 < 0 -            let pos = col -        else -            let pos = a:1 -        endif -    else -        let pos = col -    endif -    let cnt=(exists("a:2") && a:2 > 0 ? a:2 : 1) - -    " translate 1 based columns into zero based list index -    "let pos -= 1 -    let col -= 1 - -    if pos == 0 -        let pat = '^' -    elseif pos == max-1 -        let pat = '$' -    else -        let pat = <sid>GetColPat(pos,1) -    endif - -    if pat != '$' || (pat == '$' &&  getline(a:stop)[-1:] == b:delimiter) -        let subst = repeat(' '. b:delimiter, cnt) -    else -        let subst = repeat(b:delimiter. ' ', cnt) -    endif - -    " if the data contains comments, substitute one line after another -    " skipping comment lines (we could do it with a single :s statement, -    " but that would fail for the first and last column. - -    let commentpat = '\%(\%>'.(a:start-1).'l\V'. -                \ escape(b:csv_cmt[0], '\\').'\m\)'. '\&\%(\%<'. -                \ (a:stop+1). 'l\V'. escape(b:csv_cmt[0], '\\'). '\m\)' -    if search(commentpat) -        for i in range(a:start, a:stop) -            let content = getline(i) -            if content =~ '^\s*\V'. escape(b:csv_cmt[0], '\\') -                " skip comments -                continue -            endif -            exe printf("sil %ds/%s/%s/e", i, pat, subst) -        endfor -    else -        " comments should by default be skipped (pattern shouldn't match) -        exe printf("sil %d,%ds/%s/%s/e", a:start, a:stop, pat, subst) -    endif - -    call winrestview(wsv) -endfu - -fu! <sid>SumColumn(list) "{{{3 -    " Sum a list of values, but only consider the digits within each value -    " parses the digits according to the given format (if none has been -    " specified, assume POSIX format (without thousand separator) If Vim has -    " does not support floats, simply sum up only the integer part -    if empty(a:list) -        return 0 -    else -        let sum = has("float") ? 0.0 : 0 -        for item in a:list -            if empty(item) -                continue -            endif -            let nr = matchstr(item, '-\?\d\(.*\d\)\?$') -            let format1 = '^-\?\d\+\zs\V' . s:nr_format[0] . '\m\ze\d' -            let format2 = '\d\+\zs\V' . s:nr_format[1] . '\m\ze\d' -            try -                let nr = substitute(nr, format1, '', '') -                if has("float") && s:nr_format[1] != '.' -                    let nr = substitute(nr, format2, '.', '') -                endif -            catch -                let nr = 0 -            endtry -            let sum += (has("float") ? str2float(nr) : (nr + 0)) -        endfor -        if has("float") -            if float2nr(sum) == sum -                return float2nr(sum) -            else -                return printf("%.2f", sum) -            endif -        endif -        return sum -    endif -endfu - -fu! <sid>DoForEachColumn(start, stop, bang) range "{{{3 -    " Do something for each column, -    " e.g. generate SQL-Statements, convert to HTML, -    " something like this -    " TODO: Define the function -    " needs a csv_pre_convert variable -    "         csv_post_convert variable -    "         csv_convert variable -    "         result contains converted buffer content -    let result = [] - -    if !exists("g:csv_convert") -        call <sid>Warn("You need to define how to convert your data using" . -                \ "the g:csv_convert variable, see :h csv-convert") -        return -    endif - -    if exists("g:csv_pre_convert") && !empty(g:csv_pre_convert) -        call add(result, g:csv_pre_convert) -    endif - -    for item in range(a:start, a:stop, 1) -        let t = g:csv_convert -        let line = getline(item) -        if line =~ '^\s*\V'. escape(b:csv_cmt[0], '\\') -            " Filter comments out -            call add(result, line) -            continue -        endif -        let context = split(g:csv_convert, '%s') -        let columns = len(context) -        if columns > <sid>MaxColumns() -            let columns = <sid>MaxColumns() -        elseif columns == 1 -            call <sid>Warn("No Columns defined in your g:csv_convert variable, Aborting") -            return -        endif - -        if !exists("b:csv_fixed_width_cols") -            let fields=split(line, b:col . '\zs') -            if a:bang -                call map(fields, 'substitute(v:val, b:delimiter . -                    \ ''\?$'' , "", "")') -            endif -        else -            let fields=[] -            for j in range(1, columns, 1) -                call add(fields, matchstr(line, <sid>GetColPat(j,0))) -            endfor -        endif -        for j in range(1, columns, 1) -            let t=substitute(t, '%s', fields[j-1], '') -        endfor -        call add(result, t) -    endfor - -    if exists("g:csv_post_convert") && !empty(g:csv_post_convert) -        call add(result, g:csv_post_convert) -    endif - -    new -    call append('$', result) -    1d _ - -endfun - -fu! <sid>PrepareDoForEachColumn(start, stop, bang) range"{{{3 -    let pre = exists("g:csv_pre_convert") ? g:csv_pre_convert : '' -    let g:csv_pre_convert=input('Pre convert text: ', pre) -    let post = exists("g:csv_post_convert") ? g:csv_post_convert : '' -    let g:csv_post_convert=input('Post convert text: ', post) -    let convert = exists("g:csv_convert") ? g:csv_convert : '' -    let g:csv_convert=input("Converted text, use %s for column input:\n", convert) -    call <sid>DoForEachColumn(a:start, a:stop, a:bang) -endfun -fu! <sid>EscapeValue(val) "{{{3 -    return '\V' . escape(a:val, '\') -endfu - -fu! <sid>FoldValue(lnum, filter) "{{{3 -    call <sid>CheckHeaderLine() - -    if (a:lnum == s:csv_fold_headerline) -        " Don't fold away the header line -        return 0 -    endif -    let result = 0 - -    for item in values(a:filter) -        " always fold comments away -        let content = getline(a:lnum) -        if content =~ '^\s*\V'. escape(b:csv_cmt[0], '\\') -            return 1 -        elseif eval('content' .  (item.match ? '!~' : '=~') . 'item.pat') -            let result += 1 -        endif -    endfor -    return (result > 0) -endfu - -fu! <sid>PrepareFolding(add, match)  "{{{3 -    if !has("folding") -        return -    endif - -    " Move folded-parts away? -    if exists("g:csv_move_folds") -        let s:csv_move_folds = g:csv_move_folds -    else -        let s:csv_move_folds = 0 -    endif - -    if !exists("b:csv_filter") -        let b:csv_filter = {} -    endif -    if !exists("s:filter_count") || s:filter_count < 1 -        let s:filter_count = 0 -    endif -    let cpos = winsaveview() - -    if !a:add -        " remove last added item from filter -        if !empty(b:csv_filter) -            call <sid>RemoveLastItem(s:filter_count) -            let s:filter_count -= 1 -            if empty(b:csv_filter) -                call <sid>DisableFolding() -                return -            endif -        else -            " Disable folding, if no pattern available -            call <sid>DisableFolding() -            return -        endif -    else - -        let col = <sid>WColumn() -        let max = <sid>MaxColumns() -        let a   = <sid>GetColumn(line('.'), col) - -        if !exists("b:csv_fixed_width") -            try -                " strip leading whitespace -                if (a =~ '\s\+'. b:delimiter . '$') -                    let b = split(a, '^\s\+\ze[^' . b:delimiter. ']\+')[0] -                else -                    let b = a -                endif -            catch /^Vim\%((\a\+)\)\=:E684/ -                " empty pattern - should match only empty columns -                let b = a -            endtry - -            " strip trailing delimiter -            try -                let a = split(b, b:delimiter . '$')[0] -            catch /^Vim\%((\a\+)\)\=:E684/ -                let a = b -            endtry - -            if a == b:delimiter -                try -                    let a=repeat(' ', <sid>ColWidth(col)) -                catch -                    " no-op -                endtry -            endif -        endif - -        " Make a column pattern -        let b= '\%(' . -            \ (exists("b:csv_fixed_width") ? '.*' : '') . -            \ <sid>GetPat(col, max, <sid>EscapeValue(a) . '\m') . -            \ '\)' - -        let s:filter_count += 1 -        let b:csv_filter[s:filter_count] = { 'pat': b, 'id': s:filter_count, -            \ 'col': col, 'orig': a, 'match': a:match} - -    endif -    " Put the pattern into the search register, so they will also -    " be highlighted -"    let @/ = '' -"    for val in sort(values(b:csv_filter), '<sid>SortFilter') -"        let @/ .= val.pat . (val.id == s:filter_count ? '' : '\&') -"    endfor - -    " Fold settings: -    call <sid>LocalSettings('fold') -    " Don't put spaces between the arguments! -    exe 'setl foldexpr=<snr>' . s:SID . '_FoldValue(v:lnum,b:csv_filter)' - -    " Move folded area to the bottom, so there is only on consecutive -    " non-folded area -    if exists("s:csv_move_folds") && s:csv_move_folds -        \ && !&l:ro && &l:ma -        folddoclosed m$ -        let cpos.lnum = s:csv_fold_headerline + 1 -    endif -    call winrestview(cpos) -endfu - -fu! <sid>OutputFilters(bang) "{{{3 -    if !a:bang -        call <sid>CheckHeaderLine() -        if s:csv_fold_headerline -            let  title="Nr\tMatch\tCol\t      Name\tValue" -        else -            let  title="Nr\tMatch\tCol\tValue" -        endif -        echohl "Title" -        echo   printf("%s", title) -        echo   printf("%s", repeat("=",strdisplaywidth(title))) -        echohl "Normal" -        if !exists("b:csv_filter") || empty(b:csv_filter) -            echo printf("%s", "No active filter") -        else -            let items = values(b:csv_filter) -            call sort(items, "<sid>SortFilter") -            for item in items -                if s:csv_fold_headerline -                    echo printf("%02d\t% 2s\t%02d\t%10.10s\t%s", -                        \ item.id, (item.match ? '+' : '-'), item.col, -                        \ substitute(<sid>GetColumn(1, item.col), -                        \ b:col.'$', '', ''), item.orig) -                else -                    echo printf("%02d\t% 2s\t%02d\t%s", -                        \ item.id, (item.match ? '+' : '-'), -                        \ item.col, item.orig) -                endif -            endfor -        endif -    else -        " Reapply filter again -        if !exists("b:csv_filter") || empty(b:csv_filter) -            call <sid>Warn("No filters defined currently!") -            return -        else -            exe 'setl foldexpr=<snr>' . s:SID . '_FoldValue(v:lnum,b:csv_filter)' -        endif -    endif -endfu - -fu! <sid>SortFilter(a, b) "{{{3 -    return a:a.id == a:b.id ? 0 : -        \ a:a.id > a:b.id ? 1 : -1 -endfu - -fu! <sid>GetColumn(line, col) "{{{3 -    " Return Column content at a:line, a:col -    let a=getline(a:line) -    " Filter comments out -    if a =~ '^\s*\V'. escape(b:csv_cmt[0], '\\') -        return '' -    endif - -    if !exists("b:csv_fixed_width_cols") -        try -            let a = split(a, '^' . b:col . '\zs')[a:col - 1] -        catch -            " index out of range -            let a = '' -        endtry -    else -        let a = matchstr(a, <sid>GetColPat(a:col, 0)) -    endif -    return substitute(a, '^\s\+\|\s\+$', '', 'g') -endfu - -fu! <sid>RemoveLastItem(count) "{{{3 -    for [key,value] in items(b:csv_filter) -        if value.id == a:count -            call remove(b:csv_filter, key) -        endif -    endfor -endfu - -fu! <sid>DisableFolding() "{{{3 -    setl nofen fdm=manual fdc=0 fdl=0 -    if !get(g:, 'csv_disable_fdt',0) && exists("s:fdt") && exists("s:fcs") -        exe printf("setl fdt=%s fcs=%s", s:fdt, escape(s:fcs, '\\|')) -    endif -endfu - -fu! <sid>NumberFormat() "{{{3 -    let s:nr_format = [',', '.'] -    if exists("b:csv_thousands_sep") -        let s:nr_format[0] = b:csv_thousands_sep -    endif -    if exists("b:csv_decimal_sep") -        let s:nr_format[1] = b:csv_decimal_sep -    endif -endfu - -fu! <sid>CheckHeaderLine() "{{{3 -    if !exists("b:csv_headerline") -        let s:csv_fold_headerline = 1 -    else -        let s:csv_fold_headerline = b:csv_headerline -    endif -endfu - -fu! <sid>AnalyzeColumn(...) "{{{3 -    let maxcolnr = <SID>MaxColumns() -    if len(a:000) == 1 -        let colnr = a:1 -    else -        let colnr = <sid>WColumn() -    endif - -    if colnr > maxcolnr -        call <SID>Warn("There exists no column " . colnr) -        return 1 -    endif - -    " Initialize s:fold_headerline -    call <sid>CheckHeaderLine() -    let data = <sid>CopyCol('', colnr, '')[s:csv_fold_headerline : -1] -    let qty = len(data) -    let res = {} -    for item in data -        if empty(item) || item ==# b:delimiter -            let item = 'NULL' -        endif -        if !get(res, item) -            let res[item] = 0 -        endif -        let res[item]+=1 -    endfor - -    let max_items = reverse(sort(values(res))) -    let count_items = keys(res) -    if len(max_items) > 5 -        call remove(max_items, 5, -1) -        call filter(res, 'v:val =~ ''^''.join(max_items, ''\|'').''$''') -    endif - -    if has("float") -        let  title="Nr\tCount\t % \tValue" -    else -        let  title="Nr\tCount\tValue" -    endif -    echohl Title -    echo printf("%s", title) -    echohl Normal -    echo printf("%s", repeat('=', strdisplaywidth(title))) - -    let i=1 -    for val in max_items -        for key in keys(res) -            if res[key] == val && i <= len(max_items) -                if !empty(b:delimiter) -                    let k = substitute(key, b:delimiter . '\?$', '', '') -                else -                    let k = key -                endif -                if has("float") -                    echo printf("%02d\t%02d\t%2.0f%%\t%.50s", i, res[key], -                        \ ((res[key] + 0.0)/qty)*100, k) -                else -                    echo printf("%02d\t%02d\t%.50s", i, res[key], k) -                endif -                call remove(res,key) -                let i+=1 -            else -                continue -            endif -        endfor -    endfor -    echo printf("%s", repeat('=', strdisplaywidth(title))) -    echo printf("different values: %d", len(count_items)) -    unlet max_items -endfunc - -fu! <sid>Vertfold(bang, col) "{{{3 -    if a:bang -        do Syntax -        return -    endif -    if !has("conceal") -        call <sid>Warn("Concealing not supported in your Vim") -        return -    endif -    if empty(b:delimiter) && !exists("b:csv_fixed_width_cols") -        call <sid>Warn("There are no columns defined, can't hide away anything!") -        return -    endif -    if empty(a:col) -        let colnr=<SID>WColumn() -    else -        let colnr=a:col -    endif -    let pat=<sid>GetPat(colnr, <sid>MaxColumns(), '.*') -    if exists("b:csv_fixed_width_cols") && -        \ pat !~ '^\^\.\*' -        " Make the pattern implicitly start at line start, -        " so it will be applied by syntax highlighting (:h :syn-priority) -        let pat='^.*' . pat -    endif -    let pat=substitute(pat, '\\zs\(\.\*\)\@=', '', '') -    if !empty(pat) -        exe "syn match CSVFold /" . pat . "/ conceal cchar=+" -    endif -endfu - -fu! <sid>InitCSVFixedWidth() "{{{3 -    if !exists("+cc") -        " TODO: make this work with a custom matchadd() command for older -        " Vims, that don't have 'colorcolumn' -        call <sid>Warn("'colorcolumn' option not available") -        return -    endif -    " Turn off syntax highlighting -    syn clear -    let max_len = len(split(getline(1), '\zs')) -    let _cc  = &l:cc -    let &l:cc = 1 -    redraw! -    let Dict = {'1': 1} " first column is always the start of a new column -    let tcc  = &l:cc -    let &l:cc = 1 -    echo "<Cursor>, <Space>, <ESC>, <BS>, <CR>..." -    let char=getchar() -    while 1 -        if char == "\<Left>" || char == "\<Right>" -            let tcc = eval('tcc'.(char=="\<Left>" ? '-' : '+').'1') -            if tcc < 0 -                let tcc=0 -            elseif tcc > max_len -                let tcc = max_len -            endif -        elseif char == "\<Space>" || char == 32 " Space -            let Dict[tcc] = 1 -        elseif char == "\<BS>" || char == 127 -            try -                call remove(Dict, reverse(sort(keys(Dict)))[0]) -            catch /^Vim\%((\a\+)\)\=:E\(\%(716\)\|\%(684\)\)/	" Dict or List empty -                break -            endtry -        elseif char == "\<ESC>" || char == 27 -            let &l:cc=_cc -            redraw! -            return -        elseif char == "\<CR>" || char == "\n" || char == "\r"  " Enter -            let Dict[tcc] = 1 -            break -        else -            break -        endif -        let &l:cc=tcc . (!empty(keys(Dict))? ',' . join(keys(Dict), ','):'') -        redraw! -        echo "<Cursor>, <Space>, <ESC>, <BS>, <CR>..." -        let char=getchar() -    endw -    let b:csv_fixed_width_cols=[] -    let tcc=0 -    let b:csv_fixed_width_cols = sort(keys(Dict), "<sid>SortList") -    let b:csv_fixed_width = join(sort(keys(Dict), "<sid>SortList"), ',') -    call <sid>Init(1, line('$')) - -    let &l:cc=_cc -    redraw! -endfu - -fu! <sid>NewRecord(line1, line2, count) "{{{3 -    if a:count =~ "\D" -        call <sid>Warn("Invalid count specified") -        return -    endif - -    let cnt = (empty(a:count) ? 1 : a:count) -    let record = "" -    for item in range(1,<sid>MaxColumns()) -        if !exists("b:col_width") -            " Best guess width -            if exists("b:csv_fixed_width_cols") -                let record .= printf("%*s", <sid>ColWidth(item), -                            \ b:delimiter) -            else -                let record .= printf("%20s", b:delimiter) -            endif -        else -            let record .= printf("%*s", get(b:col_width, item-1, 0)+1, b:delimiter) -        endif -    endfor - -    if getline(1)[-1:] !=  b:delimiter -        let record = record[0:-2] . " " -    endif - -    let line = [] -    for item in range(cnt) -        call add(line, record) -    endfor -    for nr in range(a:line1, a:line2) -        call append(nr, line) -    endfor -endfu - -fu! <sid>MoveOver(outer) "{{{3 -    " Move over a field -    " a:outer means include the delimiter -    let last = 0 -    let outer_field = a:outer -    let cur_field = <sid>WColumn() -    let _wsv = winsaveview() - -    if cur_field == <sid>MaxColumns() -        let last = 1 -        if !outer_field && getline('.')[-1:] != b:delimiter -            " No trailing delimiter, so inner == outer -            let outer_field = 1 -        endif -    endif -    " Move 1 column backwards, unless the cursor is in the first column -    " or in front of a delimiter -    if matchstr(getline('.'), '.\%'.virtcol('.').'v') != b:delimiter && virtcol('.') > 1 -        call <sid>MoveCol(-1, line('.')) -    endif -"    if cur_field != <sid>WColumn() -        " cursor was at the beginning of the field, and moved back to the -        " previous field, move back to original position -"        call cursor(_wsv.lnum, _wsv.col) -"    endif -    let _s = @/ -    if last -        exe "sil! norm! v$h" . (outer_field ? "" : "h") . (&sel ==# 'exclusive' ? "l" : '') -    else -        exe "sil! norm! v/." . b:col . "\<cr>h" . (outer_field ? "" : "h") . (&sel ==# 'exclusive' ? "l" : '') -    endif -    let _wsv.col = col('.')-1 -    call winrestview(_wsv) -    let @/ = _s -endfu - -fu! <sid>CSVMappings() "{{{3 -    call <sid>Map('noremap', 'W', ':<C-U>call <SID>MoveCol(1, line("."))<CR>') -    call <sid>Map('noremap', '<C-Right>', ':<C-U>call <SID>MoveCol(1, line("."))<CR>') -    call <sid>Map('noremap', 'L', ':<C-U>call <SID>MoveCol(1, line("."))<CR>') -    call <sid>Map('noremap', 'E', ':<C-U>call <SID>MoveCol(-1, line("."))<CR>') -    call <sid>Map('noremap', '<C-Left>', ':<C-U>call <SID>MoveCol(-1, line("."))<CR>') -    call <sid>Map('noremap', 'H', ':<C-U>call <SID>MoveCol(-1, line("."), 1)<CR>') -    call <sid>Map('noremap', 'K', ':<C-U>call <SID>MoveCol(0, line(".")-v:count1)<CR>') -    call <sid>Map('noremap', '<Up>', ':<C-U>call <SID>MoveCol(0, line(".")-v:count1)<CR>') -    call <sid>Map('noremap', 'J', ':<C-U>call <SID>MoveCol(0, line(".")+v:count1)<CR>') -    call <sid>Map('noremap', '<Down>', ':<C-U>call <SID>MoveCol(0, line(".")+v:count1)<CR>') -    call <sid>Map('nnoremap', '<CR>', ':<C-U>call <SID>PrepareFolding(1, 1)<CR>') -    call <sid>Map('nnoremap', '<Space>', ':<C-U>call <SID>PrepareFolding(1, 0)<CR>') -    call <sid>Map('nnoremap', '<BS>', ':<C-U>call <SID>PrepareFolding(0, 1)<CR>') -    call <sid>Map('imap', '<CR>', '<sid>ColumnMode()', 'expr') -    " Text object: Field -    call <sid>Map('vnoremap', 'if', ':<C-U>call <sid>MoveOver(0)<CR>') -    call <sid>Map('vnoremap', 'af', ':<C-U>call <sid>MoveOver(1)<CR>') -    call <sid>Map('omap', 'af', ':norm vaf<cr>') -    call <sid>Map('omap', 'if', ':norm vif<cr>') -    " Remap <CR> original values to a sane backup -    call <sid>Map('noremap', '<LocalLeader>J', 'J') -    call <sid>Map('noremap', '<LocalLeader>K', 'K') -    call <sid>Map('vnoremap', '<LocalLeader>W', 'W') -    call <sid>Map('vnoremap', '<LocalLeader>E', 'E') -    call <sid>Map('noremap', '<LocalLeader>H', 'H') -    call <sid>Map('noremap', '<LocalLeader>L', 'L') -    call <sid>Map('nnoremap', '<LocalLeader><CR>', '<CR>') -    call <sid>Map('nnoremap', '<LocalLeader><Space>', '<Space>') -    call <sid>Map('nnoremap', '<LocalLeader><BS>', '<BS>') -endfu - -fu! <sid>CommandDefinitions() "{{{3 -    call <sid>LocalCmd("WhatColumn", ':echo <sid>WColumn(<bang>0)', -        \ '-bang') -    call <sid>LocalCmd("NrColumns", ':call <sid>NrColumns(<q-bang>)', '-bang') -    call <sid>LocalCmd("HiColumn", ':call <sid>HiCol(<q-args>,<bang>0)', -        \ '-bang -nargs=?') -    call <sid>LocalCmd("SearchInColumn", -        \ ':call <sid>SearchColumn(<q-args>)', '-nargs=*') -    call <sid>LocalCmd("DeleteColumn", ':call <sid>DeleteColumn(<q-args>)', -        \ '-nargs=? -complete=custom,<sid>SortComplete') -    call <sid>LocalCmd("ArrangeColumn", -        \ ':call <sid>ArrangeCol(<line1>, <line2>, <bang>0, -1)', -        \ '-range -bang') -    call <sid>LocalCmd("UnArrangeColumn", -        \':call <sid>PrepUnArrangeCol(<line1>, <line2>)', -        \ '-range') -    call <sid>LocalCmd("InitCSV", ':call <sid>Init(<line1>,<line2>,<bang>0)', -        \ '-bang -range=%') -    call <sid>LocalCmd('Header', -        \ ':call <sid>SplitHeaderLine(<q-args>,<bang>0,1)', -        \ '-nargs=? -bang') -    call <sid>LocalCmd('VHeader', -        \ ':call <sid>SplitHeaderLine(<q-args>,<bang>0,0)', -        \ '-nargs=? -bang') -    call <sid>LocalCmd("HeaderToggle", -        \ ':call <sid>SplitHeaderToggle(1)', '') -    call <sid>LocalCmd("VHeaderToggle", -        \ ':call <sid>SplitHeaderToggle(0)', '') -    call <sid>LocalCmd("Sort", -        \ ':call <sid>Sort(<bang>0, <line1>,<line2>,<q-args>)', -        \ '-nargs=* -bang -range=% -complete=custom,<sid>SortComplete') -    call <sid>LocalCmd("Column", -        \ ':call <sid>CopyCol(empty(<q-reg>)?''"'':<q-reg>,<q-count>,<q-args>)', -        \ '-count -register -nargs=?') -    call <sid>LocalCmd("MoveColumn", -        \ ':call <sid>MoveColumn(<line1>,<line2>,<f-args>)', -        \ '-range=% -nargs=* -complete=custom,<sid>SortComplete') -    call <sid>LocalCmd("SumCol", -        \ ':echo csv#EvalColumn(<q-args>, "<sid>SumColumn", <line1>,<line2>)', -        \ '-nargs=? -range=% -complete=custom,<sid>SortComplete') -    call <sid>LocalCmd("ConvertData", -        \ ':call <sid>PrepareDoForEachColumn(<line1>,<line2>,<bang>0)', -        \ '-bang -nargs=? -range=%') -    call <sid>LocalCmd("Filters", ':call <sid>OutputFilters(<bang>0)', -        \ '-nargs=0 -bang') -    call <sid>LocalCmd("Analyze", ':call <sid>AnalyzeColumn(<args>)', -        \ '-nargs=?') -    call <sid>LocalCmd("VertFold", ':call <sid>Vertfold(<bang>0,<q-args>)', -        \ '-bang -nargs=? -range=% -complete=custom,<sid>SortComplete') -    call <sid>LocalCmd("CSVFixed", ':call <sid>InitCSVFixedWidth()', '') -    call <sid>LocalCmd("NewRecord", ':call <sid>NewRecord(<line1>, -        \ <line2>, <q-args>)', '-nargs=? -range') -    call <sid>LocalCmd("NewDelimiter", ':call <sid>NewDelimiter(<q-args>, 1, line(''$''))', -        \ '-nargs=1') -    call <sid>LocalCmd("Duplicates", ':call <sid>CheckDuplicates(<q-args>)', -        \ '-nargs=1 -complete=custom,<sid>CompleteColumnNr') -    call <sid>LocalCmd('Transpose', ':call <sid>Transpose(<line1>, <line2>)', -        \ '-range=%') -    call <sid>LocalCmd('CSVTabularize', ':call <sid>Tabularize(<bang>0,<line1>,<line2>)', -        \ '-bang -range=%') -    call <sid>LocalCmd("AddColumn", -        \ ':call <sid>AddColumn(<line1>,<line2>,<f-args>)', -        \ '-range=% -nargs=* -complete=custom,<sid>SortComplete') -    call <sid>LocalCmd('Substitute', ':call <sid>SubstituteInColumn(<q-args>,<line1>,<line2>)', -        \ '-nargs=1 -range=%') -endfu - -fu! <sid>Map(map, name, definition, ...) "{{{3 -    let keyname = substitute(a:name, '[<>]', '', 'g') -    let expr = (exists("a:1") && a:1 == 'expr'  ? '<expr>' : '') -    if !get(g:, "csv_nomap_". tolower(keyname), 0) -        " All mappings are buffer local -        exe a:map "<buffer> <silent>". expr a:name a:definition -        " should already exists -        if a:map == 'nnoremap' -            let unmap = 'nunmap' -        elseif a:map == 'noremap' || a:map == 'map' -            let unmap = 'unmap' -        elseif a:map == 'vnoremap' -            let unmap = 'vunmap' -        elseif a:map == 'omap' -            let unmap = 'ounmap' -        elseif a:map == 'imap' -            let unmap = 'iunmap' -        endif -        let b:undo_ftplugin .= "| " . unmap . " <buffer> " . a:name -    endif -endfu - -fu! <sid>LocalCmd(name, definition, args) "{{{3 -    if !exists(':'.a:name) -        exe "com! -buffer " a:args a:name a:definition -        let b:undo_ftplugin .= "| sil! delc " . a:name -    endif -    " Setup :CSV<Command> Aliases -    if a:name !~ '^CSV' -        call <sid>LocalCmd('CSV'.a:name, a:definition, a:args) -    endif -endfu - -fu! <sid>Menu(enable) "{{{3 -    if a:enable -        " Make a menu for the graphical vim -        amenu CSV.&Init\ Plugin             :InitCSV<cr> -        amenu CSV.SetUp\ &fixedwidth\ Cols  :CSVFixed<cr> -        amenu CSV.-sep1-                    <nul> -        amenu &CSV.&Column.&Number          :WhatColumn<cr> -        amenu CSV.Column.N&ame              :WhatColumn!<cr> -        amenu CSV.Column.&Highlight\ column :HiColumn<cr> -        amenu CSV.Column.&Remove\ highlight :HiColumn!<cr> -        amenu CSV.Column.&Delete            :DeleteColumn<cr> -        amenu CSV.Column.&Sort              :%Sort<cr> -        amenu CSV.Column.&Copy              :Column<cr> -        amenu CSV.Column.&Move              :%MoveColumn<cr> -        amenu CSV.Column.S&um               :%SumCol<cr> -        amenu CSV.Column.Analy&ze           :Analyze<cr> -        amenu CSV.Column.&Arrange           :%ArrangeCol<cr> -        amenu CSV.Column.&UnArrange         :%UnArrangeCol<cr> -        amenu CSV.Column.&Add               :%AddColumn<cr> -        amenu CSV.-sep2-                    <nul> -        amenu CSV.&Toggle\ Header           :HeaderToggle<cr> -        amenu CSV.&ConvertData              :ConvertData<cr> -        amenu CSV.Filters                   :Filters<cr> -        amenu CSV.Hide\ C&olumn             :VertFold<cr> -        amenu CSV.&New\ Record              :NewRecord<cr> -    else -        " just in case the Menu wasn't defined properly -        sil! amenu disable CSV -    endif -endfu - -fu! <sid>SaveOptions(list) "{{{3 -    let save = {} -    for item in a:list -        exe "let save.". item. " = &l:". item -    endfor -    return save -endfu - -fu! <sid>NewDelimiter(newdelimiter, firstl, lastl) "{{{3 -    let save = <sid>SaveOptions(['ro', 'ma']) -    if exists("b:csv_fixed_width_cols") -        call <sid>Warn("NewDelimiter does not work with fixed width column!") -        return -    endif -    if !&l:ma -        setl ma -    endif -    if &l:ro -        setl noro -    endif -    let delimiter = a:newdelimiter -    if a:newdelimiter is '\t' -        let delimiter="\t" -    endif -    let line=a:firstl -    while line <= a:lastl -        " Don't change delimiter for comments -        if getline(line) =~ '^\s*\V'. escape(b:csv_cmt[0], '\\') -            let line+=1 -            continue -        endif -        let fields=split(getline(line), b:col . '\zs') -        " Remove field delimiter -        call map(fields, 'substitute(v:val, b:delimiter . -            \ ''\?$'' , "", "")') -        call setline(line, join(fields, delimiter)) -        let line+=1 -    endwhile -    " reset local buffer options -    for [key, value] in items(save) -        call setbufvar('', '&'. key, value) -    endfor -    "reinitialize the plugin -    if exists("g:csv_delim") -        let _delim = g:csv_delim -    endif -    let g:csv_delim = delimiter -    call <sid>Init(1,line('$')) -    if exists("_delim") -        let g:csv_delim = _delim -    else -        unlet g:csv_delim -    endif -    unlet! _delim -endfu - -fu! <sid>IN(list, value) "{{{3 -    for item in a:list -        if item == a:value -            return 1 -        endif -    endfor -    return 0 -endfu - -fu! <sid>DuplicateRows(columnlist) "{{{3 -    let duplicates = {} -    let cnt   = 0 -    let line  = 1 -    while line <= line('$') -        let key = "" -        let i = 1 -        let content = getline(line) -        " Skip comments -        if content =~ '^\s*\V'. escape(b:csv_cmt[0], '\\') -            continue -        endif -        let cols = split(content, b:col. '\zs') -        for column in cols -            if <sid>IN(a:columnlist, i) -                let key .= column -            endif -            let i += 1 -        endfor -        if has_key(duplicates, key) && cnt < 10 -            call <sid>Warn("Duplicate Row ". line) -            let cnt += 1 -        elseif has_key(duplicates, key) -            call <sid>Warn("More duplicate Rows after: ". line) -            call <sid>Warn("Aborting...") -            return -        else -            let duplicates[key] = 1 -        endif -        let line += 1 -    endwhile -    if cnt == 0 -        call <sid>Warn("No Duplicate Row found!") -    endif -endfu -fu! <sid>CompleteColumnNr(A,L,P) "{{{3 -    return join(range(1,<sid>MaxColumns()), "\n") -endfu - -fu! <sid>CheckDuplicates(list) "{{{3 -    let string = a:list -    if string =~ '\d\s\?-\s\?\d' -        let string = substitute(string, '\(\d\+\)\s\?-\s\?\(\d\+\)', -            \ '\=join(range(submatch(1),submatch(2)), ",")', '') -    endif -    let list=split(string, ',') -    call <sid>DuplicateRows(list) -endfu - -fu! <sid>Transpose(line1, line2) "{{{3 -    " Note: - Comments will be deleted. -    "       - Does not work with fixed-width columns -    if exists("b:csv_fixed_width") -        call <sid>Warn("Transposing does not work with fixed-width columns!") -        return -    endif -    let _wsv    = winsaveview() -    let TrailingDelim = 0 - -    if line('$') > 1 -        let TrailingDelim = getline(1) =~ b:delimiter.'$' -    endif - -    let pat = '^\s*\V'. escape(b:csv_cmt[0], '\\') - -    try -        let columns = <sid>MaxColumns(a:line1) -    catch -        " No column, probably because of comment or empty line -        " so use the number of columns from the beginning of the file -        let columns = <sid>MaxColumns() -    endtry -    let matrix  = [] -    for line in range(a:line1, a:line2) -        " Filter comments out -        if getline(line) =~ pat -            continue -        endif -        let r   = [] -        for row in range(1,columns) -            let field = <sid>GetColumn(line, row) -            call add(r, field) -        endfor -        call add(matrix, r) -    endfor -    unlet row - -    " create new transposed matrix -    let transposed = [] -    for row in matrix -        let i = 0 -        for val in row -            if get(transposed, i, []) == [] -                call add(transposed, []) -            endif -            if val[-1:] != b:delimiter -                let val .= b:delimiter -            endif -            call add(transposed[i], val) -            let i+=1 -        endfor -    endfor -    " Save memory -    unlet! matrix -    call map(transposed, 'join(v:val, '''')') -    if !TrailingDelim -        call map(transposed, 'substitute(v:val, b:delimiter.''\?$'', "", "")') -    endif -    " filter out empty records -    call filter(transposed, 'v:val != b:delimiter') - -    " Insert transposed data -    let delete_last_line = 0 -    if a:line1 == 1 && a:line2 == line('$') -        let delete_last_line = 1 -    endif -    exe a:line1. ",". a:line2. "d _" -    let first = (a:line1 > 0 ? (a:line1 - 1) : 0) -    call append(first, transposed) -    if delete_last_line -        sil $d _ -    endif -    " save memory -    unlet! transposed -    call winrestview(_wsv) -endfu - - -fu! <sid>NrColumns(bang) "{{{3 -    if !empty(a:bang) -        try -            let cols = <sid>MaxColumns(line('.')) -        catch -            " No column or comment line -            call <sid>Warn("No valid CSV Column!") -        endtry -    else -        let cols = <sid>MaxColumns() -    endif -    echo cols -endfu - -fu! <sid>Tabularize(bang, first, last) "{{{3 -    if match(split(&ft, '\.'),'csv') == -1 -        call <sid>Warn("No CSV filetype, aborting!") -        return -    endif -    let _c = winsaveview() -    " Table delimiter definition "{{{4 -    if !exists("s:td") -        let s:td = { -            \ 'hbar': (&enc =~# 'utf-8' ? '─' : '-'), -            \ 'vbar': (&enc =~# 'utf-8' ? '│' : '|'), -            \ 'scol': (&enc =~# 'utf-8' ? '├' : '|'), -            \ 'ecol': (&enc =~# 'utf-8' ? '┤' : '|'), -            \ 'ltop': (&enc =~# 'utf-8' ? '┌' : '+'), -            \ 'rtop': (&enc =~# 'utf-8' ? '┐' : '+'), -            \ 'lbot': (&enc =~# 'utf-8' ? '└' : '+'), -            \ 'rbot': (&enc =~# 'utf-8' ? '┘' : '+'), -            \ 'cros': (&enc =~# 'utf-8' ? '┼' : '+'), -            \ 'dhor': (&enc =~# 'utf-8' ? '┬' : '-'), -            \ 'uhor': (&enc =~# 'utf-8' ? '┴' : '-') -            \ } -    endif "}}}4 -    if match(getline(a:first), '^'.s:td.ltop) > -1 -        " Already tabularized, done -        call <sid>Warn("Looks already Tabularized, aborting!") -        return -    endif -    let _ma = &l:ma -    setl ma -    let colwidth = 0 -    let adjust_last = 0 -    call cursor(a:first,0) -    call <sid>CheckHeaderLine() -    let line=a:first -    if exists("g:csv_table_leftalign") -        let b:csv_arrange_leftalign = 1 -    endif -    let newlines=[] -    while line <= a:last -        let curline = getline(line) -        if empty(split(curline, b:delimiter)) -            " only empty delimiters, add one empty delimiter -            " (:NewDelimiter strips trailing delimiter -            let curline = repeat(b:delimiter, <sid>MaxColumns()) -            call add(newlines, line) -            call setline(line, curline) -        endif -        let line+=1 -    endw -    unlet! line -    if exists("b:csv_fixed_width_cols") -        let cols=copy(b:csv_fixed_width_cols) -        let pat = join(map(cols, ' ''\(\%''. v:val. ''c\)'' '), '\|') -        let colwidth = strlen(substitute(getline('$'), '.', 'x', 'g')) -        let t=-1 -        let b:col_width = [] -        for item in b:csv_fixed_width_cols + [colwidth] -            if t > -1 -                call add(b:col_width, item-t) -            endif -            let t = item -        endfor -    else -        " don't clear column width variable, might have been set in the -        " plugin! -        sil call <sid>ArrangeCol(a:first, a:last, 0, -1) -        if !get(b:, 'csv_arrange_leftalign',0) -            for line in newlines -                let cline = getline(line) -                let cline = substitute(cline, '\s$', ' ', '') -                call setline(line, cline) -            endfor -            unlet! line -        endif -    endif - -    if empty(b:col_width) -        call <sid>Warn('An error occured, aborting!') -        return -    endif -    if getline(a:first)[-1:] isnot? b:delimiter -        let b:col_width[-1] += 1 -    endif -    let marginline = s:td.scol. join(map(copy(b:col_width), 'repeat(s:td.hbar, v:val)'), s:td.cros). s:td.ecol - -    call <sid>NewDelimiter(s:td.vbar, a:first, a:last+adjust_last) -    "exe printf('sil %d,%ds/%s/%s/ge', a:first, (a:last+adjust_last), -    "    \ (exists("b:csv_fixed_width_cols") ? pat : b:delimiter ), s:td.vbar) -    " Add vertical bar in first column, if there isn't already one -    exe printf('sil %d,%ds/%s/%s/e', a:first, a:last+adjust_last, -        \ '^[^'. s:td.vbar. s:td.scol. ']', s:td.vbar.'&') -    " And add a final vertical bar, if there isn't one already -    exe printf('sil %d,%ds/%s/%s/e', a:first, a:last+adjust_last, -        \ '[^'. s:td.vbar. s:td.ecol. ']$', '&'. s:td.vbar) -    " Make nice intersection graphs -    let line = split(getline(a:first), s:td.vbar) -    call map(line, 'substitute(v:val, ''[^''.s:td.vbar. '']'', s:td.hbar, ''g'')') -    " Set top and bottom margins -    call append(a:first-1, s:td.ltop. join(line, s:td.dhor). s:td.rtop) -    call append(a:last+adjust_last+1, s:td.lbot. join(line, s:td.uhor). s:td.rbot) - -    if s:csv_fold_headerline > 0 -        call append(a:first + s:csv_fold_headerline, marginline) -        let adjust_last += 1 -    endif -    " Syntax will be turned off, so disable this part -    " -    " Adjust headerline to header of new table -    "let b:csv_headerline = (exists('b:csv_headerline')?b:csv_headerline+2:3) -    "call <sid>CheckHeaderLine() -    " Adjust syntax highlighting -    "unlet! b:current_syntax -    "ru syntax/csv.vim - -    if a:bang -        exe printf('sil %d,%ds/^%s\zs\n/&%s&/e', a:first + s:csv_fold_headerline, a:last + adjust_last, -                    \ '[^'.s:td.scol. '][^'.s:td.hbar.'].*', marginline) -    endif - -    syn clear -    let &l:ma = _ma -    call winrestview(_c) -endfu - -fu! <sid>SubstituteInColumn(command, line1, line2) range "{{{3 -    " Command can be something like 1,2/foobar/foobaz/ to replace in 1 and second column -    " Command can be something like /foobar/foobaz/ to replace in the current column -    " Command can be something like 1,$/foobar/foobaz/ to replace in all columns -    " Command can be something like 3/foobar/foobaz/flags to replace only in the 3rd column - -    " Save position and search register -    let _wsv = winsaveview() -    let _search = [ '/', getreg('/'), getregtype('/')] -    let columns = [] -    let maxcolnr = <sid>MaxColumns() -    let simple_s_command = 0 " when set to 1, we can simply use an :s command - -    " try to split on '/' if it is not escaped or in a collection -    let cmd = split(a:command, '\%([\\]\|\[[^]]*\)\@<!/') -    if a:command !~? '^\%([$]\|\%(\d\+\)\%(,\%([0-9]\+\|[$]\)\)\?\)/' || -                \ len(cmd) == 2 || -                \ ((len(cmd) == 3 && cmd[2] =~# '^[&cgeiInp#l]\+$')) -        " No Column address given -        call add(columns, <sid>WColumn()) -        let cmd = [columns[0]] + cmd "First item of cmd list contains address! -    elseif ((len(cmd) == 3 && cmd[2] !~# '^[&cgeiInp#l]\+$') -    \ || len(cmd) == 4) -        " command could be '1/foobbar/foobaz' -        " but also 'foobar/foobar/g' -        let columns = split(cmd[0], ',') -        if empty(columns) -            " No columns given? replace in current column only -            let columns[0] = <sid>WColumn() -        elseif columns[-1] == '$' -            let columns[-1] = maxcolnr -        endif -    else " not reached ? -        call add(columns, <sid>WColumn()) -    endif - -    try -        if len(cmd) == 1 || columns[0] =~ '\D' || (len(columns) == 2 && columns[1] =~ '\D') -            call <SID>Warn("Error! Usage :S [columns/]pattern/replace[/flags]") -            return -        endif - -        if len(columns) == 2 && columns[0] == 1 && columns[1] == maxcolnr -            let simple_s_command = 1 -        elseif len(columns) == 2 -            let columns = range(columns[0], columns[1]) -        endif - -        let has_flags = len(cmd) == 4 - -        if simple_s_command -            while search(cmd[1]) -                exe printf("%d,%ds/%s/%s%s", a:line1, a:line2, cmd[1], cmd[2], (has_flags ? '/'. cmd[3] : '')) -                if !has_flags || (has_flags && cmd[3] !~# 'g') -                    break -                endif -            endw -        else -            for colnr in columns -                let @/ = <sid>GetPat(colnr, maxcolnr, cmd[1]) -                while search(@/) -                    exe printf("%d,%ds//%s%s", a:line1, a:line2, cmd[2], (has_flags ? '/'. cmd[3] : '')) -                    if !has_flags || (has_flags && cmd[3] !~# 'g') -                        break -                    endif -                endw -            endfor -        endif -    catch /^Vim\%((\a\+)\)\=:E486/ -        " Pattern not found -        echohl Error -        echomsg "E486: Pattern not found in column " . colnr . ": " . pat -        if &vbs > 0 -            echomsg substitute(v:exception, '^[^:]*:', '','') -        endif -        echohl Normal -    catch -        echohl Error -        "if &vbs > 0 -            echomsg substitute(v:exception, '^[^:]*:', '','') -        "endif -        echohl Normal -    finally -        " Restore position and search register -        call winrestview(_wsv) -        call call('setreg', _search) -    endtry -endfu - -fu! <sid>ColumnMode() "{{{3 -    let mode = mode() -    if mode =~# 'R' -        " (virtual) Replace mode -        let new_line = (line('.') == line('$') || -        \ (synIDattr(synIDtrans(synID(line("."), col("."), 1)), "name") =~? "comment")) -        return "\<ESC>g`[". (new_line ? "o" : "J".mode) -    else -        return "\<CR>" -    endif -endfu -fu! <sid>Timeout(start) "{{{3 -    return localtime()-a:start < 2 -endfu - -" Global functions "{{{2 -fu! csv#EvalColumn(nr, func, first, last) range "{{{3 -    " Make sure, the function is called for the correct filetype. -    if match(split(&ft, '\.'), 'csv') == -1 -        call <sid>Warn("File is no CSV file!") -        return -    endif -    let save = winsaveview() -    call <sid>CheckHeaderLine() -    let nr = matchstr(a:nr, '^\-\?\d\+') -    let col = (empty(nr) ? <sid>WColumn() : nr) -    if col == 0 -        let col = 1 -    endif -    " don't take the header line into consideration -    let start = a:first - 1 + s:csv_fold_headerline -    let stop  = a:last  - 1 + s:csv_fold_headerline - -    let column = <sid>CopyCol('', col, '')[start : stop] -    " Delete delimiter -    call map(column, 'substitute(v:val, b:delimiter . "$", "", "g")') -    " Revmoe trailing whitespace -    call map(column, 'substitute(v:val, ''^\s\+$'', "", "g")') -    " Remove leading whitespace -    call map(column, 'substitute(v:val, ''^\s\+'', "", "g")') -    " Delete empty values -    " Leave this up to the function that does something -    " with each value -    "call filter(column, '!empty(v:val)') - -    " parse the optional number format -    let format = matchstr(a:nr, '/[^/]*/') -    call <sid>NumberFormat() -    if !empty(format) -        try -            let s = [] -            " parse the optional number format -            let str = matchstr(format, '/\zs[^/]*\ze/', 0, start) -            let s = matchlist(str, '\(.\)\?:\(.\)\?')[1:2] -            if empty(s) -                " Number format wrong -                call <sid>Warn("Numberformat wrong, needs to be /x:y/!") -                return '' -            endif -            if !empty(s[0]) -                let s:nr_format[0] = s[0] -            endif -            if !empty(s[1]) -                let s:nr_format[1] = s[1] -            endif -        endtry -    endif -    try -        let result=call(function(a:func), [column]) -        return result -    catch -        " Evaluation of expression failed -        echohl Title -        echomsg "Evaluating" matchstr(a:func, '[a-zA-Z]\+$') -        \ "failed for column" col . "!" -        echohl Normal -        return '' -    finally -        call winrestview(save) -    endtry -endfu - -" return field index (x,y) with leading/trailing whitespace and trailing -" delimiter stripped (only when a:0 is not given) -fu! CSVField(x, y, ...) "{{{3 -    if &ft != 'csv' -        return -    endif -    let y = a:y - 1 -    let x = (a:x < 0 ? 0 : a:x) -    let orig = !empty(a:0) -    let y = (y < 0 ? 0 : y) -    let x = (x > (<sid>MaxColumns()) ? (<sid>MaxColumns()) : x) -    let col = <sid>CopyCol('',x,'') -    if !orig -    " remove leading and trainling whitespace and the delimiter -        return matchstr(col[y], '^\s*\zs.\{-}\ze\s*'.b:delimiter.'\?$') -    else -        return col[y] -    endif -endfu -" return current column number (if a:0 is given, returns the name -fu! CSVCol(...) "{{{3 -    return <sid>WColumn(a:0) -endfu -fu! CSVPat(colnr, ...) "{{{3 -    " Make sure, we are working in a csv file -    if &ft != 'csv' -        return '' -    endif -    " encapsulates GetPat(), that returns the search pattern for a -    " given column and tries to set the cursor at the specific position -    let pat = <sid>GetPat(a:colnr, <SID>MaxColumns(), a:0 ? a:1 : '.*') -    "let pos = match(pat, '.*\\ze') + 1 -    " Try to set the cursor at the beginning of the pattern -    " does not work -    "call setcmdpos(pos) -    return pat -endfu - -fu! CSV_WCol(...) "{{{3 -    try -        if exists("a:1") && (a:1 == 'Name' || a:1 == 1) -            return printf("%s", <sid>WColumn(1)) -        else -            return printf(" %d/%d", <SID>WColumn(), <SID>MaxColumns()) -        endif -    catch -        return '' -    endtry -endfun - -fu! CSV_SetSplitOptions(window) "{{{3 -    if exists("s:local_stl") -        " local horizontal statusline -        for opt in items({'&nu': &l:nu, '&rnu': &l:rnu, '&fdc': &fdc}) -            if opt[1] != getwinvar(a:window, opt[0]) -                call setwinvar(a:window, opt[0], opt[1]) -            endif -        endfor -        " Check statusline (airline might change it) -        if getwinvar(a:window, '&l:stl') != s:local_stl -            call setwinvar(a:window, '&stl', s:local_stl) -        endif -    endif -endfun - -fu! CSV_CloseBuffer(buffer) "{{{3 -    " Setup by SetupAutoCmd autocommand -    try -        if bufnr((a:buffer)+0) > -1 -            exe a:buffer. "bw" -        endif -    catch /^Vim\%((\a\+)\)\=:E517/	" buffer already wiped -    " no-op -    finally -        augroup CSV_QuitPre -            au! -        augroup END -        augroup! CSV_QuitPre -    endtry -endfu - -fu! CSVSum(col, fmt, first, last) "{{{3 -    let first = a:first -    let last  = a:last -    if empty(first) -        let first = 1 -    endif -    if empty(last) -        let last = line('$') -    endif -    return csv#EvalColumn(a:col, '<sid>SumColumn', first, last) -endfu -" Initialize Plugin "{{{2 -let b:csv_start = exists("b:csv_start") ? b:csv_start : 1 -let b:csv_end   = exists("b:csv_end") ? b:csv_end : line('$') - -call <SID>Init(b:csv_start, b:csv_end) -let &cpo = s:cpo_save -unlet s:cpo_save - -" Vim Modeline " {{{2 -" vim: set foldmethod=marker et: | 
