align.vim 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. " Borrowed from Tabular
  2. " Private Functions {{{1
  3. " function! s:StripTrailingSpaces(string) - Remove all trailing spaces {{{2
  4. " from a string.
  5. function! s:StripTrailingSpaces(string)
  6. return matchstr(a:string, '^.\{-}\ze\s*$')
  7. endfunction
  8. function! s:Padding(string, length, where) "{{{3
  9. let gap_length = a:length - tablemode#utils#StrDisplayWidth(a:string)
  10. if a:where =~# 'l'
  11. return a:string . repeat(" ", gap_length)
  12. elseif a:where =~# 'r'
  13. return repeat(" ", gap_length) . a:string
  14. elseif a:where =~# 'c'
  15. let right = gap_length / 2
  16. let left = right + (right * 2 != gap_length)
  17. return repeat(" ", left) . a:string . repeat(" ", right)
  18. endif
  19. endfunction
  20. " Public Functions {{{1
  21. " function! tablemode#align#Split() - Split a string into fields and delimiters {{{2
  22. " Like split(), but include the delimiters as elements
  23. " All odd numbered elements are delimiters
  24. " All even numbered elements are non-delimiters (including zero)
  25. function! tablemode#align#Split(string, delim)
  26. let rv = []
  27. let beg = 0
  28. let len = len(a:string)
  29. let searchoff = 0
  30. while 1
  31. let mid = match(a:string, a:delim, beg + searchoff, 1)
  32. if mid == -1 || mid == len
  33. break
  34. endif
  35. let matchstr = matchstr(a:string, a:delim, beg + searchoff, 1)
  36. let length = strlen(matchstr)
  37. if length == 0 && beg == mid
  38. " Zero-length match for a zero-length delimiter - advance past it
  39. let searchoff += 1
  40. continue
  41. endif
  42. if beg == mid
  43. let rv += [ "" ]
  44. else
  45. let rv += [ a:string[beg : mid-1] ]
  46. endif
  47. let rv += [ matchstr ]
  48. let beg = mid + length
  49. let searchoff = 0
  50. endwhile
  51. let rv += [ strpart(a:string, beg) ]
  52. return rv
  53. endfunction
  54. function! tablemode#align#alignments(lnum, ncols) "{{{2
  55. let achr = g:table_mode_align_char
  56. let alignments = []
  57. if tablemode#table#IsBorder(a:lnum+1)
  58. let corner = tablemode#utils#get_buffer_or_global_option('table_mode_corner')
  59. let corner_corner = tablemode#utils#get_buffer_or_global_option('table_mode_corner_corner')
  60. let hcols = tablemode#align#Split(getline(a:lnum+1), '[' . corner . corner_corner . ']')
  61. for idx in range(len(hcols))
  62. " Right align if header
  63. call add(alignments, 'l')
  64. if hcols[idx] =~# achr . '[^'.achr.']\+' . achr
  65. let alignments[idx] = 'c'
  66. elseif hcols[idx] =~# achr . '$'
  67. let alignments[idx] = 'r'
  68. endif
  69. " if hcols[idx] !~# '[^0-9\.]' | let alignments[idx] = 'r' | endif
  70. endfor
  71. end
  72. return alignments
  73. endfunction
  74. function! tablemode#align#Align(lines) "{{{2
  75. if empty(a:lines) | return [] | endif
  76. let lines = map(a:lines, 'map(v:val, "v:key =~# \"text\" ? tablemode#align#Split(v:val, g:table_mode_escaped_separator_regex) : v:val")')
  77. for line in lines
  78. let stext = line.text
  79. if len(stext) <= 1 | continue | endif
  80. if stext[0] !~ tablemode#table#StartExpr()
  81. let stext[0] = s:StripTrailingSpaces(stext[0])
  82. endif
  83. if len(stext) >= 2
  84. for i in range(1, len(stext)-1)
  85. let stext[i] = tablemode#utils#strip(stext[i])
  86. endfor
  87. endif
  88. endfor
  89. let maxes = []
  90. for line in lines
  91. let stext = line.text
  92. if len(stext) <= 1 | continue | endif
  93. for i in range(len(stext))
  94. if i == len(maxes)
  95. let maxes += [ tablemode#utils#StrDisplayWidth(stext[i]) ]
  96. else
  97. let maxes[i] = max([ maxes[i], tablemode#utils#StrDisplayWidth(stext[i]) ])
  98. endif
  99. endfor
  100. endfor
  101. if tablemode#utils#get_buffer_or_global_option('table_mode_ignore_align') ==# 1
  102. let alignments = []
  103. else
  104. let alignments = tablemode#align#alignments(lines[0].lnum, len(lines[0].text))
  105. endif
  106. for idx in range(len(lines))
  107. let tlnum = lines[idx].lnum
  108. let tline = lines[idx].text
  109. if len(tline) <= 1 | continue | endif
  110. for jdx in range(len(tline))
  111. " Dealing with the header being the first line
  112. if jdx >= len(alignments) | call add(alignments, 'l') | endif
  113. let field = s:Padding(tline[jdx], maxes[jdx], alignments[jdx])
  114. let tline[jdx] = field . (jdx == 0 || jdx == len(tline) ? '' : ' ')
  115. endfor
  116. let lines[idx].text = s:StripTrailingSpaces(join(tline, ''))
  117. endfor
  118. return lines
  119. endfunction