Skip to content

Commit

Permalink
Change the methodology for handling indentation
Browse files Browse the repository at this point in the history
Indentation is left alone until after lines have been split into fields.
We then find the common indent remaining in the 1st field of each line
that will be affected by the align operation (for GTabularize,
non-matching lines don't factor in here).  Also, blank lines don't
affect the calculation of longest common indent.

Before calculation of field widths, leading indent is stripped from all
fields, and after the fields have been joined back together we re-add
the common indent that was stripped earlier.
  • Loading branch information
godlygeek committed Jul 3, 2024
1 parent 8405725 commit cdac1a6
Showing 1 changed file with 42 additions and 14 deletions.
56 changes: 42 additions & 14 deletions autoload/tabular.vim
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,27 @@ function! s:StripLeadingSpaces(string)
return matchstr(a:string, '^\s*\zs.*$')
endfunction

" Find the longest common indent for a list of strings {{{2
" If a string is shorter than the others but contains no non-whitespace
" characters, it does not end the match. This provides consistency with
" vim's behavior that blank lines don't have trailing spaces.
function! s:LongestCommonIndent(strings)
if empty(a:strings)
return ''
endif

let n = 0
while 1
let ns = join(map(copy(a:strings), 'v:val[n]'), '')
if ns !~ '^ \+$\|^\t\+$'
break
endif
let n += 1
endwhile

return strpart(a:strings[0], 0, n)
endfunction

" Split a string into fields and delimiters {{{2
" Like split(), but include the delimiters as elements
" All odd numbered elements are delimiters
Expand Down Expand Up @@ -220,27 +241,30 @@ function! tabular#TabularizeStrings(strings, delim, ...)

let format = split(formatstr, s:formatelempat . '\zs')

let lines = map(a:strings, 's:SplitDelim(v:val, a:delim)')
let lines = a:strings

" Strip spaces
" - Only from non-delimiters; spaces in delimiters must have been matched
" intentionally
" - Don't strip leading spaces from the first element; we like indenting.
call map(lines, 's:SplitDelim(v:val, a:delim)')

let first_fields = []

" Strip spaces from non-delimiters; spaces in delimiters must have been
" matched intentionally
for line in lines
if len(line) == 1 && s:do_gtabularize
continue " Leave non-matching lines unchanged for GTabularize
endif

if line[0] !~ '^\s*$'
let line[0] = s:StripTrailingSpaces(line[0])
endif
if len(line) >= 3
for i in range(2, len(line)-1, 2)
call add(first_fields, line[0])

if len(line) >= 1
for i in range(0, len(line)-1, 2)
let line[i] = s:StripLeadingSpaces(s:StripTrailingSpaces(line[i]))
endfor
endif
endfor

let common_indent = s:LongestCommonIndent(first_fields)

" Find the max length of each field
let maxes = []
for line in lines
Expand All @@ -257,8 +281,6 @@ function! tabular#TabularizeStrings(strings, delim, ...)
endfor
endfor

let lead_blank = empty(filter(copy(lines), 'v:val[0] =~ "\\S"'))

" Concatenate the fields, according to the format pattern.
for idx in range(len(lines))
let line = lines[idx]
Expand All @@ -280,10 +302,16 @@ function! tabular#TabularizeStrings(strings, delim, ...)
let field = s:Center(line[i], maxes[i])
endif

let line[i] = field . (lead_blank && i == 0 ? '' : repeat(" ", pad))
let line[i] = field . repeat(" ", pad)
endfor

let lines[idx] = s:StripTrailingSpaces(join(line, ''))
let prefix = common_indent
if len(line) == 1 && s:do_gtabularize
" We didn't strip the indent in this case; nothing to put back.
let prefix = ''
endif

let lines[idx] = s:StripTrailingSpaces(prefix . join(line, ''))
endfor
endfunction

Expand Down

0 comments on commit cdac1a6

Please sign in to comment.