diff options
Diffstat (limited to 'vim/bundle/vim-table-mode/autoload')
8 files changed, 1150 insertions, 0 deletions
diff --git a/vim/bundle/vim-table-mode/autoload/tablemode.vim b/vim/bundle/vim-table-mode/autoload/tablemode.vim new file mode 100644 index 0000000..defc3dd --- /dev/null +++ b/vim/bundle/vim-table-mode/autoload/tablemode.vim @@ -0,0 +1,195 @@ +" Private Functions {{{1 +function! s:SetBufferOptDefault(opt, val) "{{{2 + if !exists('b:' . a:opt) + let b:{a:opt} = a:val + endif +endfunction + +function! s:Map(map, to, mode) "{{{2 + if !empty(a:to) && !hasmapto(a:map, a:mode) + for l:mode in split(a:mode, '.\zs') + execute l:mode . 'map <buffer>' a:to a:map + endfor + endif +endfunction + +function! s:UnMap(map, mode) "{{{2 + if !empty(maparg(a:map, a:mode)) + for mode in split(a:mode, '.\zs') + execute l:mode . 'unmap <buffer>' a:map + endfor + endif +endfunction + +function! s:ToggleMapping() "{{{2 + let separator_map = g:table_mode_separator + " '|' is a special character, we need to map <Bar> instead + if g:table_mode_separator ==# '|' | let separator_map = '<Bar>' | endif + + if !g:table_mode_disable_mappings + if tablemode#IsActive() + call s:Map('<Plug>(table-mode-tableize)', separator_map, 'i') + call s:Map('<Plug>(table-mode-motion-up)', g:table_mode_motion_up_map, 'n') + call s:Map('<Plug>(table-mode-motion-down)', g:table_mode_motion_down_map, 'n') + call s:Map('<Plug>(table-mode-motion-left)', g:table_mode_motion_left_map, 'n') + call s:Map('<Plug>(table-mode-motion-right)', g:table_mode_motion_right_map, 'n') + + call s:Map('<Plug>(table-mode-cell-text-object-a)', g:table_mode_cell_text_object_a_map, 'ox') + call s:Map('<Plug>(table-mode-cell-text-object-i)', g:table_mode_cell_text_object_i_map, 'ox') + + call s:Map('<Plug>(table-mode-realign)', g:table_mode_realign_map, 'n') + call s:Map('<Plug>(table-mode-delete-row)', g:table_mode_delete_row_map, 'n') + call s:Map('<Plug>(table-mode-delete-column)', g:table_mode_delete_column_map, 'n') + call s:Map('<Plug>(table-mode-add-formula)', g:table_mode_add_formula_map, 'n') + call s:Map('<Plug>(table-mode-eval-formula)', g:table_mode_eval_formula_map, 'n') + call s:Map('<Plug>(table-mode-echo-cell)', g:table_mode_echo_cell_map, 'n') + call s:Map('<Plug>(table-mode-sort)', g:table_mode_sort_map, 'n') + else + call s:UnMap(separator_map, 'i') + call s:UnMap(g:table_mode_motion_up_map, 'n') + call s:UnMap(g:table_mode_motion_down_map, 'n') + call s:UnMap(g:table_mode_motion_left_map, 'n') + call s:UnMap(g:table_mode_motion_right_map, 'n') + + call s:UnMap(g:table_mode_cell_text_object_a_map, 'ox') + call s:UnMap(g:table_mode_cell_text_object_i_map, 'ox') + + call s:UnMap(g:table_mode_realign_map, 'n') + call s:UnMap(g:table_mode_delete_row_map, 'n') + call s:UnMap(g:table_mode_delete_column_map, 'n') + call s:UnMap(g:table_mode_add_formula_map, 'n') + call s:UnMap(g:table_mode_eval_formula_map, 'n') + call s:UnMap(g:table_mode_echo_cell_map, 'n') + call s:UnMap(g:table_mode_sort_map, 'n') + endif + endif +endfunction + +function! tablemode#SyntaxEnable() + exec 'syntax match Table' + \ '/' . tablemode#table#StartExpr() . '\zs|.\+|\ze' . tablemode#table#EndExpr() . '/' + \ 'contains=TableBorder,TableSeparator,TableColumnAlign containedin=ALL' + syntax match TableSeparator /|/ contained + syntax match TableColumnAlign /:/ contained + syntax match TableBorder /[\-+]\+/ contained + + hi! link TableBorder Delimiter + hi! link TableSeparator Delimiter + hi! link TableColumnAlign Type +endfunction + +function! s:ToggleSyntax() + if tablemode#IsActive() + call tablemode#SyntaxEnable() + else + syntax clear Table + syntax clear TableBorder + syntax clear TableSeparator + syntax clear TableColumnAlign + + hi! link TableBorder NONE + hi! link TableSeparator NONE + hi! link TableColumnAlign NONE + endif +endfunction + +function! s:SetActive(bool) "{{{2 + let b:table_mode_active = a:bool + call s:ToggleSyntax() + call s:ToggleMapping() + if tablemode#IsActive() + doautocmd User TableModeEnabled + else + doautocmd User TableModeDisabled + endif +endfunction + +function! s:ConvertDelimiterToSeparator(line, ...) "{{{2 + let old_gdefault = &gdefault + set nogdefault + + let delim = g:table_mode_delimiter + if a:0 | let delim = a:1 | endif + if delim ==# ',' + silent! execute a:line . 's/' . "[\'\"][^\'\"]*\\zs,\\ze[^\'\"]*[\'\"]/__COMMA__/g" + endif + + let [cstart, cend] = [tablemode#table#GetCommentStart(), tablemode#table#GetCommentEnd()] + let [match_char_start, match_char_end] = ['.', '.'] + if tablemode#utils#strlen(cend) > 0 | let match_char_end = '[^' . cend . ']' | endif + if tablemode#utils#strlen(cstart) > 0 | let match_char_start = '[^' . cstart . ']' | endif + + silent! execute a:line . 's/' . tablemode#table#StartExpr() . '\zs\ze' . match_char_start . + \ '\|' . delim . '\|' . match_char_end . '\zs\ze' . tablemode#table#EndExpr() . '/' . + \ g:table_mode_separator . '/g' + + if delim ==# ',' + silent! execute a:line . 's/' . "[\'\"][^\'\"]*\\zs__COMMA__\\ze[^\'\"]*[\'\"]/,/g" + endif + + let &gdefault=old_gdefault +endfunction + +function! s:Tableizeline(line, ...) "{{{2 + let delim = g:table_mode_delimiter + if a:0 && type(a:1) == type('') && !empty(a:1) | let delim = a:1[1:-1] | endif + call s:ConvertDelimiterToSeparator(a:line, delim) +endfunction + +" Public API {{{1 +function! tablemode#IsActive() "{{{2 + if g:table_mode_always_active | return 1 | endif + + call s:SetBufferOptDefault('table_mode_active', 0) + return b:table_mode_active +endfunction + +function! tablemode#TableizeInsertMode() "{{{2 + if tablemode#IsActive() && getline('.') =~# (tablemode#table#StartExpr() . g:table_mode_separator . g:table_mode_separator) + call tablemode#table#AddBorder('.') + normal! A + elseif tablemode#IsActive() && getline('.') =~# (tablemode#table#StartExpr() . g:table_mode_separator) + let column = tablemode#utils#strlen(substitute(getline('.')[0:col('.')], '[^' . g:table_mode_separator . ']', '', 'g')) + let position = tablemode#utils#strlen(matchstr(getline('.')[0:col('.')], '.*' . g:table_mode_separator . '\s*\zs.*')) + call tablemode#table#Realign('.') + normal! 0 + call search(repeat('[^' . g:table_mode_separator . ']*' . g:table_mode_separator, column) . '\s\{-\}' . repeat('.', position), 'ce', line('.')) + endif +endfunction + +function! tablemode#Enable() "{{{2 + call s:SetActive(1) +endfunction + +function! tablemode#Disable() "{{{2 + call s:SetActive(0) +endfunction + +function! tablemode#Toggle() "{{{2 + if g:table_mode_always_active + return 1 + endif + + call s:SetBufferOptDefault('table_mode_active', 0) + call s:SetActive(!b:table_mode_active) +endfunction + +function! tablemode#TableizeRange(...) range "{{{2 + let lnum = a:firstline + while lnum < (a:firstline + (a:lastline - a:firstline + 1)) + call s:Tableizeline(lnum, a:1) + undojoin + let lnum += 1 + endwhile + + call tablemode#table#Realign(lnum - 1) +endfunction + +function! tablemode#TableizeByDelimiter() "{{{2 + let delim = input('/') + if delim =~# "\<Esc>" || delim =~# "\<C-C>" | return | endif + let vm = visualmode() + if vm ==? 'line' || vm ==? 'V' + exec line("'<") . ',' . line("'>") . "call tablemode#TableizeRange('/' . delim)" + endif +endfunction diff --git a/vim/bundle/vim-table-mode/autoload/tablemode/align.vim b/vim/bundle/vim-table-mode/autoload/tablemode/align.vim new file mode 100644 index 0000000..9e6330c --- /dev/null +++ b/vim/bundle/vim-table-mode/autoload/tablemode/align.vim @@ -0,0 +1,134 @@ +" Borrowed from Tabular +" Private Functions {{{1 +" function! s:StripTrailingSpaces(string) - Remove all trailing spaces {{{2 +" from a string. +function! s:StripTrailingSpaces(string) + return matchstr(a:string, '^.\{-}\ze\s*$') +endfunction + +function! s:Padding(string, length, where) "{{{3 + let gap_length = a:length - tablemode#utils#StrDisplayWidth(a:string) + if a:where =~# 'l' + return a:string . repeat(" ", gap_length) + elseif a:where =~# 'r' + return repeat(" ", gap_length) . a:string + elseif a:where =~# 'c' + let right = gap_length / 2 + let left = right + (right * 2 != gap_length) + return repeat(" ", left) . a:string . repeat(" ", right) + endif +endfunction + +" Public Functions {{{1 +" function! tablemode#align#Split() - Split a string into fields and delimiters {{{2 +" Like split(), but include the delimiters as elements +" All odd numbered elements are delimiters +" All even numbered elements are non-delimiters (including zero) +function! tablemode#align#Split(string, delim) + let rv = [] + let beg = 0 + + let len = len(a:string) + let searchoff = 0 + + while 1 + let mid = match(a:string, a:delim, beg + searchoff, 1) + if mid == -1 || mid == len + break + endif + + let matchstr = matchstr(a:string, a:delim, beg + searchoff, 1) + let length = strlen(matchstr) + + if length == 0 && beg == mid + " Zero-length match for a zero-length delimiter - advance past it + let searchoff += 1 + continue + endif + + if beg == mid + let rv += [ "" ] + else + let rv += [ a:string[beg : mid-1] ] + endif + + let rv += [ matchstr ] + + let beg = mid + length + let searchoff = 0 + endwhile + + let rv += [ strpart(a:string, beg) ] + + return rv +endfunction + +function! tablemode#align#alignments(lnum, ncols) "{{{2 + let achr = g:table_mode_align_char + let alignments = [] + if tablemode#table#IsBorder(a:lnum+1) + let hcols = tablemode#align#Split(getline(a:lnum+1), '[' . g:table_mode_corner . g:table_mode_corner_corner . ']') + for idx in range(len(hcols)) + " Right align if header + call add(alignments, 'l') + if hcols[idx] =~# achr . '[^'.achr.']\+' . achr + let alignments[idx] = 'c' + elseif hcols[idx] =~# achr . '$' + let alignments[idx] = 'r' + endif + " if hcols[idx] !~# '[^0-9\.]' | let alignments[idx] = 'r' | endif + endfor + end + return alignments +endfunction + +function! tablemode#align#Align(lines) "{{{2 + if empty(a:lines) | return [] | endif + let lines = map(a:lines, 'map(v:val, "v:key =~# \"text\" ? tablemode#align#Split(v:val, g:table_mode_separator) : v:val")') + + for line in lines + let stext = line.text + if len(stext) <= 1 | continue | endif + + if stext[0] !~ tablemode#table#StartExpr() + let stext[0] = s:StripTrailingSpaces(stext[0]) + endif + if len(stext) >= 2 + for i in range(1, len(stext)-1) + let stext[i] = tablemode#utils#strip(stext[i]) + endfor + endif + endfor + + let maxes = [] + for line in lines + let stext = line.text + if len(stext) <= 1 | continue | endif + for i in range(len(stext)) + if i == len(maxes) + let maxes += [ tablemode#utils#StrDisplayWidth(stext[i]) ] + else + let maxes[i] = max([ maxes[i], tablemode#utils#StrDisplayWidth(stext[i]) ]) + endif + endfor + endfor + + let alignments = tablemode#align#alignments(lines[0].lnum, len(lines[0].text)) + + for idx in range(len(lines)) + let tlnum = lines[idx].lnum + let tline = lines[idx].text + + if len(tline) <= 1 | continue | endif + for jdx in range(len(tline)) + " Dealing with the header being the first line + if jdx >= len(alignments) | call add(alignments, 'l') | endif + let field = s:Padding(tline[jdx], maxes[jdx], alignments[jdx]) + let tline[jdx] = field . (jdx == 0 || jdx == len(tline) ? '' : ' ') + endfor + + let lines[idx].text = s:StripTrailingSpaces(join(tline, '')) + endfor + + return lines +endfunction diff --git a/vim/bundle/vim-table-mode/autoload/tablemode/logger.vim b/vim/bundle/vim-table-mode/autoload/tablemode/logger.vim new file mode 100644 index 0000000..ab3986d --- /dev/null +++ b/vim/bundle/vim-table-mode/autoload/tablemode/logger.vim @@ -0,0 +1,5 @@ +function! tablemode#logger#log(message) + if g:table_mode_verbose + echom message + endif +endfunction diff --git a/vim/bundle/vim-table-mode/autoload/tablemode/spreadsheet.vim b/vim/bundle/vim-table-mode/autoload/tablemode/spreadsheet.vim new file mode 100644 index 0000000..6f79d5c --- /dev/null +++ b/vim/bundle/vim-table-mode/autoload/tablemode/spreadsheet.vim @@ -0,0 +1,189 @@ +" Private Functions {{{1 +function! s:Sum(list) "{{{2 + let result = 0.0 + for item in a:list + if type(item) == type(1) || type(item) == type(1.0) + let result += item + elseif type(item) == type('') + let result += str2float(item) + elseif type(item) == type([]) + let result += s:Sum(item) + endif + endfor + return result +endfunction + +function! s:Average(list) "{{{2 + return s:Sum(a:list)/len(a:list) +endfunction + +" Public Functions {{{1 +function! tablemode#spreadsheet#GetFirstRow(line) "{{{2 + if tablemode#table#IsRow(a:line) + let line = tablemode#utils#line(a:line) + + while !tablemode#table#IsHeader(line - 1) && (tablemode#table#IsRow(line - 1) || tablemode#table#IsBorder(line - 1)) + let line -= 1 + endwhile + if tablemode#table#IsBorder(line) | let line += 1 | endif + + return line + endif +endfunction + +function! tablemode#spreadsheet#MoveToFirstRow() "{{{2 + if tablemode#table#IsRow('.') + call cursor(tablemode#spreadsheet#GetFirstRow('.'), col('.')) + endif +endfunction + +function! tablemode#spreadsheet#GetLastRow(line) "{{{2 + if tablemode#table#IsRow(a:line) + let line = tablemode#utils#line(a:line) + + while tablemode#table#IsTable(line + 1) + let line += 1 + endwhile + if tablemode#table#IsBorder(line) | let line -= 1 | endif + + return line + endif +endfunction + +function! tablemode#spreadsheet#MoveToLastRow() "{{{2 + if tablemode#table#IsRow('.') + call cursor(tablemode#spreadsheet#GetLastRow('.'), col('.')) + endif +endfunction + +function! tablemode#spreadsheet#LineNr(line, row) "{{{2 + if tablemode#table#IsRow(a:line) + let line = tablemode#spreadsheet#GetFirstRow(a:line) + let row_nr = 0 + + while tablemode#table#IsTable(line + 1) + if tablemode#table#IsRow(line) + let row_nr += 1 + if a:row ==# row_nr | break | endif + endif + let line += 1 + endwhile + + return line + endif +endfunction + +function! tablemode#spreadsheet#RowNr(line) "{{{2 + let line = tablemode#utils#line(a:line) + + let rowNr = 0 + while !tablemode#table#IsHeader(line) && tablemode#table#IsTable(line) + if tablemode#table#IsRow(line) | let rowNr += 1 | endif + let line -= 1 + endwhile + + return rowNr +endfunction + +function! tablemode#spreadsheet#RowCount(line) "{{{2 + let line = tablemode#utils#line(a:line) + + let [tline, totalRowCount] = [line, 0] + while !tablemode#table#IsHeader(tline) && tablemode#table#IsTable(tline) + if tablemode#table#IsRow(tline) | let totalRowCount += 1 | endif + let tline -= 1 + endwhile + + let tline = line + 1 + while !tablemode#table#IsHeader(tline) && tablemode#table#IsTable(tline) + if tablemode#table#IsRow(tline) | let totalRowCount += 1 | endif + let tline += 1 + endwhile + + return totalRowCount +endfunction + +function! tablemode#spreadsheet#ColumnNr(pos) "{{{2 + let pos = [] + if type(a:pos) == type('') + let pos = [line(a:pos), col(a:pos)] + elseif type(a:pos) == type([]) + let pos = a:pos + else + return 0 + endif + let row_start = stridx(getline(pos[0]), g:table_mode_separator) + return tablemode#utils#strlen(substitute(getline(pos[0])[(row_start):pos[1]-2], '[^' . g:table_mode_separator . ']', '', 'g')) +endfunction + +function! tablemode#spreadsheet#ColumnCount(line) "{{{2 + let line = tablemode#utils#line(a:line) + + return tablemode#utils#strlen(substitute(getline(line), '[^' . g:table_mode_separator . ']', '', 'g'))-1 +endfunction + +function! tablemode#spreadsheet#IsFirstCell() "{{{2 + return tablemode#spreadsheet#ColumnNr('.') ==# 1 +endfunction + +function! tablemode#spreadsheet#IsLastCell() "{{{2 + return tablemode#spreadsheet#ColumnNr('.') ==# tablemode#spreadsheet#ColumnCount('.') +endfunction + +function! tablemode#spreadsheet#MoveToStartOfCell() "{{{2 + if getline('.')[col('.')-1] ==# g:table_mode_separator && !tablemode#spreadsheet#IsLastCell() + normal! 2l + else + execute 'normal! F' . g:table_mode_separator . '2l' + endif +endfunction + +function! tablemode#spreadsheet#DeleteColumn() "{{{2 + if tablemode#table#IsRow('.') + for i in range(v:count1) + call tablemode#spreadsheet#MoveToStartOfCell() + call tablemode#spreadsheet#MoveToFirstRow() + silent! execute "normal! h\<C-V>f" . g:table_mode_separator + call tablemode#spreadsheet#MoveToLastRow() + normal! d + endfor + + call tablemode#table#Realign('.') + endif +endfunction + +function! tablemode#spreadsheet#DeleteRow() "{{{2 + if tablemode#table#IsRow('.') + for i in range(v:count1) + if tablemode#table#IsRow('.') + normal! dd + endif + + if !tablemode#table#IsRow('.') + normal! k + endif + endfor + + call tablemode#table#Realign('.') + endif +endfunction + +function! tablemode#spreadsheet#Sum(range, ...) abort "{{{2 + let args = copy(a:000) + call insert(args, a:range) + return s:Sum(call('tablemode#spreadsheet#cell#GetCellRange', args)) +endfunction + +function! tablemode#spreadsheet#Average(range, ...) abort "{{{2 + let args = copy(a:000) + call insert(args, a:range) + return s:Average(call('tablemode#spreadsheet#cell#GetCellRange', args)) +endfunction + +function! tablemode#spreadsheet#Sort(bang, ...) "{{{2 + let opts = a:0 ? a:1 : '' + let bang = a:bang ? '!' : '' + let [firstRow, lastRow] = [tablemode#spreadsheet#GetFirstRow('.'), tablemode#spreadsheet#GetLastRow('.')] + call tablemode#spreadsheet#MoveToStartOfCell() + exec ':'.firstRow.','.lastRow . 'sort'.bang opts '/.*\%'.col('.').'v/' +endfunction diff --git a/vim/bundle/vim-table-mode/autoload/tablemode/spreadsheet/cell.vim b/vim/bundle/vim-table-mode/autoload/tablemode/spreadsheet/cell.vim new file mode 100644 index 0000000..d1d912b --- /dev/null +++ b/vim/bundle/vim-table-mode/autoload/tablemode/spreadsheet/cell.vim @@ -0,0 +1,258 @@ +" Private Functions {{{1 +" function! s:ParseRange(range, ...) {{{2 +" range: A string representing range of cells. +" - Can be row1:row2 for values in the current columns in those rows. +" - Can be row1,col1:row2,col2 for range between row1,col1 till +" row2,col2. +function! s:ParseRange(range, ...) + if a:0 < 1 + let default_col = tablemode#spreadsheet#ColumnNr('.') + elseif a:0 < 2 + let default_col = a:1 + endif + + if type(a:range) != type('') + let range = string(a:range) + else + let range = a:range + endif + + let [rowcol1, rowcol2] = split(range, ':') + let [rcs1, rcs2] = [map(split(rowcol1, ','), 'str2nr(v:val)'), map(split(rowcol2, ','), 'str2nr(v:val)')] + + if len(rcs1) == 2 + let [row1, col1] = rcs1 + else + let [row1, col1] = [rcs1[0], default_col] + endif + + if len(rcs2) == 2 + let [row2, col2] = rcs2 + else + let [row2, col2] = [rcs2[0], default_col] + endif + + return [row1, col1, row2, col2] +endfunction + + +" Public Functions {{{1 +" function! tablemode#spreadsheet#cell#GetCells() - Function to get values of cells in a table {{{2 +" tablemode#spreadsheet#GetCells(row) - Get values of all cells in a row as a List. +" tablemode#spreadsheet#GetCells(0, col) - Get values of all cells in a column as a List. +" tablemode#spreadsheet#GetCells(row, col) - Get the value of table cell by given row, col. +function! tablemode#spreadsheet#cell#GetCells(line, ...) abort + let line = tablemode#utils#line(a:line) + + if tablemode#table#IsRow(line) + if a:0 < 1 + let [row, colm] = [line, 0] + elseif a:0 < 2 + let [row, colm] = [a:1, 0] + elseif a:0 < 3 + let [row, colm] = a:000 + endif + + let first_row = tablemode#spreadsheet#GetFirstRow(line) + let last_row = tablemode#spreadsheet#GetLastRow(line) + if row == 0 + let values = [] + let line = first_row + while tablemode#table#IsTable(line) + if tablemode#table#IsRow(line) + let row_line = getline(line)[stridx(getline(line), g:table_mode_separator):strridx(getline(line), g:table_mode_separator)] + call add(values, tablemode#utils#strip(get(split(row_line, g:table_mode_separator), colm>0?colm-1:colm, ''))) + endif + let line += 1 + endwhile + return values + else + let row_nr = 0 + let row_diff = row > 0 ? 1 : -1 + let line = row > 0 ? first_row : last_row + while tablemode#table#IsTable(line) + if tablemode#table#IsRow(line) + let row_nr += row_diff + if row ==# row_nr | break | endif + endif + let line += row_diff + endwhile + + let row_line = getline(line)[stridx(getline(line), g:table_mode_separator):strridx(getline(line), g:table_mode_separator)] + if colm == 0 + return map(split(row_line, g:table_mode_separator), 'tablemode#utils#strip(v:val)') + else + let split_line = split(row_line, g:table_mode_separator) + return tablemode#utils#strip(get(split(row_line, g:table_mode_separator), colm>0?colm-1:colm, '')) + endif + endif + endif +endfunction + +function! tablemode#spreadsheet#cell#GetCell(...) "{{{2 + if a:0 == 0 + let [row, colm] = [tablemode#spreadsheet#RowNr('.'), tablemode#spreadsheet#ColumnNr('.')] + elseif a:0 == 2 + let [row, colm] = [a:1, a:2] + endif + + return tablemode#spreadsheet#cell#GetCells('.', row, colm) +endfunction + +function! tablemode#spreadsheet#cell#GetRow(row, ...) abort "{{{2 + let line = a:0 ? a:1 : '.' + return tablemode#spreadsheet#cell#GetCells(line, a:row) +endfunction + +function! tablemode#spreadsheet#cell#GetRowColumn(col, ...) abort "{{{2 + let line = a:0 ? a:1 : '.' + let row = tablemode#spreadsheet#RowNr('.') + return tablemode#spreadsheet#cell#GetCells(line, row, a:col) +endfunction + +function! tablemode#spreadsheet#cell#GetColumn(col, ...) abort "{{{2 + let line = a:0 ? a:1 : '.' + return tablemode#spreadsheet#cell#GetCells(line, 0, a:col) +endfunction + +function! tablemode#spreadsheet#cell#GetColumnRow(row, ...) abort "{{{2 + let line = a:0 ? a:1 : '.' + let col = tablemode#spreadsheet#ColumnNr('.') + return tablemode#spreadsheet#cell#GetCells(line, a:row, col) +endfunction + +function! tablemode#spreadsheet#cell#GetCellRange(range, ...) abort "{{{2 + if a:0 < 1 + let [line, colm] = ['.', tablemode#spreadsheet#ColumnNr('.')] + elseif a:0 < 2 + let [line, colm] = [a:1, tablemode#spreadsheet#ColumnNr('.')] + elseif a:0 < 3 + let [line, colm] = [a:1, a:2] + else + call tablemode#utils#throw('Invalid Range') + endif + + let values = [] + + if tablemode#table#IsRow(line) + let [row1, col1, row2, col2] = s:ParseRange(a:range, colm) + + if row1 == row2 + if col1 == col2 + call add(values, tablemode#spreadsheet#cell#GetCells(line, row1, col1)) + else + let values = tablemode#spreadsheet#cell#GetRow(row1, line)[(col1-1):(col2-1)] + endif + else + if col1 == col2 + let values = tablemode#spreadsheet#cell#GetColumn(col1, line)[(row1-1):(row2-1)] + else + let tcol = col1 + while tcol <= col2 + call add(values, tablemode#spreadsheet#cell#GetColumn(tcol, line)[(row1-1):(row2-1)]) + let tcol += 1 + endwhile + endif + endif + endif + + return values +endfunction + +function! tablemode#spreadsheet#cell#SetCell(val, ...) "{{{2 + if a:0 == 0 + let [line, row, colm] = ['.', tablemode#spreadsheet#RowNr('.'), tablemode#spreadsheet#ColumnNr('.')] + elseif a:0 == 2 + let [line, row, colm] = ['.', a:1, a:2] + elseif a:0 == 3 + let [line, row, colm] = a:000 + endif + + " Account for negative values to reference from relatively from the last + if row < 0 | let row = tablemode#spreadsheet#RowCount(line) + row + 1 | endif + if colm < 0 | let colm = tablemode#spreadsheet#ColumnCount(line) + colm + 1 | endif + + if tablemode#table#IsRow(line) + let line = tablemode#spreadsheet#LineNr(line, row) + let line_val = getline(line) + let cstartexpr = tablemode#table#StartCommentExpr() + let values = split(getline(line)[stridx(line_val, g:table_mode_separator):strridx(line_val, g:table_mode_separator)], g:table_mode_separator) + if len(values) < colm | return | endif + let values[colm-1] = a:val + let line_value = g:table_mode_separator . join(values, g:table_mode_separator) . g:table_mode_separator + if tablemode#utils#strlen(cstartexpr) > 0 && line_val =~# cstartexpr + let sce = matchstr(line_val, tablemode#table#StartCommentExpr()) + let ece = matchstr(line_val, tablemode#table#EndCommentExpr()) + let line_value = sce . line_value . ece + endif + call setline(line, line_value) + call tablemode#table#Realign(line) + endif +endfunction +function! tablemode#spreadsheet#cell#TextObject(inner) "{{{2 + if tablemode#table#IsRow('.') + call tablemode#spreadsheet#MoveToStartOfCell() + if a:inner + normal! v + call search('[^' . g:table_mode_separator . ']\ze\s*' . g:table_mode_separator) + else + execute 'normal! vf' . g:table_mode_separator . 'l' + endif + endif +endfunction +function! tablemode#spreadsheet#cell#Motion(direction, ...) "{{{2 + let l:count = a:0 ? a:1 : v:count1 + if tablemode#table#IsRow('.') + for ii in range(l:count) + if a:direction ==# 'l' + if tablemode#spreadsheet#IsLastCell() + if !tablemode#table#IsRow(line('.') + 1) && (tablemode#table#IsBorder(line('.') + 1) && !tablemode#table#IsRow(line('.') + 2)) + return + endif + call tablemode#spreadsheet#cell#Motion('j', 1) + normal! 0 + endif + + " If line starts with g:table_mode_separator + if getline('.')[col('.')-1] ==# g:table_mode_separator + normal! 2l + else + execute 'normal! f' . g:table_mode_separator . '2l' + endif + elseif a:direction ==# 'h' + if tablemode#spreadsheet#IsFirstCell() + if !tablemode#table#IsRow(line('.') - 1) && (tablemode#table#IsBorder(line('.') - 1) && !tablemode#table#IsRow(line('.') - 2)) + return + endif + call tablemode#spreadsheet#cell#Motion('k', 1) + normal! $ + endif + + " If line ends with g:table_mode_separator + if getline('.')[col('.')-1] ==# g:table_mode_separator + execute 'normal! F' . g:table_mode_separator . '2l' + else + execute 'normal! 2F' . g:table_mode_separator . '2l' + endif + elseif a:direction ==# 'j' + if tablemode#table#IsRow(line('.') + 1) + " execute 'normal! ' . 1 . 'j' + normal! j + elseif tablemode#table#IsBorder(line('.') + 1) && tablemode#table#IsRow(line('.') + 2) + " execute 'normal! ' . 2 . 'j' + normal! 2j + endif + elseif a:direction ==# 'k' + if tablemode#table#IsRow(line('.') - 1) + " execute 'normal! ' . 1 . 'k' + normal! k + elseif tablemode#table#IsBorder(line('.') - 1) && tablemode#table#IsRow(line('.') - 2) + " execute 'normal! ' . (1 + 1) . 'k' + normal! 2k + endif + endif + endfor + endif +endfunction + +" vim: sw=2 sts=2 fdl=0 fdm=marker diff --git a/vim/bundle/vim-table-mode/autoload/tablemode/spreadsheet/formula.vim b/vim/bundle/vim-table-mode/autoload/tablemode/spreadsheet/formula.vim new file mode 100644 index 0000000..8271b5d --- /dev/null +++ b/vim/bundle/vim-table-mode/autoload/tablemode/spreadsheet/formula.vim @@ -0,0 +1,122 @@ +" Private Functions {{{1 + +" Public Functions {{{1 +function! tablemode#spreadsheet#formula#Add(...) "{{{2 + let fr = a:0 ? a:1 : input('f=') + let row = tablemode#spreadsheet#RowNr('.') + let colm = tablemode#spreadsheet#ColumnNr('.') + let indent = indent('.') + let indent_str = repeat(' ', indent) + + if fr !=# '' + let fr = '$' . row . ',' . colm . '=' . fr + let fline = tablemode#spreadsheet#GetLastRow('.') + 1 + if tablemode#table#IsBorder(fline) | let fline += 1 | endif + let cursor_pos = [line('.'), col('.')] + if getline(fline) =~# 'tmf: ' + " Comment line correctly + let line_val = getline(fline) + let start_pos = match(line_val, tablemode#table#StartCommentExpr()) + let end_pos = match(line_val, tablemode#table#EndCommentExpr()) + if empty(end_pos) | let end_pos = len(line_val) | endif + let line_expr = strpart(line_val, start_pos, end_pos) + let sce = matchstr(line_val, tablemode#table#StartCommentExpr() . '\zs') + let ece = matchstr(line_val, tablemode#table#EndCommentExpr()) + call setline(fline, sce . line_expr . '; ' . fr . ece) + else + let cstring = &commentstring + let [cmss, cmse] = ['', ''] + if len(cstring) > 0 + let cms = split(cstring, '%s') + if len(cms) == 2 + let [cmss, cmse] = cms + else + let [cmss, cmse] = [cms[0], ''] + endif + endif + let fr = indent_str . cmss . ' tmf: ' . fr . ' ' . cmse + call append(fline-1, fr) + call cursor(cursor_pos) + endif + call tablemode#spreadsheet#formula#EvaluateFormulaLine() + endif +endfunction + +function! tablemode#spreadsheet#formula#EvaluateExpr(expr, line) abort "{{{2 + let line = tablemode#utils#line(a:line) + let [target, expr] = map(split(a:expr, '='), 'tablemode#utils#strip(v:val)') + let cell = substitute(target, '\$', '', '') + if cell =~# ',' + let [row, colm] = map(split(cell, ','), 'str2nr(v:val)') + else + let [row, colm] = [0, str2nr(cell)] + endif + + if expr =~# 'Sum(.*)' + let expr = substitute(expr, 'Sum(\([^)]*\))', 'tablemode#spreadsheet#Sum("\1",'.line.','.colm.')', 'g') + endif + + if expr =~# 'Average(.*)' + let expr = substitute(expr, 'Average(\([^)]*\))', 'tablemode#spreadsheet#Average("\1",'.line.','.colm.')', 'g') + endif + + if expr =~# '\$\d\+,\d\+' + let expr = substitute(expr, '\$\(\d\+\),\(\d\+\)', + \ '\=str2float(tablemode#spreadsheet#cell#GetCells(line, submatch(1), submatch(2)))', 'g') + endif + + if cell =~# ',' + if expr =~# '\$' + let expr = substitute(expr, '\$\(\d\+\)', + \ '\=str2float(tablemode#spreadsheet#cell#GetCells(line, row, submatch(1)))', 'g') + endif + call tablemode#spreadsheet#cell#SetCell(eval(expr), line, row, colm) + else + let [row, line] = [1, tablemode#spreadsheet#GetFirstRow(line)] + while tablemode#table#IsRow(line) + let texpr = expr + if expr =~# '\$' + let texpr = substitute(texpr, '\$\(\d\+\)', + \ '\=str2float(tablemode#spreadsheet#cell#GetCells(line, row, submatch(1)))', 'g') + endif + + call tablemode#spreadsheet#cell#SetCell(eval(texpr), line, row, colm) + let row += 1 + let line += 1 + endwhile + endif +endfunction + +function! tablemode#spreadsheet#formula#EvaluateFormulaLine() abort "{{{2 + let exprs = [] + let cstring = &commentstring + let matchexpr = '' + if len(cstring) > 0 + let cms = split(cstring, '%s') + if len(cms) == 2 + let matchexpr = '^\s*' . escape(cms[0], '/*') . '\s*tmf: \zs.*\ze' . escape(cms[1], '/*') . '\s*$' + else + let matchexpr = '^\s*' . escape(cms[0], '/*') . '\s*tmf: \zs.*$' + endif + else + let matchexpr = '^\s* tmf: \zs.*$' + endif + if tablemode#table#IsRow('.') " We're inside the table + let line = tablemode#spreadsheet#GetLastRow('.') + let fline = line + 1 + if tablemode#table#IsBorder(fline) | let fline += 1 | endif + if getline(fline) =~# 'tmf: ' + let exprs = split(matchstr(getline(fline), matchexpr), ';') + endif + elseif getline('.') =~# 'tmf: ' " We're on the formula line + let line = line('.') - 1 + if tablemode#table#IsBorder(line) | let line -= 1 | endif + if tablemode#table#IsRow(line) + let exprs = split(matchstr(getline('.'), matchexpr), ';') + endif + endif + + for expr in exprs + call tablemode#spreadsheet#formula#EvaluateExpr(expr, line) + endfor +endfunction diff --git a/vim/bundle/vim-table-mode/autoload/tablemode/table.vim b/vim/bundle/vim-table-mode/autoload/tablemode/table.vim new file mode 100644 index 0000000..82344b1 --- /dev/null +++ b/vim/bundle/vim-table-mode/autoload/tablemode/table.vim @@ -0,0 +1,198 @@ +" Private Functions {{{1 +function! s:BorderExpr() "{{{2 + return tablemode#table#StartExpr() . + \ '[' . g:table_mode_corner . g:table_mode_corner_corner . ']' . + \ '[' . escape(g:table_mode_fillchar . g:table_mode_header_fillchar . g:table_mode_corner . g:table_mode_align_char, '-') . ']\+' . + \ '[' . g:table_mode_corner . g:table_mode_corner_corner . ']' . + \ tablemode#table#EndExpr() +endfunction + +function! s:DefaultBorder() "{{{2 + if tablemode#IsActive() + return g:table_mode_corner_corner . g:table_mode_fillchar . g:table_mode_corner . g:table_mode_fillchar . g:table_mode_corner_corner + else + return '' + endif +endfunction + +function! s:GenerateHeaderBorder(line) "{{{2 + let line = tablemode#utils#line(a:line) + if tablemode#table#IsRow(line - 1) || tablemode#table#IsRow(line + 1) + let line_val = '' + if tablemode#table#IsRow(line + 1) + let line_val = getline(line + 1) + endif + if tablemode#table#IsRow(line - 1) && tablemode#utils#strlen(line_val) < tablemode#utils#strlen(getline(line - 1)) + let line_val = getline(line - 1) + endif + if tablemode#utils#strlen(line_val) <= 1 | return s:DefaultBorder() | endif + + let border = substitute(line_val[stridx(line_val, g:table_mode_separator):strridx(line_val, g:table_mode_separator)], g:table_mode_separator, g:table_mode_corner, 'g') + " To accurately deal with unicode double width characters + if tablemode#table#IsHeader(line - 1) + let fill_columns = map(split(border, g:table_mode_corner), 'repeat(g:table_mode_header_fillchar, tablemode#utils#StrDisplayWidth(v:val))') + else + let fill_columns = map(split(border, g:table_mode_corner), 'repeat(g:table_mode_fillchar, tablemode#utils#StrDisplayWidth(v:val))') + endif + let border = g:table_mode_corner . join(fill_columns, g:table_mode_corner) . g:table_mode_corner + let border = substitute(border, '^' . g:table_mode_corner . '\(.*\)' . g:table_mode_corner . '$', g:table_mode_corner_corner . '\1' . g:table_mode_corner_corner, '') + + " Incorporate header alignment chars + if getline(line) =~# g:table_mode_align_char + let pat = '[' . g:table_mode_corner_corner . g:table_mode_corner . ']' + let hcols = tablemode#align#Split(getline(line), pat) + let gcols = tablemode#align#Split(border, pat) + + for idx in range(len(hcols)) + if hcols[idx] =~# g:table_mode_align_char + " center align + if hcols[idx] =~# g:table_mode_align_char . '[^'.g:table_mode_align_char.']\+' . g:table_mode_align_char + let gcols[idx] = g:table_mode_align_char . gcols[idx][1:-2] . g:table_mode_align_char + elseif hcols[idx] =~# g:table_mode_align_char . '$' + let gcols[idx] = gcols[idx][:-2] . g:table_mode_align_char + else + let gcols[idx] = g:table_mode_align_char . gcols[idx][1:] + endif + endif + endfor + let border = join(gcols, '') + endif + + let cstartexpr = tablemode#table#StartCommentExpr() + if tablemode#utils#strlen(cstartexpr) > 0 && getline(line) =~# cstartexpr + let sce = matchstr(line_val, tablemode#table#StartCommentExpr()) + let ece = matchstr(line_val, tablemode#table#EndCommentExpr()) + return sce . border . ece + elseif getline(line) =~# tablemode#table#StartExpr() + let indent = matchstr(line_val, tablemode#table#StartExpr()) + return indent . border + else + return border + endif + else + return s:DefaultBorder() + endif +endfunction + +" Public Functions {{{1 +function! tablemode#table#GetCommentStart() "{{{2 + let cstring = &commentstring + if tablemode#utils#strlen(cstring) > 0 + return substitute(split(cstring, '%s')[0], '[^()]', '\\\0', 'g') + else + return '' + endif +endfunction + +function! tablemode#table#StartCommentExpr() "{{{2 + let cstartexpr = tablemode#table#GetCommentStart() + if tablemode#utils#strlen(cstartexpr) > 0 + return '^\s*' . cstartexpr . '\s*' + else + return '' + endif +endfunction + +function! tablemode#table#GetCommentEnd() "{{{2 + let cstring = &commentstring + if tablemode#utils#strlen(cstring) > 0 + let cst = split(cstring, '%s') + if len(cst) == 2 + return substitute(cst[1], '[^()]', '\\\0', 'g') + else + return '' + endif + else + return '' + endif +endfunction + +function! tablemode#table#EndCommentExpr() "{{{2 + let cendexpr = tablemode#table#GetCommentEnd() + if tablemode#utils#strlen(cendexpr) > 0 + return '.*\zs\s\+' . cendexpr . '\s*$' + else + return '' + endif +endfunction + +function! tablemode#table#StartExpr() "{{{2 + let cstart = tablemode#table#GetCommentStart() + if tablemode#utils#strlen(cstart) > 0 + return '^\s*\(' . cstart . '\)\?\s*' + else + return '^\s*' + endif +endfunction + +function! tablemode#table#EndExpr() "{{{2 + let cend = tablemode#table#GetCommentEnd() + if tablemode#utils#strlen(cend) > 0 + return '\s*\(\s\+' . cend . '\)\?\s*$' + else + return '\s*$' + endif +endfunction + +function! tablemode#table#IsBorder(line) "{{{2 + return !empty(getline(a:line)) && getline(a:line) =~# s:BorderExpr() +endfunction + +function! tablemode#table#IsHeader(line) "{{{2 + let line = tablemode#utils#line(a:line) + " if line <= 0 || line > line('$') | return 0 | endif + return tablemode#table#IsRow(line) + \ && !tablemode#table#IsRow(line-1) + \ && !tablemode#table#IsRow(line-2) + \ && !tablemode#table#IsBorder(line-2) + \ && tablemode#table#IsBorder(line+1) +endfunction + +function! tablemode#table#IsRow(line) "{{{2 + return !tablemode#table#IsBorder(a:line) && getline(a:line) =~# (tablemode#table#StartExpr() . g:table_mode_separator) . '[^' . g:table_mode_separator . ']\+' +endfunction + +function! tablemode#table#IsTable(line) "{{{2 + return tablemode#table#IsRow(a:line) || tablemode#table#IsBorder(a:line) +endfunction + +function! tablemode#table#AddBorder(line) "{{{2 + call setline(a:line, s:GenerateHeaderBorder(a:line)) +endfunction + +function! tablemode#table#Realign(line) "{{{2 + let line = tablemode#utils#line(a:line) + + let lines = [] + let [lnum, blines] = [line, []] + while tablemode#table#IsTable(lnum) + if tablemode#table#IsBorder(lnum) + call insert(blines, lnum) + let lnum -= 1 + continue + endif + call insert(lines, {'lnum': lnum, 'text': getline(lnum)}) + let lnum -= 1 + endwhile + + let lnum = line + 1 + while tablemode#table#IsTable(lnum) + if tablemode#table#IsBorder(lnum) + call add(blines, lnum) + let lnum += 1 + continue + endif + call add(lines, {'lnum': lnum, 'text': getline(lnum)}) + let lnum += 1 + endwhile + + let lines = tablemode#align#Align(lines) + + for aline in lines + call setline(aline.lnum, aline.text) + endfor + + for bline in blines + call tablemode#table#AddBorder(bline) + endfor +endfunction diff --git a/vim/bundle/vim-table-mode/autoload/tablemode/utils.vim b/vim/bundle/vim-table-mode/autoload/tablemode/utils.vim new file mode 100644 index 0000000..215da6c --- /dev/null +++ b/vim/bundle/vim-table-mode/autoload/tablemode/utils.vim @@ -0,0 +1,49 @@ +" Private Functions {{{1 + +" Public Functions {{{1 +function! tablemode#utils#throw(string) abort "{{{2 + let v:errmsg = 'table-mode: ' . a:string + throw v:errmsg +endfunction + +function! tablemode#utils#line(row) "{{{2 + if type(a:row) == type('') + return line(a:row) + else + return a:row + endif +endfunction + +function! tablemode#utils#strip(string) "{{{2 + return matchstr(a:string, '^\s*\zs.\{-}\ze\s*$') +endfunction + +" function! tablemode#utils#strlen {{{2 +" To count multibyte characters accurately +function! tablemode#utils#strlen(text) + return strlen(substitute(a:text, '.', 'x', 'g')) +endfunction + +function! tablemode#utils#StrDisplayWidth(string) "{{{2 + if exists('*strdisplaywidth') + return strdisplaywidth(a:string) + else + " Implement the tab handling part of strdisplaywidth for vim 7.2 and + " earlier - not much that can be done about handling doublewidth + " characters. + let rv = 0 + let i = 0 + + for char in split(a:string, '\zs') + if char == "\t" + let rv += &ts - i + let i = 0 + else + let rv += 1 + let i = (i + 1) % &ts + endif + endfor + + return rv + endif +endfunction |