diff --git a/CHANGELOG.md b/CHANGELOG.md index a3a2c4e..6935536 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,8 @@ # Change Log +## Version 4.2.0 +* Refactored cells logic out to autoload/tablemode/spreadsheet/cell.vim +* Refactored formula logic out to autoload/tablemode/spreadsheet/formula.vim + ## Version 4.1.0 * Fixed bad references within plugin * Added fixtures diff --git a/README.md b/README.md index 526fa34..dbba7b6 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# VIM Table Mode v4.1.0 [![Build Status](https://travis-ci.org/dhruvasagar/vim-table-mode.png?branch=master)](https://travis-ci.org/dhruvasagar/vim-table-mode) +# VIM Table Mode v4.2.0 [![Build Status](https://travis-ci.org/dhruvasagar/vim-table-mode.png?branch=master)](https://travis-ci.org/dhruvasagar/vim-table-mode) An awesome automatic table creator & formatter allowing one to create neat tables as you type. diff --git a/autoload/tablemode.vim b/autoload/tablemode.vim index 2d38a03..bd64928 100644 --- a/autoload/tablemode.vim +++ b/autoload/tablemode.vim @@ -4,7 +4,6 @@ " Author: Dhruva Sagar " License: MIT (http://www.opensource.org/licenses/MIT) " Website: https://github.com/dhruvasagar/vim-table-mode -" Version: 4.1.0 " Note: This plugin was heavily inspired by the 'CucumberTables.vim' " (https://gist.github.com/tpope/287147) plugin by Tim Pope. " diff --git a/autoload/tablemode/align.vim b/autoload/tablemode/align.vim index d1db1df..d618f45 100644 --- a/autoload/tablemode/align.vim +++ b/autoload/tablemode/align.vim @@ -4,7 +4,6 @@ " Author: Dhruva Sagar " License: MIT (http://www.opensource.org/licenses/MIT) " Website: https://github.com/dhruvasagar/vim-table-mode -" Version: 4.1.0 " Note: This plugin was heavily inspired by the 'CucumberTables.vim' " (https://gist.github.com/tpope/287147) plugin by Tim Pope. " diff --git a/autoload/tablemode/spreadsheet.vim b/autoload/tablemode/spreadsheet.vim index 48b830b..30a6a85 100644 --- a/autoload/tablemode/spreadsheet.vim +++ b/autoload/tablemode/spreadsheet.vim @@ -4,7 +4,6 @@ " Author: Dhruva Sagar " License: MIT (http://www.opensource.org/licenses/MIT) " Website: https://github.com/dhruvasagar/vim-table-mode -" Version: 4.1.0 " Note: This plugin was heavily inspired by the 'CucumberTables.vim' " (https://gist.github.com/tpope/287147) plugin by Tim Pope. " @@ -37,42 +36,6 @@ function! s:Average(list) "{{{2 return s:Sum(a:list)/len(a:list) endfunction -" 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#sid() "{{{2 return maparg('', 'n') @@ -229,115 +192,6 @@ function! tablemode#spreadsheet#GetFirstRow(line) "{{{2 endif endfunction -" function! tablemode#spreadsheet#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#GetCells(line, ...) abort - let line = tablemode#utils#line(a:line) - - if tablemode#table#IsATableRow(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) - if row == 0 - let values = [] - let line = first_row - while tablemode#table#IsATableRow(line) || tablemode#table#IsATableHeader(line) - if tablemode#table#IsATableRow(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 line = first_row - while tablemode#table#IsATableRow(line) || tablemode#table#IsATableHeader(line) - if tablemode#table#IsATableRow(line) - let row_nr += 1 - if row ==# row_nr | break | endif - endif - let line += 1 - 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#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#GetCells('.', row, colm) -endfunction - -function! tablemode#spreadsheet#GetRow(row, ...) abort "{{{2 - let line = a:0 < 1 ? '.' : a:1 - return tablemode#spreadsheet#GetCells(line, a:row) -endfunction - -function! tablemode#spreadsheet#GetRowColumn(col, ...) abort "{{{2 - let line = a:0 < 1 ? '.' : a:1 - let row = tablemode#RowNr('.') - return tablemode#spreadsheet#GetCells(line, row, a:col) -endfunction - -function! tablemode#spreadsheet#GetColumn(col, ...) abort "{{{2 - let line = a:0 < 1 ? '.' : a:1 - return tablemode#spreadsheet#GetCells(line, 0, a:col) -endfunction - -function! tablemode#spreadsheet#GetColumnRow(row, ...) abort "{{{2 - let line = a:0 < 1 ? '.' : a:1 - let col = tablemode#spreadsheet#ColumnNr('.') - return tablemode#spreadsheet#GetCells(line, a:row, col) -endfunction - -function! tablemode#spreadsheet#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 - - if tablemode#table#IsATableRow(line) - let line = tablemode#utils#line(line) + (row - tablemode#spreadsheet#RowNr(line)) * 1 - 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#TableRealign(line) - endif -endfunction - function! tablemode#spreadsheet#DeleteColumn() "{{{2 if tablemode#table#IsATableRow('.') for i in range(v:count1) @@ -368,171 +222,16 @@ function! tablemode#spreadsheet#DeleteRow() "{{{2 endif endfunction -function! tablemode#spreadsheet#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#IsATableRow(line) - let [row1, col1, row2, col2] = s:ParseRange(a:range, colm) - - if row1 == row2 - if col1 == col2 - call add(values, tablemode#spreadsheet#GetCells(line, row1, col1)) - else - let values = tablemode#spreadsheet#GetRow(row1, line)[(col1-1):(col2-1)] - endif - else - if col1 == col2 - let values = tablemode#spreadsheet#GetColumn(col1, line)[(row1-1):(row2-1)] - else - let tcol = col1 - while tcol <= col2 - call add(values, tablemode#spreadsheet#GetColumn(tcol, line)[(row1-1):(row2-1)]) - let tcol += 1 - endwhile - endif - endif - endif - - return values -endfunction - function! tablemode#spreadsheet#Sum(range, ...) abort "{{{2 let args = copy(a:000) call insert(args, a:range) - return s:Sum(call('tablemode#spreadsheet#GetCellRange', args)) + 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#GetCellRange', args)) -endfunction - -function! tablemode#spreadsheet#AddFormula(...) "{{{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#IsATableHeader(fline) | let fline += 1 | endif - let cursor_pos = [line('.'), col('.')] - if getline(fline) =~# 'tmf: ' - " Comment line correctly - let line_val = getline(fline) - let line_expr = line_val[match(line_val, tablemode#table#StartCommentExpr()):match(line_val, tablemode#table#EndCommentExpr())] - 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#EvaluateFormulaLine() - endif -endfunction - -function! tablemode#spreadsheet#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#GetCells(line, submatch(1), submatch(2)))', 'g') - endif - - if cell =~# ',' - if expr =~# '\$' - let expr = substitute(expr, '\$\(\d\+\)', - \ '\=str2float(tablemode#spreadsheet#GetCells(line, row, submatch(1)))', 'g') - endif - call tablemode#spreadsheet#SetCell(eval(expr), line, row, colm) - else - let [row, line] = [1, tablemode#spreadsheet#GetFirstRow(line)] - while tablemode#table#IsATableRow(line) - let texpr = expr - if expr =~# '\$' - let texpr = substitute(texpr, '\$\(\d\+\)', - \ '\=str2float(tablemode#spreadsheet#GetCells(line, row, submatch(1)))', 'g') - endif - - call tablemode#spreadsheet#SetCell(eval(texpr), line, row, colm) - let row += 1 - let line += 1 - endwhile - endif -endfunction - -function! tablemode#spreadsheet#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#IsATableRow('.') " We're inside the table - let line = tablemode#spreadsheet#GetLastRow('.') - let fline = line + 1 - if tablemode#table#IsATableHeader(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#IsATableHeader(line) | let line -= 1 | endif - if tablemode#table#IsATableRow(line) - let exprs = split(matchstr(getline('.'), matchexpr), ';') - endif - endif - - for expr in exprs - call tablemode#spreadsheet#EvaluateExpr(expr, line) - endfor + return s:Average(call('tablemode#spreadsheet#cell#GetCellRange', args)) endfunction function! tablemode#spreadsheet#CellTextObject(inner) "{{{2 diff --git a/autoload/tablemode/spreadsheet/cell.vim b/autoload/tablemode/spreadsheet/cell.vim new file mode 100644 index 0000000..2ec9b01 --- /dev/null +++ b/autoload/tablemode/spreadsheet/cell.vim @@ -0,0 +1,279 @@ +" ============================== Header ====================================== +" File: autoload/tablemode/spreadsheet/cell.vim +" Description: Table mode for vim for creating neat tables. +" Author: Dhruva Sagar +" License: MIT (http://www.opensource.org/licenses/MIT) +" Website: https://github.com/dhruvasagar/vim-table-mode +" Note: This plugin was heavily inspired by the 'CucumberTables.vim' +" (https://gist.github.com/tpope/287147) plugin by Tim Pope. +" +" Copyright Notice: +" Permission is hereby granted to use and distribute this code, +" with or without modifications, provided that this copyright +" notice is copied with it. Like anything else that's free, +" table-mode.vim is provided *as is* and comes with no warranty +" of any kind, either expressed or implied. In no event will +" the copyright holder be liable for any damamges resulting +" from the use of this software. +" ============================================================================= +" 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#sid() "{{{2 + return maparg('', 'n') +endfunction +nnoremap + +function! tablemode#spreadsheet#cell#scope() "{{{2 + return s: +endfunction + +" 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#IsATableRow(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) + if row == 0 + let values = [] + let line = first_row + while tablemode#table#IsATableRow(line) || tablemode#table#IsATableHeader(line) + if tablemode#table#IsATableRow(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 line = first_row + while tablemode#table#IsATableRow(line) || tablemode#table#IsATableHeader(line) + if tablemode#table#IsATableRow(line) + let row_nr += 1 + if row ==# row_nr | break | endif + endif + let line += 1 + 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 < 1 ? '.' : a:1 + return tablemode#spreadsheet#cell#GetCells(line, a:row) +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#IsATableRow(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#GetRowColumn(col, ...) abort "{{{2 + let line = a:0 < 1 ? '.' : 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 < 1 ? '.' : a:1 + return tablemode#spreadsheet#cell#GetCells(line, 0, a:col) +endfunction + +function! tablemode#spreadsheet#cell#GetColumnRow(row, ...) abort "{{{2 + let line = a:0 < 1 ? '.' : a:1 + let col = tablemode#spreadsheet#ColumnNr('.') + return tablemode#spreadsheet#cell#GetCells(line, a:row, col) +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 + + if tablemode#table#IsATableRow(line) + let line = tablemode#utils#line(line) + (row - tablemode#spreadsheet#RowNr(line)) * 1 + 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#TableRealign(line) + endif +endfunction +function! tablemode#spreadsheet#cell#TextObject(inner) "{{{2 + if tablemode#table#IsATableRow('.') + 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#IsATableRow('.') + for ii in range(l:count) + if a:direction ==# 'l' + if tablemode#spreadsheet#IsLastCell() + if !tablemode#table#IsATableRow(line('.') + 1) && (tablemode#table#IsATableHeader(line('.') + 1) && !tablemode#table#IsATableRow(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#IsATableRow(line('.') - 1) && (tablemode#table#IsATableHeader(line('.') - 1) && !tablemode#table#IsATableRow(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#IsATableRow(line('.') + 1) + " execute 'normal! ' . 1 . 'j' + normal! j + elseif tablemode#table#IsATableHeader(line('.') + 1) && tablemode#table#IsATableRow(line('.') + 2) + " execute 'normal! ' . 2 . 'j' + normal! 2j + endif + elseif a:direction ==# 'k' + if tablemode#table#IsATableRow(line('.') - 1) + " execute 'normal! ' . 1 . 'k' + normal! k + elseif tablemode#table#IsATableHeader(line('.') - 1) && tablemode#table#IsATableRow(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/autoload/tablemode/spreadsheet/formula.vim b/autoload/tablemode/spreadsheet/formula.vim new file mode 100644 index 0000000..51e2132 --- /dev/null +++ b/autoload/tablemode/spreadsheet/formula.vim @@ -0,0 +1,147 @@ +" ============================== Header ====================================== +" File: autoload/tablemode/spreadsheet/formula.vim +" Description: Table mode for vim for creating neat tables. +" Author: Dhruva Sagar +" License: MIT (http://www.opensource.org/licenses/MIT) +" Website: https://github.com/dhruvasagar/vim-table-mode +" Note: This plugin was heavily inspired by the 'CucumberTables.vim' +" (https://gist.github.com/tpope/287147) plugin by Tim Pope. +" +" Copyright Notice: +" Permission is hereby granted to use and distribute this code, +" with or without modifications, provided that this copyright +" notice is copied with it. Like anything else that's free, +" table-mode.vim is provided *as is* and comes with no warranty +" of any kind, either expressed or implied. In no event will +" the copyright holder be liable for any damamges resulting +" from the use of this software. +" ============================================================================= + +" Private Functions {{{1 + +" Public Functions {{{1 +function! tablemode#spreadsheet#formula#sid() "{{{2 + return maparg('', 'n') +endfunction +nnoremap + +function! tablemode#spreadsheet#formula#scope() "{{{2 + return s: +endfunction + +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#IsATableHeader(fline) | let fline += 1 | endif + let cursor_pos = [line('.'), col('.')] + if getline(fline) =~# 'tmf: ' + " Comment line correctly + let line_val = getline(fline) + let line_expr = line_val[match(line_val, tablemode#table#StartCommentExpr()):match(line_val, tablemode#table#EndCommentExpr())] + 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#IsATableRow(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#IsATableRow('.') " We're inside the table + let line = tablemode#spreadsheet#GetLastRow('.') + let fline = line + 1 + if tablemode#table#IsATableHeader(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#IsATableHeader(line) | let line -= 1 | endif + if tablemode#table#IsATableRow(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/autoload/tablemode/table.vim b/autoload/tablemode/table.vim index 0863590..e6aebc3 100644 --- a/autoload/tablemode/table.vim +++ b/autoload/tablemode/table.vim @@ -4,7 +4,6 @@ " Author: Dhruva Sagar " License: MIT (http://www.opensource.org/licenses/MIT) " Website: https://github.com/dhruvasagar/vim-table-mode -" Version: 4.1.0 " Note: This plugin was heavily inspired by the 'CucumberTables.vim' " (https://gist.github.com/tpope/287147) plugin by Tim Pope. " diff --git a/autoload/tablemode/utils.vim b/autoload/tablemode/utils.vim index 72b8889..21bce69 100644 --- a/autoload/tablemode/utils.vim +++ b/autoload/tablemode/utils.vim @@ -4,7 +4,6 @@ " Author: Dhruva Sagar " License: MIT (http://www.opensource.org/licenses/MIT) " Website: https://github.com/dhruvasagar/vim-table-mode -" Version: 4.1.0 " Note: This plugin was heavily inspired by the 'CucumberTables.vim' " (https://gist.github.com/tpope/287147) plugin by Tim Pope. " diff --git a/doc/table-mode.txt b/doc/table-mode.txt index 3de0ac8..f442fe0 100644 --- a/doc/table-mode.txt +++ b/doc/table-mode.txt @@ -1,7 +1,7 @@ -*table-mode.txt* Table Mode for easy table formatting. v4.1.0 +*table-mode.txt* Table Mode for easy table formatting. v4.2.0 =============================================================================== Table Mode, THE AWESOME AUTOMATIC TABLE CREATOR & FORMATTER - VERSION 4.1.0 + VERSION 4.2.0 Author: Dhruva Sagar License: MIT diff --git a/plugin/table-mode.vim b/plugin/table-mode.vim index 5023bc6..58290df 100644 --- a/plugin/table-mode.vim +++ b/plugin/table-mode.vim @@ -4,7 +4,6 @@ " Author: Dhruva Sagar " License: MIT (http://www.opensource.org/licenses/MIT) " Website: http://github.com/dhruvasagar/vim-table-mode -" Version: 3.3.3 " Note: This plugin was heavily inspired by the 'CucumberTables.vim' " (https://gist.github.com/tpope/287147) plugin by Tim Pope. " @@ -69,9 +68,9 @@ endif " }}}2 command! -nargs=? -range Tableize ,call tablemode#table#TableizeRange() -command! TableAddFormula call tablemode#spreadsheet#AddFormula() +command! TableAddFormula call tablemode#spreadsheet#formula#Add() command! TableModeRealign call tablemode#spreadsheet#TableRealign('.') -command! TableEvalFormulaLine call tablemode#spreadsheet#EvaluateFormulaLine() +command! TableEvalFormulaLine call tablemode#spreadsheet#formula#EvaluateFormulaLine() nnoremap (table-mode-tableize) :Tableize xnoremap (table-mode-tableize) :Tableize @@ -79,19 +78,19 @@ xnoremap (table-mode-tableize-delimiter) :call tablemode#Tab nnoremap (table-mode-realign) :call tablemode#table#TableRealign('.') -nnoremap (table-mode-motion-up) :call tablemode#table#TableMotion('k') -nnoremap (table-mode-motion-down) :call tablemode#table#TableMotion('j') -nnoremap (table-mode-motion-left) :call tablemode#table#TableMotion('h') -nnoremap (table-mode-motion-right) :call tablemode#table#TableMotion('l') +nnoremap (table-mode-motion-up) :call tablemode#spreadsheet#cell#Motion('k') +nnoremap (table-mode-motion-down) :call tablemode#spreadsheet#cell#Motion('j') +nnoremap (table-mode-motion-left) :call tablemode#spreadsheet#cell#Motion('h') +nnoremap (table-mode-motion-right) :call tablemode#spreadsheet#cell#Motion('l') -onoremap (table-mode-cell-text-object-a) :call tablemode#spreadsheet#CellTextObject(0) -onoremap (table-mode-cell-text-object-i) :call tablemode#spreadsheet#CellTextObject(1) +onoremap (table-mode-cell-text-object-a) :call tablemode#spreadsheet#cell#TextObject(0) +onoremap (table-mode-cell-text-object-i) :call tablemode#spreadsheet#cell#TextObject(1) nnoremap (table-mode-delete-row) :call tablemode#spreadsheet#DeleteRow() nnoremap (table-mode-delete-column) :call tablemode#spreadsheet#DeleteColumn() -nnoremap (table-mode-add-formula) :call tablemode#spreadsheet#AddFormula() -nnoremap (table-mode-eval-formula) :call tablemode#spreadsheet#EvaluateFormulaLine() +nnoremap (table-mode-add-formula) :call tablemode#spreadsheet#formula#Add() +nnoremap (table-mode-eval-formula) :call tablemode#spreadsheet#formula#EvaluateFormulaLine() nnoremap (table-mode-echo-cell) :call TableEchoCell() diff --git a/t/align.vim b/t/align.vim index 92d909b..479f81a 100644 --- a/t/align.vim +++ b/t/align.vim @@ -1,5 +1,5 @@ " vim: fdm=indent -source t/config.vim +source t/config/options.vim call vspec#hint({'scope': 'tablemode#align#scope()', 'sid': 'tablemode#align#sid()'}) diff --git a/t/cell.vim b/t/cell.vim new file mode 100644 index 0000000..32a2407 --- /dev/null +++ b/t/cell.vim @@ -0,0 +1,49 @@ +" vim: fdm=indent +source t/config/options.vim + +call vspec#hint({'scope': 'tablemode#spreadsheet#cell#scope()', 'sid': 'tablemode#spreadsheet#cell#sid()'}) + +describe 'cell API' + before + new + read t/fixtures/sample.txt + end + + it 'should return the cells' + Expect tablemode#spreadsheet#cell#GetCells(2, 1, 1) ==# 'test11' + " Get Rows + Expect tablemode#spreadsheet#cell#GetCells(2, 1) == ['test11', 'test12'] + Expect tablemode#spreadsheet#cell#GetCells(2, 2) == ['test21', 'test22'] + " Get Columns + Expect tablemode#spreadsheet#cell#GetCells(2, 0, 1) == ['test11', 'test21'] + Expect tablemode#spreadsheet#cell#GetCells(2, 0, 2) == ['test12', 'test22'] + end + + it 'should return the cells in a range' + " Entire table as range + Expect tablemode#spreadsheet#cell#GetCellRange('1,1:2,2', 2, 1) == [['test11', 'test21'], ['test12', 'test22']] + + " Get Rows given different seed lines and columns + Expect tablemode#spreadsheet#cell#GetCellRange('1,1:1,2', 2, 1) == ['test11', 'test12'] + Expect tablemode#spreadsheet#cell#GetCellRange('1,1:1,2', 2, 2) == ['test11', 'test12'] + Expect tablemode#spreadsheet#cell#GetCellRange('1,1:1,2', 3, 1) == ['test11', 'test12'] + Expect tablemode#spreadsheet#cell#GetCellRange('1,1:1,2', 3, 2) == ['test11', 'test12'] + Expect tablemode#spreadsheet#cell#GetCellRange('2,1:2,2', 2, 1) == ['test21', 'test22'] + Expect tablemode#spreadsheet#cell#GetCellRange('2,1:2,2', 2, 2) == ['test21', 'test22'] + Expect tablemode#spreadsheet#cell#GetCellRange('2,1:2,2', 3, 1) == ['test21', 'test22'] + Expect tablemode#spreadsheet#cell#GetCellRange('2,1:2,2', 3, 2) == ['test21', 'test22'] + + " Get Columns given different seed lines and column + Expect tablemode#spreadsheet#cell#GetCellRange('1:2', 2, 1) == ['test11', 'test21'] + Expect tablemode#spreadsheet#cell#GetCellRange('1:2', 2, 2) == ['test12', 'test22'] + Expect tablemode#spreadsheet#cell#GetCellRange('1:2', 3, 1) == ['test11', 'test21'] + Expect tablemode#spreadsheet#cell#GetCellRange('1:2', 3, 2) == ['test12', 'test22'] + + " Get Column given negative values in range for representing rows from + " the end, -1 being the second last row. + Expect tablemode#spreadsheet#cell#GetCellRange('1:-1', 2, 1) == ['test11'] + Expect tablemode#spreadsheet#cell#GetCellRange('1:-1', 3, 1) == ['test11'] + Expect tablemode#spreadsheet#cell#GetCellRange('1:-1', 2, 2) == ['test12'] + Expect tablemode#spreadsheet#cell#GetCellRange('1:-1', 3, 2) == ['test12'] + end +end diff --git a/t/config.vim b/t/config/options.vim similarity index 100% rename from t/config.vim rename to t/config/options.vim diff --git a/t/formula.vim b/t/formula.vim new file mode 100644 index 0000000..ba11f9b --- /dev/null +++ b/t/formula.vim @@ -0,0 +1,41 @@ +" vim: fdm=indent +source t/config/options.vim + +call vspec#hint({'scope': 'tablemode#spreadsheet#formula#scope()', 'sid': 'tablemode#spreadsheet#formula#sid()'}) + +describe 'Formulas' + describe 'Add Formula' + before + new + read t/fixtures/formula/sample.txt + end + + it 'should add a formula successfully' + call cursor(6, 15) + call tablemode#spreadsheet#formula#Add("Sum(1:4)") + Expect tablemode#spreadsheet#cell#GetCell() == '125.0' + call cursor(8, 15) + Expect getline('.') == '/* tmf: $5,2=Sum(1:4) */' + + call cursor(7, 15) + call tablemode#spreadsheet#formula#Add("Sum(1:-1)") + Expect tablemode#spreadsheet#cell#GetCell() == '250.0' + call cursor(8, 15) + Expect getline('.') == '/* tmf: $5,2=Sum(1:4) ; $6,2=Sum(1:-1) */' + end + end + + describe 'Evaluate Formula' + before + new + read t/fixtures/formula/formula.txt + end + + it 'should evaluate the formula successfull' + call cursor(6, 15) + call tablemode#spreadsheet#formula#EvaluateFormulaLine() + Expect &modified == 1 + Expect tablemode#spreadsheet#cell#GetCell() == '125.0' + end + end +end diff --git a/t/spreadsheet.vim b/t/spreadsheet.vim index 2a61992..bbb2708 100644 --- a/t/spreadsheet.vim +++ b/t/spreadsheet.vim @@ -1,5 +1,5 @@ " vim: fdm=indent -source t/config.vim +source t/config/options.vim call vspec#hint({'scope': 'tablemode#spreadsheet#scope()', 'sid': 'tablemode#spreadsheet#sid()'}) @@ -34,44 +34,6 @@ describe 'spreadsheet' Expect tablemode#spreadsheet#GetLastRow(2) == 3 Expect tablemode#spreadsheet#GetLastRow(3) == 3 end - - it 'should return the cells' - Expect tablemode#spreadsheet#GetCells(2, 1, 1) ==# 'test11' - " Get Rows - Expect tablemode#spreadsheet#GetCells(2, 1) == ['test11', 'test12'] - Expect tablemode#spreadsheet#GetCells(2, 2) == ['test21', 'test22'] - " Get Columns - Expect tablemode#spreadsheet#GetCells(2, 0, 1) == ['test11', 'test21'] - Expect tablemode#spreadsheet#GetCells(2, 0, 2) == ['test12', 'test22'] - end - - it 'should return the cells in a range' - " Entire table as range - Expect tablemode#spreadsheet#GetCellRange('1,1:2,2', 2, 1) == [['test11', 'test21'], ['test12', 'test22']] - - " Get Rows given different seed lines and columns - Expect tablemode#spreadsheet#GetCellRange('1,1:1,2', 2, 1) == ['test11', 'test12'] - Expect tablemode#spreadsheet#GetCellRange('1,1:1,2', 2, 2) == ['test11', 'test12'] - Expect tablemode#spreadsheet#GetCellRange('1,1:1,2', 3, 1) == ['test11', 'test12'] - Expect tablemode#spreadsheet#GetCellRange('1,1:1,2', 3, 2) == ['test11', 'test12'] - Expect tablemode#spreadsheet#GetCellRange('2,1:2,2', 2, 1) == ['test21', 'test22'] - Expect tablemode#spreadsheet#GetCellRange('2,1:2,2', 2, 2) == ['test21', 'test22'] - Expect tablemode#spreadsheet#GetCellRange('2,1:2,2', 3, 1) == ['test21', 'test22'] - Expect tablemode#spreadsheet#GetCellRange('2,1:2,2', 3, 2) == ['test21', 'test22'] - - " Get Columns given different seed lines and column - Expect tablemode#spreadsheet#GetCellRange('1:2', 2, 1) == ['test11', 'test21'] - Expect tablemode#spreadsheet#GetCellRange('1:2', 2, 2) == ['test12', 'test22'] - Expect tablemode#spreadsheet#GetCellRange('1:2', 3, 1) == ['test11', 'test21'] - Expect tablemode#spreadsheet#GetCellRange('1:2', 3, 2) == ['test12', 'test22'] - - " Get Column given negative values in range for representing rows from - " the end, -1 being the second last row. - Expect tablemode#spreadsheet#GetCellRange('1:-1', 2, 1) == ['test11'] - Expect tablemode#spreadsheet#GetCellRange('1:-1', 3, 1) == ['test11'] - Expect tablemode#spreadsheet#GetCellRange('1:-1', 2, 2) == ['test12'] - Expect tablemode#spreadsheet#GetCellRange('1:-1', 3, 2) == ['test12'] - end end describe 'Manipulations' @@ -93,41 +55,4 @@ describe 'spreadsheet' Expect tablemode#spreadsheet#ColumnCount('.') == 1 end end - - describe 'Formulas' - describe 'Add Formula' - before - new - read t/fixtures/formula/sample.txt - end - - it 'should add a formula successfully' - call cursor(6, 15) - call tablemode#spreadsheet#AddFormula("Sum(1:4)") - Expect tablemode#spreadsheet#GetCell() == '125.0' - call cursor(8, 15) - Expect getline('.') == '/* tmf: $5,2=Sum(1:4) */' - - call cursor(7, 15) - call tablemode#spreadsheet#AddFormula("Sum(1:-1)") - Expect tablemode#spreadsheet#GetCell() == '250.0' - call cursor(8, 15) - Expect getline('.') == '/* tmf: $5,2=Sum(1:4) ; $6,2=Sum(1:-1) */' - end - end - - describe 'Evaluate Formula' - before - new - read t/fixtures/formula/formula.txt - end - - it 'should evaluate the formula successfull' - call cursor(6, 15) - call tablemode#spreadsheet#EvaluateFormulaLine() - Expect &modified == 1 - Expect tablemode#spreadsheet#GetCell() == '125.0' - end - end - end end diff --git a/t/table.vim b/t/table.vim index 8535747..3297622 100644 --- a/t/table.vim +++ b/t/table.vim @@ -1,5 +1,5 @@ " vim: fdm=indent -source t/config.vim +source t/config/options.vim call vspec#hint({'scope': 'tablemode#table#scope()', 'sid': 'tablemode#table#sid()'}) diff --git a/t/tablemode.vim b/t/tablemode.vim index e78d130..c336ea3 100644 --- a/t/tablemode.vim +++ b/t/tablemode.vim @@ -1,5 +1,5 @@ " vim: fdm=indent -source t/config.vim +source t/config/options.vim call vspec#hint({'scope': 'tablemode#scope()', 'sid': 'tablemode#sid()'}) diff --git a/t/utils.vim b/t/utils.vim index 3127286..676cf4c 100644 --- a/t/utils.vim +++ b/t/utils.vim @@ -1,5 +1,5 @@ " vim: fdm=indent -source t/config.vim +source t/config/options.vim call vspec#hint({'scope': 'tablemode#utils#scope()', 'sid': 'tablemode#utils#sid()'})