Last active
August 29, 2015 14:06
-
-
Save kamichidu/4017dd7ff2d0bdfd2794 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
let s:S= vital#of('vital').import('Data.String') | |
let s:L= vital#of('vital').import('Data.List') | |
let s:tabular= { | |
\ '__column_defs': [], | |
\ '__hborder': 1, | |
\ '__vborder': 1, | |
\ '__header': [], | |
\ '__rows': [], | |
\ '__footer': [], | |
\} | |
let s:default_column_def= { | |
\ 'halign': 'left', | |
\ 'valign': 'top', | |
\ 'width': 0, | |
\} | |
function! s:tabular.header(...) | |
if a:0 == 0 | |
return deepcopy(self.__header) | |
else | |
let header= deepcopy(a:1) | |
if len(header) != len(self.__column_defs) | |
throw "vital: Text.Table: Not match column size." | |
endif | |
let self.__header= header | |
endif | |
endfunction | |
function! s:tabular.add_column(def) | |
let self.__column_defs+= [deepcopy(a:def)] | |
endfunction | |
function! s:tabular.add_row(row) | |
let row= deepcopy(a:row) | |
if len(row) != len(self.__column_defs) | |
throw "vital: Text.Table: Not match column size." | |
endif | |
let self.__rows+= [row] | |
endfunction | |
function! s:tabular.footer(...) | |
if a:0 == 0 | |
return deepcopy(self.__footer) | |
else | |
let footer= deepcopy(a:1) | |
if len(footer) != len(self.__column_defs) | |
throw "vital: Text.Table: Not match column size." | |
endif | |
let self.__footer= footer | |
endif | |
endfunction | |
function! s:tabular.stringify() | |
let context= {} | |
let context.header= self.__header | |
let context.footer= self.__footer | |
let context.rows= self.__rows | |
let context.column_defs= [] | |
for col in range(len(self.__column_defs)) | |
let orig= self.__column_defs[col] | |
let def= extend(deepcopy(s:default_column_def), orig) | |
if def.width == 0 | |
" `1' is nl | |
let def.width= max(map(copy(context.rows), 'strlen(v:val[col])')) + 1 | |
endif | |
let context.column_defs+= [def] | |
endfor | |
let context.hborder= self.__hborder | |
let context.vborder= self.__vborder | |
return s:_stringify(context) | |
endfunction | |
function! s:_stringify(context) | |
let buffer= [] | |
let buffer+= s:_make_border_string(a:context) | |
if !empty(a:context.header) | |
let buffer+= s:_make_row_string(a:context, a:context.header) | |
let buffer+= s:_make_border_string(a:context) | |
endif | |
for row in a:context.rows | |
let buffer+= s:_make_row_string(a:context, row) | |
endfor | |
if !empty(a:context.footer) | |
let buffer+= s:_make_border_string(a:context) | |
let buffer+= s:_make_row_string(a:context, a:context.footer) | |
endif | |
let buffer+= s:_make_border_string(a:context) | |
return join(buffer, "\n") | |
endfunction | |
function! s:_make_border_string(context) | |
if !a:context.hborder | |
return [] | |
endif | |
let buffer= [] | |
for def in a:context.column_defs | |
let buffer+= [repeat('-', def.width + 2)] | |
endfor | |
if a:context.vborder | |
return ['+' . join(buffer, '+') . '+'] | |
else | |
return ['-' . join(buffer, '-') . '-'] | |
endif | |
endfunction | |
function! s:_make_row_string(context, row) | |
let buffer= [] | |
for col in range(len(a:context.column_defs)) | |
let def= a:context.column_defs[col] | |
let cell= a:row[col] | |
let buffer+= [s:_make_cell_string(def, cell)] | |
unlet cell | |
endfor | |
" vertical align | |
let tmp= [] | |
let col= 0 | |
for cells in s:_make_equals_size(buffer) | |
let def= a:context.column_defs[col] | |
let tmp+= [s:_valign(def, cells)] | |
let col+= 1 | |
endfor | |
let buffer= tmp | |
unlet tmp | |
let out= [] | |
for cells in s:_zip(buffer) | |
let cellstrs= [] | |
for col in range(len(a:context.column_defs)) | |
let def= a:context.column_defs[col] | |
let cell= cells[col] | |
" horizontal align | |
let cellstrs+= [s:_halign(def, cell)] | |
endfor | |
if a:context.vborder | |
let out+= ['| ' . join(cellstrs, ' | ') . ' |'] | |
else | |
let out+= [join(cell, ' ')] | |
endif | |
endfor | |
return out | |
endfunction | |
function! s:_make_cell_string(def, expr) | |
let cellstr= s:_to_string(a:expr) | |
return s:S.wrap(cellstr, a:def.width) | |
endfunction | |
function! s:_halign(def, expr) | |
if a:def.halign ==# 'left' | |
return printf('%-*s', a:def.width, s:_to_string(a:expr)) | |
elseif a:def.halign ==# 'center' | |
throw printf("vital: Text.Table: Sorry, halign `%s' is unimplemented yet.", a:def.halign) | |
elseif a:def.halign ==# 'right' | |
return printf('% *s', a:def.width, s:_to_string(a:expr)) | |
else | |
throw printf("vital: Text.Table: Unknown halign `%s'", a:def.halign) | |
endif | |
endfunction | |
function! s:_valign(def, list) | |
if a:def.valign ==# 'top' | |
return a:list | |
elseif a:def.valign ==# 'center' | |
throw printf("vital: Text.Table: Sorry, valign `%s' is unimplemented yet.", a:def.valign) | |
elseif a:def.valign ==# 'bottom' | |
let buffer= [] | |
for e in reverse(copy(a:list)) | |
let buffer+= [e] | |
endfor | |
return buffer | |
else | |
throw printf("vital: Text.Table: Unknown valign `%s'", a:def.valign) | |
endif | |
endfunction | |
function! s:_to_string(expr) | |
if type(a:expr) == type('') | |
return a:expr | |
elseif type(a:expr) == type(0) | |
return '' . a:expr | |
elseif type(a:expr) == type(0.0) | |
return printf('%f', a:expr) | |
else | |
throw 'vital: Text.Table: Unsupported type' | |
endif | |
endfunction | |
function! s:_make_equals_size(list) | |
let mlen= max(map(copy(a:list), 'len(v:val)')) | |
let res= [] | |
for l in a:list | |
let res+= [map(range(mlen), 'get(l, v:val, "")')] | |
endfor | |
return res | |
endfunction | |
function! s:_zip(list) | |
let mlen= max(map(copy(a:list), 'len(v:val)')) | |
let zip= [] | |
for i in range(mlen) | |
let buf= [] | |
for l in a:list | |
let buf+= [get(l, i, '')] | |
endfor | |
let zip+= [buf] | |
endfor | |
return zip | |
endfunction | |
" test | |
try | |
call s:tabular.add_column({ }) | |
call s:tabular.add_column({ 'width': 10}) | |
call s:tabular.add_column({'halign': 'right', 'valign': 'bottom', 'width': 8}) | |
call s:tabular.header(['h1', 'h2', 'h3']) | |
call s:tabular.add_row(['r1c1', 'r1c2', 'r1c3']) | |
call s:tabular.add_row(['r2c1', 'r2c2', 'r2c3']) | |
call s:tabular.add_row(['r2c1', 'ああああああああああああああああ', 'r2c3']) | |
call s:tabular.footer(['f1', 'f2', 'f3']) | |
echo s:tabular.stringify() | |
catch | |
echo v:throwpoint | |
echo v:exception | |
endtry |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment