diff --git a/autoload/tablemode.vim b/autoload/tablemode.vim index 92c8f97..607d09f 100644 --- a/autoload/tablemode.vim +++ b/autoload/tablemode.vim @@ -1,9 +1,10 @@ " ============================== Header ==================================={{{ +" File: autoload/tablemode.vim " Description: Table mode for vim for creating neat tables. " Author: Dhruva Sagar " License: MIT (http://www.opensource.org/licenses/MIT) " Website: http://github.com/dhruvasagar/vim-table-mode -" Version: 2.4.0 +" Version: 3.0 " Note: This plugin was heavily inspired by the 'CucumberTables.vim' " (https://gist.github.com/tpope/287147) plugin by Tim Pope and " uses a small amount of code from it. @@ -75,7 +76,7 @@ endfunction function! s:Sum(list) "{{{3 let result = 0 for item in a:list - if type(item) == type(1) + if type(item) == type(1) || type(item) == type(1.0) let result = result + item elseif type(item) == type('') let result = result + str2nr(item) @@ -95,7 +96,7 @@ endfunction function! s:GetCommentStart() "{{{3 let cstring = &commentstring if s:Strlen(cstring) > 0 - return substitute(split(substitute(cstring, '%s', ' ', 'g'))[0], '.', '\\\0', 'g') + return substitute(split(cstring, '%s')[0], '.', '\\\0', 'g') else return '' endif @@ -131,11 +132,7 @@ endfunction " }}}3 function! s:RowGap() "{{{3 - if g:table_mode_border - return 2 - else - return 1 - endif + return g:table_mode_border ? 2 : 1 endfunction " }}}3 @@ -242,8 +239,7 @@ function! s:GetFirstRow(line) "{{{2 if tablemode#IsATableRow(a:line) let line = s:Line(a:line) - while line > 0 - if !tablemode#IsATableRow(line - s:RowGap()) | break | endif + while tablemode#IsATableRow(line - s:RowGap()) let line = line - s:RowGap() endwhile @@ -263,8 +259,7 @@ function! s:GetLastRow(line) "{{{2 if tablemode#IsATableRow(a:line) let line = s:Line(a:line) - while line <= line('$') - if !tablemode#IsATableRow(line + s:RowGap()) | break | endif + while tablemode#IsATableRow(line+ s:RowGap()) let line = line + s:RowGap() endwhile @@ -305,26 +300,26 @@ function! s:GetCells(line, ...) abort let [row, colm] = a:000 endif - if row > 0 - let line = line + (row - tablemode#RowNr(line)) * s:RowGap() - - if colm > 0 - return s:Strip(split(getline(line), g:table_mode_separator)[colm-1]) - else - return map(split(getline(line), g:table_mode_separator), 's:Strip(v:val)') - endif - elseif colm > 0 + if row == 0 let values = [] let line = s:GetFirstRow(line) - while line <= line('$') - if tablemode#IsATableRow(line) - call add(values, s:Strip(split(getline(line), g:table_mode_separator)[colm-1])) - else - break - endif + while tablemode#IsATableRow(line) + call add(values, s:Strip(split(getline(line), g:table_mode_separator)[colm>0?colm-1:colm])) let line = line + s:RowGap() endwhile return values + else + if row > 0 + let line = line + (row - tablemode#RowNr(line)) * s:RowGap() + else + let line = line + row * s:RowGap() + endif + + if colm == 0 + return map(split(getline(line), g:table_mode_separator), 's:Strip(v:val)') + else + return s:Strip(split(getline(line), g:table_mode_separator)[colm>0?colm-1:colm]) + endif endif endif endfunction @@ -362,26 +357,31 @@ endfunction " }}}2 function! s:GetRow(row, ...) abort "{{{2 - if a:0 < 1 - let line = '.' - elseif a:0 < 2 - let line = a:1 - endif - + let line = a:0 < 1 ? '.' : a:1 return s:GetCells(line, a:row) endfunction " }}}2 -function! s:GetColumn(col, ...) "{{{2 - if a:0 < 1 - let line = '.' - elseif a:0 < 2 - let line = a:1 - endif +function! s:GetRowColumn(col, ...) abort "{{{2 + let line = a:0 < 1 ? '.' : a:1 + let row = tablemode#RowNr('.') + return s:GetCells(line, row, a:col) +endfunction +" }}}2 + +function! s:GetColumn(col, ...) abort "{{{2 + let line = a:0 < 1 ? '.' : a:1 return s:GetCells(line, 0, a:col) endfunction " }}}2 +function! s:GetColumnRow(row, ...) abort "{{{2 + let line = a:0 < 1 ? '.' : a:1 + let col = tablemode#ColumnNr('.') + return s:GetCells(line, a:row, col) +endfunction +" }}}2 + function! s:ParseRange(range, ...) "{{{2 if a:0 < 1 let default_col = tablemode#ColumnNr('.') @@ -448,7 +448,7 @@ function! s:GetCellRange(range, ...) abort let tcol = col1 while tcol <= col2 call add(values, s:GetColumn(tcol, line)[(row1-1):(row2-1)]) - let tcol = tcol + 1 + let tcol += 1 endwhile endif endif @@ -580,6 +580,16 @@ endfunction " Public API {{{1 +function! tablemode#GetLastRow(line) "{{{2 + return s:GetLastRow(a:line) +endfunction +" }}}2 + +function! tablemode#GetFirstRow(line) "{{{2 + return s:GetFirstRow(a:line) +endfunction +" }}}2 + function! tablemode#TableizeInsertMode() "{{{2 if s:IsTableModeActive() && getline('.') =~# (s:StartExpr() . g:table_mode_separator) let column = s:Strlen(substitute(getline('.')[0:col('.')], '[^' . g:table_mode_separator . ']', '', 'g')) @@ -613,7 +623,7 @@ endfunction function! tablemode#TableizeRange(...) range "{{{2 let shift = 1 - if g:table_mode_border | let shift = shift + 1 | endif + if g:table_mode_border | let shift += 1 | endif call s:Tableizeline(a:firstline, a:1) undojoin " The first one causes 2 extra lines for top & bottom border while the @@ -644,24 +654,16 @@ function! tablemode#TableRealign(line) "{{{2 let [lnums, lines] = [[], []] let tline = line - while tline > 0 - if tablemode#IsATableRow(tline) - call insert(lnums, tline) - call insert(lines, getline(tline)) - else - break - endif + while tablemode#IsATableRow(tline) + call insert(lnums, tline) + call insert(lines, getline(tline)) let tline = tline - s:RowGap() endwhile let tline = line + s:RowGap() - while tline <= line('$') - if tablemode#IsATableRow(tline) - call add(lnums, tline) - call add(lines, getline(tline)) - else - break - endif + while tablemode#IsATableRow(tline) + call add(lnums, tline) + call add(lines, getline(tline)) let tline = tline + s:RowGap() endwhile @@ -685,22 +687,14 @@ function! tablemode#RowCount(line) "{{{2 let line = s:Line(a:line) let [tline, totalRowCount] = [line, 0] - while tline > 0 - if tablemode#IsATableRow(tline) - let totalRowCount = totalRowCount + 1 - else - break - endif + while tablemode#IsATableRow(tline) + let totalRowCount += 1 let tline = tline - s:RowGap() endwhile let tline = line + s:RowGap() - while tline <= line('$') - if tablemode#IsATableRow(tline) - let totalRowCount = totalRowCount + 1 - else - break - endif + while tablemode#IsATableRow(tline) + let totalRowCount += 1 let tline = tline + s:RowGap() endwhile @@ -712,12 +706,8 @@ function! tablemode#RowNr(line) "{{{2 let line = s:Line(a:line) let rowNr = 0 - while line > 0 - if tablemode#IsATableRow(line) - let rowNr = rowNr + 1 - else - break - endif + while tablemode#IsATableRow(line) + let rowNr += 1 let line = line - s:RowGap() endwhile @@ -868,6 +858,94 @@ function! tablemode#Average(range, ...) abort "{{{2 endfunction " }}}2 +function! tablemode#AddFormula() "{{{2 + let fr = input('f=') + let row = tablemode#RowNr('.') + let colm = tablemode#ColumnNr('.') + + if fr !=# '' + let fr = '$' . row . ',' . colm . '=' . fr + let fline = tablemode#GetLastRow('.') + s:RowGap() + let cursor_pos = [line('.'), col('.')] + if getline(fline) =~# 'tmf: ' + call setline(fline, getline(fline) . ';' . fr) + else + let cstring = &commentstring + if len(cstring) > 0 + let cstring = split(cstring, '%s')[0] + endif + let fr = cstring . 'tmf: ' . fr + call append(fline-1, fr) + call cursor(cursor_pos) + endif + call tablemode#EvaluateFormulaLine() + endif +endfunction +" }}}2 + +function! tablemode#EvaluateExpr(expr, line) abort "{{{2 + let line = s:Line(a:line) + let [target, expr] = split(a:expr, '=') + let cell = substitute(target, '\$', '', '') + if cell =~# ',' + let [row, colm] = split(cell, ',') + else + let [row, colm] = [0, cell] + endif + + if expr =~# 'Sum(.*)' + let expr = substitute(expr, 'Sum(\(.*\))', 'tablemode#Sum("\1",'.line.','.colm.')', 'g') + endif + + if expr =~# 'Average(.*)' + let expr = substitute(expr, 'Average(\(.*\))', 'tablemode#Average("\1",'.line.','.colm.')', 'g') + endif + + if expr =~# '[\$,]' + let expr = substitute(expr, '\$\(\d\+\),\(\d*\)', + \ '\=str2float(s:GetCells(line, submatch(1), submatch(2)))', 'g') + endif + + if cell =~# ',' + call s:SetCell(eval(expr), line, row, colm) + else + let [row, line] = [1, s:GetFirstRow(line)] + while tablemode#IsATableRow(line) + if expr =~# '\$' + let texpr = substitute(expr, '\$\(\d\+\)', + \ '\=str2float(s:GetCells(line, row, submatch(1)))', 'g') + else + let texpr = expr + endif + + call s:SetCell(eval(texpr), line, row, colm) + let row += 1 + let line += s:RowGap() + endwhile + endif +endfunction +" }}}2 + +function! tablemode#EvaluateFormulaLine() "{{{2 + let exprs = [] + if tablemode#IsATableRow('.') " We're inside the table + let line = s:GetLastRow('.') + if getline(line + s:RowGap()) =~# 'tmf: ' + let exprs = split(matchstr(getline(line + s:RowGap()), 'tmf: \zs.*'), ';') + endif + elseif getline('.') =~# 'tmf: ' " We're on the formula line + let line = line('.') - s:RowGap() + if tablemode#IsATableRow(line) + let exprs = split(matchstr(getline('.'), 'tmf: \zs.*'), ';') + endif + endif + + for expr in exprs + call tablemode#EvaluateExpr(expr, line) + endfor +endfunction +" }}}2 + " }}}1 " vim: sw=2 sts=2 fdl=0 fdm=marker diff --git a/after/plugin/table-mode.vim b/plugin/table-mode.vim similarity index 77% rename from after/plugin/table-mode.vim rename to plugin/table-mode.vim index e65379b..d44a71e 100644 --- a/after/plugin/table-mode.vim +++ b/plugin/table-mode.vim @@ -25,13 +25,13 @@ if exists('g:loaded_table_mode') endif let g:loaded_table_mode = 1 "}}}1 -" -" Finish if Tabularize plugin is not available {{{1 -if !exists(':Tabularize') - echoerr 'Table Mode depends on Tabularize, ensure that is installed first.' - finish -endif -" }}}1 + +" " Finish if Tabularize plugin is not available {{{1 +" if !exists(':Tabularize') +" echoerr 'Table Mode depends on Tabularize, ensure that is installed first.' +" finish +" endif +" " }}}1 " Avoiding side effects {{{1 let s:save_cpo = &cpo @@ -62,7 +62,7 @@ call s:SetGlobalOptDefault('table_mode_cell_text_object', 'tc') call s:SetGlobalOptDefault('table_mode_delete_row_map', 'tdd') call s:SetGlobalOptDefault('table_mode_delete_column_map', 'tdc') call s:SetGlobalOptDefault('table_mode_add_formula_map', 'tfa') -call s:SetGlobalOptDefault('table_mode_recalculate_map', 'tfr') +call s:SetGlobalOptDefault('table_mode_expr_calc_map', 'tfe') "}}}1 function! s:TableMotion() "{{{1 @@ -73,36 +73,6 @@ function! s:TableMotion() "{{{1 endfunction " }}}1 -let s:tables = {} - -function! s:AddTableFormula() abort "{{{1 - let fr = input('f=') - - if fr !=# '' - let [formula, range] = split(fr) - - let [line, colm] = [line('.'), tablemode#ColumnNr('.')] - let key = join([bufnr('%'), line, colm], ':') - let formula = 'tablemode#'.formula.'('.string(range).','.line.','.colm.')' - - let row = tablemode#RowNr(line) - call tablemode#SetCell(eval(formula), line, row, colm) - - let s:tables[key] = formula - endif -endfunction -" }}}1 - -function! s:RecalculateFormulas() "{{{1 - let formulas = filter(s:tables, 'split(v:key, ":")[0] == string(bufnr("%"))') - for [key, formula] in items(formulas) - let [bufnr, line, colm] = map(split(key, ':'), 'str2nr(v:val)') - let row = tablemode#RowNr(line) - call tablemode#SetCell(eval(formula), line, row, colm) - endfor -endfunction -" }}}1 - " Define Commands & Mappings {{{1 if !g:table_mode_always_active "{{{2 exec "nnoremap " . g:table_mode_toggle_map . @@ -123,6 +93,9 @@ endif command! -nargs=? -range Tableize ,call tablemode#TableizeRange() +command! TableAddFormula call tablemode#AddFormula() +command! TableEvalFormulaLine call tablemode#EvaluateFormulaLine() + execute "xnoremap " . g:table_mode_tableize_map . \ " :Tableize" execute "nnoremap " . g:table_mode_tableize_map . @@ -139,12 +112,10 @@ execute "nnoremap " . g:table_mode_delete_row_map . \ " :call tablemode#DeleteRow()" execute "nnoremap " . g:table_mode_delete_column_map . \ " :call tablemode#DeleteColumn()" - -command! TableFormula call s:AddTableFormula() -command! TableRecalc call s:RecalculateFormulas() - -execute "nnoremap " . g:table_mode_add_formula_map . " :TableFormula" -execute "nnoremap " . g:table_mode_recalculate_map . " :TableRecalc" +execute "nnoremap " . g:table_mode_add_formula_map . + \ " :TableAddFormula" +execute "nnoremap " . g:table_mode_expr_calc_map . + \ " :TableEvalFormulaLine" "}}}1 " Avoiding side effects {{{1