table.vim 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. " Private Functions {{{1
  2. function! s:blank(string) "{{{2
  3. return a:string =~# '^\s*$'
  4. endfunction
  5. function! s:BorderExpr() "{{{2
  6. let corner = tablemode#utils#get_buffer_or_global_option('table_mode_corner')
  7. let corner_corner = tablemode#utils#get_buffer_or_global_option('table_mode_corner_corner')
  8. let header_fillchar = tablemode#utils#get_buffer_or_global_option('table_mode_header_fillchar')
  9. return tablemode#table#StartExpr() .
  10. \ '[' . corner . corner_corner . ']' .
  11. \ '[' . escape(g:table_mode_fillchar . header_fillchar . corner . g:table_mode_align_char, '-') . ']\+' .
  12. \ '[' . corner . corner_corner . ']' .
  13. \ tablemode#table#EndExpr()
  14. endfunction
  15. function! s:DefaultBorder() "{{{2
  16. if tablemode#IsActive()
  17. let corner = tablemode#utils#get_buffer_or_global_option('table_mode_corner')
  18. let corner_corner = tablemode#utils#get_buffer_or_global_option('table_mode_corner_corner')
  19. return corner_corner . g:table_mode_fillchar . corner . g:table_mode_fillchar . corner_corner
  20. else
  21. return ''
  22. endif
  23. endfunction
  24. function! s:GenerateHeaderBorder(line) "{{{2
  25. let line = tablemode#utils#line(a:line)
  26. if tablemode#table#IsRow(line - 1) || tablemode#table#IsRow(line + 1)
  27. let line_val = ''
  28. if tablemode#table#IsRow(line + 1)
  29. let line_val = getline(line + 1)
  30. endif
  31. if tablemode#table#IsRow(line - 1) && tablemode#utils#strlen(line_val) < tablemode#utils#strlen(getline(line - 1))
  32. let line_val = getline(line - 1)
  33. endif
  34. if tablemode#utils#strlen(line_val) <= 1 | return s:DefaultBorder() | endif
  35. let corner = tablemode#utils#get_buffer_or_global_option('table_mode_corner')
  36. let corner_corner = tablemode#utils#get_buffer_or_global_option('table_mode_corner_corner')
  37. let header_fillchar = tablemode#utils#get_buffer_or_global_option('table_mode_header_fillchar')
  38. let tline = line_val[stridx(line_val, g:table_mode_separator):strridx(line_val, g:table_mode_separator)]
  39. let fillchar = tablemode#table#IsHeader(line - 1) ? header_fillchar : g:table_mode_fillchar
  40. let special_replacement = '___'
  41. let border = substitute(tline, g:table_mode_escaped_separator_regex, special_replacement, 'g')
  42. let seperator_match_regex = special_replacement . '\zs\(.\{-}\)\ze' . special_replacement
  43. let border = substitute(border, seperator_match_regex, '\=repeat(fillchar, tablemode#utils#StrDisplayWidth(submatch(0)))', 'g')
  44. let border = substitute(border, special_replacement, g:table_mode_separator, 'g')
  45. let border = substitute(border, g:table_mode_separator, corner, 'g')
  46. let border = substitute(border, '^' . corner . '\(.*\)' . corner . '$', corner_corner . '\1' . corner_corner, '')
  47. " Incorporate header alignment chars
  48. if getline(line) =~# g:table_mode_align_char
  49. let pat = '[' . corner_corner . corner . ']'
  50. let hcols = tablemode#align#Split(getline(line), pat)
  51. let gcols = tablemode#align#Split(border, pat)
  52. for idx in range(len(hcols))
  53. if hcols[idx] =~# g:table_mode_align_char
  54. " center align
  55. if hcols[idx] =~# g:table_mode_align_char . '[^'.g:table_mode_align_char.']\+' . g:table_mode_align_char
  56. let gcols[idx] = g:table_mode_align_char . gcols[idx][1:-2] . g:table_mode_align_char
  57. elseif hcols[idx] =~# g:table_mode_align_char . '$'
  58. let gcols[idx] = gcols[idx][:-2] . g:table_mode_align_char
  59. else
  60. let gcols[idx] = g:table_mode_align_char . gcols[idx][1:]
  61. endif
  62. endif
  63. endfor
  64. let border = join(gcols, '')
  65. endif
  66. let cstartexpr = tablemode#table#StartCommentExpr()
  67. if tablemode#utils#strlen(cstartexpr) > 0 && getline(line) =~# cstartexpr
  68. let sce = matchstr(line_val, tablemode#table#StartCommentExpr())
  69. let ece = matchstr(line_val, tablemode#table#EndCommentExpr())
  70. return sce . border . ece
  71. elseif getline(line) =~# tablemode#table#StartExpr()
  72. let indent = matchstr(line_val, tablemode#table#StartExpr())
  73. return indent . border
  74. else
  75. return border
  76. endif
  77. else
  78. return s:DefaultBorder()
  79. endif
  80. endfunction
  81. " Public Functions {{{1
  82. function! tablemode#table#GetCommentStart() "{{{2
  83. let cstring = &commentstring
  84. if tablemode#utils#strlen(cstring) > 0
  85. return substitute(split(cstring, '%s')[0], '[^(%)]', '\\\0', 'g')
  86. else
  87. return ''
  88. endif
  89. endfunction
  90. function! tablemode#table#StartCommentExpr() "{{{2
  91. let cstartexpr = tablemode#table#GetCommentStart()
  92. if tablemode#utils#strlen(cstartexpr) > 0
  93. return '^\s*' . cstartexpr . '\s*'
  94. else
  95. return ''
  96. endif
  97. endfunction
  98. function! tablemode#table#GetCommentEnd() "{{{2
  99. let cstring = &commentstring
  100. if tablemode#utils#strlen(cstring) > 0
  101. let cst = split(cstring, '%s')
  102. if len(cst) == 2
  103. return substitute(cst[1], '[^()]', '\\\0', 'g')
  104. else
  105. return ''
  106. endif
  107. else
  108. return ''
  109. endif
  110. endfunction
  111. function! tablemode#table#EndCommentExpr() "{{{2
  112. let cendexpr = tablemode#table#GetCommentEnd()
  113. if tablemode#utils#strlen(cendexpr) > 0
  114. return '.*\zs\s\+' . cendexpr . '\s*$'
  115. else
  116. return ''
  117. endif
  118. endfunction
  119. function! tablemode#table#StartExpr() "{{{2
  120. let cstart = tablemode#table#GetCommentStart()
  121. if tablemode#utils#strlen(cstart) > 0
  122. return '^\s*\(' . cstart . '\)\?\s*'
  123. else
  124. return '^\s*'
  125. endif
  126. endfunction
  127. function! tablemode#table#EndExpr() "{{{2
  128. let cend = tablemode#table#GetCommentEnd()
  129. if tablemode#utils#strlen(cend) > 0
  130. return '\s*\(\s\+' . cend . '\)\?\s*$'
  131. else
  132. return '\s*$'
  133. endif
  134. endfunction
  135. function! tablemode#table#IsBorder(line) "{{{2
  136. return !s:blank(getline(a:line)) && getline(a:line) =~# s:BorderExpr()
  137. endfunction
  138. function! tablemode#table#IsHeader(line) "{{{2
  139. let line = tablemode#utils#line(a:line)
  140. " if line <= 0 || line > line('$') | return 0 | endif
  141. return tablemode#table#IsRow(line)
  142. \ && !tablemode#table#IsRow(line-1)
  143. \ && !tablemode#table#IsRow(line-2)
  144. \ && !tablemode#table#IsBorder(line-2)
  145. \ && tablemode#table#IsBorder(line+1)
  146. endfunction
  147. function! tablemode#table#IsRow(line) "{{{2
  148. return !tablemode#table#IsBorder(a:line) && getline(a:line) =~# (tablemode#table#StartExpr() . g:table_mode_separator) . '[^' . g:table_mode_separator . ']\+'
  149. endfunction
  150. function! tablemode#table#IsTable(line) "{{{2
  151. return tablemode#table#IsRow(a:line) || tablemode#table#IsBorder(a:line)
  152. endfunction
  153. function! tablemode#table#AddBorder(line) "{{{2
  154. call setline(a:line, s:GenerateHeaderBorder(a:line))
  155. endfunction
  156. function! tablemode#table#Realign(line) "{{{2
  157. let utree = undotree()
  158. if utree.seq_cur != utree.seq_last
  159. " skip during undo
  160. return
  161. endif
  162. let current_fm = &foldmethod " save foldmethod to be restored
  163. setlocal foldmethod=manual " manual foldmethod while table is being aligned
  164. let line = tablemode#utils#line(a:line)
  165. let lines = []
  166. let [lnum, blines] = [line, []]
  167. while tablemode#table#IsTable(lnum)
  168. if tablemode#table#IsBorder(lnum)
  169. call insert(blines, lnum)
  170. let lnum -= 1
  171. continue
  172. endif
  173. call insert(lines, {'lnum': lnum, 'text': getline(lnum)})
  174. let lnum -= 1
  175. endwhile
  176. let lnum = line + 1
  177. while tablemode#table#IsTable(lnum)
  178. if tablemode#table#IsBorder(lnum)
  179. call add(blines, lnum)
  180. let lnum += 1
  181. continue
  182. endif
  183. call add(lines, {'lnum': lnum, 'text': getline(lnum)})
  184. let lnum += 1
  185. endwhile
  186. let lines = tablemode#align#Align(lines)
  187. for aline in lines
  188. undojoin | keepjumps call setline(aline.lnum, aline.text)
  189. endfor
  190. for bline in blines
  191. undojoin | keepjumps call tablemode#table#AddBorder(bline)
  192. endfor
  193. " restore foldmethod
  194. execute "setlocal foldmethod=" . current_fm
  195. endfunction