Added the following formula functions:

- Min: get the lowest value
  - Max: get the highest value
  - CountE: count the number of empty cells
  - CountNE: count the number of non-empty cells
  - PercentE: percent of empty cells
  - PercentNE: percent of non-empty cells
  - AverageNE: average over non-empty cells

Also added a subtle tweak that ignores an HTML comment tag ('<!--')
found between the table and the starting formula line. Being able to
wrap all the formula lines with an HTML comment prevents the formulas
from being rendered in Markdown/ReST output.
This commit is contained in:
Eric Davis
2020-04-18 18:46:21 -07:00
parent 29e7cb41bb
commit 5cdf3c2ac1
3 changed files with 160 additions and 2 deletions

View File

@@ -1,4 +1,76 @@
" Private Functions {{{1
function! s:Min(list) "{{{2
let result = v:null
for item in a:list
if empty(item)
continue
endif
if type(item) == type(1) || type(item) == type(1.0)
if result == v:null || item < result
let result = item
endif
elseif type(item) == type('')
let val = str2float(item)
if result == v:null || val < result
let result = val
endif
elseif type(item) == type([])
let val = s:Sum(item)
if result == v:null || val < result
let result = val
endif
endif
endfor
return result == v:null ? 0 : result
endfunction
function! s:Max(list) "{{{2
let result = v:null
for item in a:list
if empty(item)
continue
endif
if type(item) == type(1) || type(item) == type(1.0)
if result == v:null || item > result
let result = item
endif
elseif type(item) == type('')
let val = str2float(item)
if result == v:null || val > result
let result = val
endif
elseif type(item) == type([])
let val = s:Sum(item)
if result == v:null || val > result
let result = val
endif
endif
endfor
return result == v:null ? 0 : result
endfunction
function! s:CountE(list) "{{{2
let result = 0
for item in a:list
if empty(item)
let result += 1
endif
endfor
return result
endfunction
function! s:CountNE(list) "{{{2
return len(a:list)-s:CountE(a:list)
endfunction
function! s:PercentE(list) "{{{2
return (s:CountE(a:list)*100)/len(a:list)
endfunction
function! s:PercentNE(list) "{{{2
return (s:CountNE(a:list)*100)/len(a:list)
endfunction
function! s:Sum(list) "{{{2
let result = 0.0
for item in a:list
@@ -17,6 +89,10 @@ function! s:Average(list) "{{{2
return s:Sum(a:list)/len(a:list)
endfunction
function! s:AverageNE(list) "{{{2
return s:Sum(a:list)/s:CountNE(a:list)
endfunction
" Public Functions {{{1
function! tablemode#spreadsheet#GetFirstRow(line) "{{{2
if tablemode#table#IsRow(a:line)
@@ -244,6 +320,42 @@ function! tablemode#spreadsheet#InsertColumn(after) "{{{2
endif
endfunction
function! tablemode#spreadsheet#Min(range, ...) abort "{{{2
let args = copy(a:000)
call insert(args, a:range)
return s:Min(call('tablemode#spreadsheet#cell#GetCellRange', args))
endfunction
function! tablemode#spreadsheet#Max(range, ...) abort "{{{2
let args = copy(a:000)
call insert(args, a:range)
return s:Max(call('tablemode#spreadsheet#cell#GetCellRange', args))
endfunction
function! tablemode#spreadsheet#CountE(range, ...) abort "{{{2
let args = copy(a:000)
call insert(args, a:range)
return s:CountE(call('tablemode#spreadsheet#cell#GetCellRange', args))
endfunction
function! tablemode#spreadsheet#CountNE(range, ...) abort "{{{2
let args = copy(a:000)
call insert(args, a:range)
return s:CountNE(call('tablemode#spreadsheet#cell#GetCellRange', args))
endfunction
function! tablemode#spreadsheet#PercentE(range, ...) abort "{{{2
let args = copy(a:000)
call insert(args, a:range)
return s:PercentE(call('tablemode#spreadsheet#cell#GetCellRange', args))
endfunction
function! tablemode#spreadsheet#PercentNE(range, ...) abort "{{{2
let args = copy(a:000)
call insert(args, a:range)
return s:PercentNE(call('tablemode#spreadsheet#cell#GetCellRange', args))
endfunction
function! tablemode#spreadsheet#Sum(range, ...) abort "{{{2
let args = copy(a:000)
call insert(args, a:range)
@@ -256,6 +368,12 @@ function! tablemode#spreadsheet#Average(range, ...) abort "{{{2
return s:Average(call('tablemode#spreadsheet#cell#GetCellRange', args))
endfunction
function! tablemode#spreadsheet#AverageNE(range, ...) abort "{{{2
let args = copy(a:000)
call insert(args, a:range)
return s:AverageNE(call('tablemode#spreadsheet#cell#GetCellRange', args))
endfunction
function! tablemode#spreadsheet#Sort(bang, ...) range "{{{2
if exists('*getcurpos')
let col = getcurpos()[4] " curswant

View File

@@ -15,6 +15,9 @@ function! tablemode#spreadsheet#formula#Add(...) "{{{2
let fr = '$' . row . ',' . colm . '=' . fr
let fline = tablemode#spreadsheet#GetLastRow('.') + 1
if tablemode#table#IsBorder(fline) | let fline += 1 | endif
if getline(fline) =~# '^\s*<!--' " ignore line with an HTML comment tag
let fline += 1
endif
let cursor_pos = [line('.'), col('.')]
if getline(fline) =~# 'tmf: '
" Comment line correctly
@@ -55,6 +58,30 @@ function! tablemode#spreadsheet#formula#EvaluateExpr(expr, line) abort "{{{2
let [row, colm] = [0, str2nr(cell)]
endif
if expr =~# 'Min(.*)'
let expr = substitute(expr, 'Min(\([^)]*\))', 'tablemode#spreadsheet#Min("\1",'.line.','.colm.')', 'g')
endif
if expr =~# 'Max(.*)'
let expr = substitute(expr, 'Max(\([^)]*\))', 'tablemode#spreadsheet#Max("\1",'.line.','.colm.')', 'g')
endif
if expr =~# 'CountE(.*)'
let expr = substitute(expr, 'CountE(\([^)]*\))', 'tablemode#spreadsheet#CountE("\1",'.line.','.colm.')', 'g')
endif
if expr =~# 'CountNE(.*)'
let expr = substitute(expr, 'CountNE(\([^)]*\))', 'tablemode#spreadsheet#CountNE("\1",'.line.','.colm.')', 'g')
endif
if expr =~# 'PercentE(.*)'
let expr = substitute(expr, 'PercentE(\([^)]*\))', 'tablemode#spreadsheet#PercentE("\1",'.line.','.colm.')', 'g')
endif
if expr =~# 'PercentNE(.*)'
let expr = substitute(expr, 'PercentNE(\([^)]*\))', 'tablemode#spreadsheet#PercentNE("\1",'.line.','.colm.')', 'g')
endif
if expr =~# 'Sum(.*)'
let expr = substitute(expr, 'Sum(\([^)]*\))', 'tablemode#spreadsheet#Sum("\1",'.line.','.colm.')', 'g')
endif
@@ -63,6 +90,10 @@ function! tablemode#spreadsheet#formula#EvaluateExpr(expr, line) abort "{{{2
let expr = substitute(expr, 'Average(\([^)]*\))', 'tablemode#spreadsheet#Average("\1",'.line.','.colm.')', 'g')
endif
if expr =~# 'AverageNE(.*)'
let expr = substitute(expr, 'AverageNE(\([^)]*\))', 'tablemode#spreadsheet#AverageNE("\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')
@@ -107,6 +138,9 @@ function! tablemode#spreadsheet#formula#EvaluateFormulaLine() abort "{{{2
if tablemode#table#IsRow('.') " We're inside the table
let line = tablemode#spreadsheet#GetLastRow('.')
let fline = line + 1
if getline(fline) =~# '^\s*<!--' " ignore line with an HTML comment tag
let fline += 1
endif
if tablemode#table#IsBorder(fline) | let fline += 1 | endif
while s:IsFormulaLine(fline)
let exprs += split(matchstr(getline(fline), matchexpr), ';')
@@ -116,6 +150,9 @@ function! tablemode#spreadsheet#formula#EvaluateFormulaLine() abort "{{{2
let fline = line('.')
let line = line('.') - 1
while s:IsFormulaLine(line) | let fline = line | let line -= 1 | endwhile
if getline(fline) =~# '^\s*<!--' " ignore line with an HTML comment tag
let line -= 1
endif
if tablemode#table#IsBorder(line) | let line -= 1 | endif
if tablemode#table#IsRow(line)
" let exprs = split(matchstr(getline('.'), matchexpr), ';')

View File

@@ -120,8 +120,11 @@ Formula Expressions :
The formula can be a simple mathematical expression involving cells
which are also defined by the same format as that of the target cell.
Apart from basic mathematical expressions, table mode also provides
special functions 'Sum' and 'Average'. Both these functions take a
range as input. A range can be of two forms :
special functions 'Min', 'Max', 'CountE' (number of empty cells),
'CountNE' (number of non-empty cells), 'PercentE' (percent of empty
cells), 'PercentNE' (percent of non-empty cells), 'Sum', 'Average',
and 'AverageNE' (average over non-empty cells). All these functions
take a range as input. A range can be of two forms :
'n:m': This represents cells in the current column from row
'n' through 'm'. If 'm' is negative it represents 'm' row