Skip to content

Instantly share code, notes, and snippets.

@markscottwright
Created April 6, 2018 19:02
Show Gist options
  • Save markscottwright/db42ff5848b105f33a996c6d60787acd to your computer and use it in GitHub Desktop.
Save markscottwright/db42ff5848b105f33a996c6d60787acd to your computer and use it in GitHub Desktop.
How to format a org-mode style table in Vim
# how to format a table in VIM
function! Strip(input_string)
return substitute(a:input_string, '^\s*\(.\{-}\)\s*$', '\1', '')
endfunction
function! GetFields(line_num)
let cur_line = Strip(getline(a:line_num))
let maybe_padded = split(cur_line, "|")
let fields = []
for f in maybe_padded
let fields = add(fields, Strip(f))
endfor
return fields
endfunction
function! GetWidths(line_num)
let widths = []
for field in GetFields(a:line_num)
let widths = add(widths, strlen(field))
endfor
return widths
endfunction
function! IsHeaderSeparator(line_num)
return Strip(getline(a:line_num)) =~ "^|[-|+]*$"
endfunction
function! IsTableLine(line_num)
return Strip(getline(a:line_num)) =~ "^|"
endfunction
function! IsNumericString(s)
let numeric = a:s =~ "^[0-9]*$"
return numeric
endfunction
function! GetIsNumeric(start_line_num, end_line_num)
let is_numeric = []
for line_num in range(a:start_line_num, a:end_line_num)
if IsHeaderSeparator(line_num)
let is_numeric = []
continue
endif
let new_is_numeric = []
let fields = GetFields(line_num)
for field_num in range(max([len(fields), len(is_numeric)]))
let field_numeric_so_far = get(is_numeric, field_num, 1)
let this_field_is_numeric = field_num >= len(fields)
\ || IsNumericString(fields[field_num])
echom this_field_is_numeric
let new_is_numeric = add(new_is_numeric,
\ this_field_is_numeric && field_numeric_so_far)
echom join(new_is_numeric)
endfor
let is_numeric = new_is_numeric
endfor
return is_numeric
endfunction
function! GetMaxWidths(start_line_num, end_line_num)
let max_widths = []
let line_num = a:start_line_num
while line_num <= a:end_line_num
if !IsHeaderSeparator(line_num)
let widths = GetWidths(line_num)
let new_max_widths = []
for col_num in range(max([len(widths), len(max_widths)]))
let max_col_width = max([get(widths, col_num, 0), get(max_widths, col_num, 0)])
let new_max_widths = add(new_max_widths, max_col_width)
endfor
let max_widths = new_max_widths
endif
let line_num = line_num + 1
endwhile
return max_widths
endfunction
function! FindFirstLine(cur_line)
let start_line = a:cur_line
while start_line > 0 && IsTableLine(start_line)
let start_line = start_line - 1
endwhile
if start_line != a:cur_line
let start_line = start_line + 1
endif
return start_line
endfunction
function! FindLastLine(cur_line)
let end_line = a:cur_line
while end_line <= line('$') && IsTableLine(end_line)
let end_line = end_line + 1
endwhile
if end_line != a:cur_line
let end_line = end_line - 1
endif
return end_line
endfunction
function! FormatTable()
let cur_line = line('.')
let start_line = FindFirstLine(cur_line)
let end_line = FindLastLine(cur_line)
let max_widths = GetMaxWidths(start_line, end_line)
if len(max_widths) < 1
echom "No table found"
return
endif
let is_numeric = GetIsNumeric(start_line, end_line)
echom join(is_numeric)
for line_num in range(start_line, end_line)
if IsHeaderSeparator(line_num)
let padded_fields = []
for field_num in range(len(max_widths))
let padded_fields = add(padded_fields, repeat("-", max_widths[field_num]+2))
endfor
call setline(line_num, "|" . join(padded_fields, "+") . "|")
else
let padded_fields = []
let fields = GetFields(line_num)
for field_num in range(len(max_widths))
if is_numeric[field_num]
let fmt_string = " %" . max_widths[field_num] . "s "
else
let fmt_string = " %-" . max_widths[field_num]. "s "
endif
if field_num < len(fields)
let padded_fields = add(padded_fields, printf(fmt_string, fields[field_num]))
else
let padded_fields = add(padded_fields, printf(fmt_string, ""))
endif
endfor
call setline(line_num, "|" . join(padded_fields, "|") . "|")
endif
endfor
endfunction
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment