Completed a fully custom formatexpr (#436)

This commit is contained in:
Karl Yngve Lervåg 2016-08-01 22:57:43 +02:00
parent b82a8d3798
commit 0fdaee31ed
3 changed files with 115 additions and 24 deletions

View File

@ -44,7 +44,8 @@ function! vimtex#format#formatexpr() " {{{1
let l:top = v:lnum let l:top = v:lnum
let l:bottom = v:lnum + v:count - 1 let l:bottom = v:lnum + v:count - 1
let l:mark = l:bottom let l:lines_old = getline(l:top, l:bottom)
let l:tries = 5
" This is a hack to make undo restore the correct position " This is a hack to make undo restore the correct position
if mode() !=# 'i' if mode() !=# 'i'
@ -52,7 +53,43 @@ function! vimtex#format#formatexpr() " {{{1
normal! x normal! x
endif endif
for l:current in range(l:bottom, l:top, -1) " Main formatting algorithm
while l:tries > 0
" Format the range of lines
let l:bottom = s:format(l:top, l:bottom)
" Ensure proper indentation
silent! execute printf('normal! %sG=%sG', l:top, l:bottom)
" Check if any lines have changed
let l:lines_new = getline(l:top, l:bottom)
let l:index = s:compare_lines(l:lines_new, l:lines_old)
let l:top += l:index
if l:top > l:bottom | break | endif
let l:lines_old = l:lines_new[l:index:]
let l:tries -= 1
endwhile
" Move cursor to first non-blank of the last formatted line
if mode() !=# 'i'
execute 'normal!' l:bottom . 'G^'
endif
" Don't change the text if the formatting algorithm failed
if l:tries == 0
silent! undo
call vimtex#echo#warning('Formatting of selected text failed!')
endif
let &l:foldenable = l:foldenable
endfunction
" }}}1
function! s:format(top, bottom) " {{{1
let l:bottom = a:bottom
let l:mark = a:bottom
for l:current in range(a:bottom, a:top, -1)
let l:line = getline(l:current) let l:line = getline(l:current)
if vimtex#util#in_mathzone(l:current, 1) if vimtex#util#in_mathzone(l:current, 1)
@ -63,24 +100,79 @@ function! vimtex#format#formatexpr() " {{{1
if l:line =~# s:border_end if l:line =~# s:border_end
if l:current < l:mark if l:current < l:mark
execute 'normal!' (l:current+1) . 'Ggw' . l:mark . 'G' let l:bottom += s:format_build_lines(l:current+1, l:mark)
endif endif
let l:mark = l:current let l:mark = l:current
endif endif
if l:line =~# s:border_beginning if l:line =~# s:border_beginning
if l:current < l:mark if l:current < l:mark
execute 'normal!' l:current . 'Ggw' . l:mark . 'G' let l:bottom += s:format_build_lines(l:current, l:mark)
endif endif
let l:mark = l:current-1 let l:mark = l:current-1
endif endif
endwhile
if l:top <= l:mark if l:line =~# '^\s*$'
execute 'normal!' l:top . 'Ggw' . l:mark . 'G' let l:bottom += s:format_build_lines(l:current+1, l:mark)
let l:mark = l:current-1
endif
endfor
if a:top <= l:mark
let l:bottom += s:format_build_lines(a:top, l:mark)
endif endif
let &l:foldenable = l:foldenable return l:bottom
endfunction
" }}}1
function! s:format_build_lines(start, end) " {{{1
"
" Get the desired text to format as a list of words
"
let l:words = split(join(map(getline(a:start, a:end),
\ 'substitute(v:val, ''^\s*'', '''', '''')'), ' '), ' ')
if empty(l:words) | return 0 | endif
"
" Add the words in properly indented and formatted lines
"
let l:lnum = a:start-1
let l:current = repeat(' ', VimtexIndent(a:start))
for l:word in l:words
if len(l:word) + len(l:current) > &tw
call append(l:lnum, substitute(l:current, '\s$', '', ''))
let l:lnum += 1
let l:current = repeat(' ', VimtexIndent(a:start))
endif
let l:current .= l:word . ' '
endfor
if l:current !~# '^\s*$'
call append(l:lnum, substitute(l:current, '\s$', '', ''))
let l:lnum += 1
endif
"
" Remove old text
"
silent! execute printf('%s;+%s delete', l:lnum+1, a:end-a:start)
"
" Return the difference between number of lines of old and new text
"
return l:lnum - a:end
endfunction
" }}}1
function! s:compare_lines(new, old) " {{{1
let l:min_length = min([len(a:new), len(a:old)])
for l:i in range(l:min_length)
if a:new[l:i] !=# a:old[l:i]
return l:i
endif
endfor
return l:min_length
endfunction endfunction
" }}}1 " }}}1

View File

@ -17,31 +17,31 @@ let s:cpo_save = &cpo
set cpo&vim set cpo&vim
setlocal autoindent setlocal autoindent
setlocal indentexpr=VimtexIndent() setlocal indentexpr=VimtexIndent(v:lnum)
setlocal indentkeys& setlocal indentkeys&
setlocal indentkeys+=[,(,{,),},],\&,=item setlocal indentkeys+=[,(,{,),},],\&,=item
function! VimtexIndent() " {{{1 function! VimtexIndent(lnum) " {{{1
let l:nprev = s:get_prev_line(prevnonblank(v:lnum - 1)) let l:nprev = s:get_prev_line(prevnonblank(a:lnum - 1))
if l:nprev == 0 | return 0 | endif if l:nprev == 0 | return 0 | endif
" Get current and previous line and remove comments " Get current and previous line and remove comments
let l:cur = substitute(getline(v:lnum), '\\\@<!%.*', '', '') let l:cur = substitute(getline(a:lnum), '\\\@<!%.*', '', '')
let l:prev = substitute(getline(l:nprev), '\\\@<!%.*', '', '') let l:prev = substitute(getline(l:nprev), '\\\@<!%.*', '', '')
" Check for verbatim modes " Check for verbatim modes
if s:is_verbatim(l:cur, v:lnum) if s:is_verbatim(l:cur, a:lnum)
return empty(l:cur) ? indent(l:nprev) : indent(v:lnum) return empty(l:cur) ? indent(l:nprev) : indent(a:lnum)
endif endif
" Align on ampersands " Align on ampersands
if l:cur =~# '^\s*&' && l:prev =~# '\\\@<!&.*' if l:cur =~# '^\s*&' && l:prev =~# '\\\@<!&.*'
return indent(v:lnum) + match(l:prev, '\\\@<!&') - stridx(l:cur, '&') return indent(a:lnum) + match(l:prev, '\\\@<!&') - stridx(l:cur, '&')
endif endif
" Use previous indentation for comments " Use previous indentation for comments
if l:cur =~# '^\s*%' if l:cur =~# '^\s*%'
return indent(v:lnum) return indent(a:lnum)
endif endif
let l:nprev = s:get_prev_line(l:nprev, 'ignore-ampersands') let l:nprev = s:get_prev_line(l:nprev, 'ignore-ampersands')
@ -50,7 +50,7 @@ function! VimtexIndent() " {{{1
let l:ind = indent(l:nprev) let l:ind = indent(l:nprev)
let l:ind += s:indent_envs(l:cur, l:prev) let l:ind += s:indent_envs(l:cur, l:prev)
let l:ind += s:indent_delims(l:cur, l:prev) let l:ind += s:indent_delims(l:cur, l:prev, a:lnum)
let l:ind += s:indent_tikz(l:nprev, l:prev) let l:ind += s:indent_tikz(l:nprev, l:prev)
return l:ind return l:ind
endfunction endfunction
@ -105,8 +105,8 @@ let s:envs_begitem = s:envs_item . '\|' . s:envs_beglist
let s:envs_enditem = s:envs_item . '\|' . s:envs_endlist let s:envs_enditem = s:envs_item . '\|' . s:envs_endlist
" }}}1 " }}}1
function! s:indent_delims(cur, prev) " {{{1 function! s:indent_delims(cur, prev, lnum) " {{{1
let [l:open, l:close] = vimtex#delim#get_valid_regexps(v:lnum, col('.')) let [l:open, l:close] = vimtex#delim#get_valid_regexps(a:lnum, col('.'))
return &sw*( max([s:count(a:prev, l:open) - s:count(a:prev, l:close), 0]) return &sw*( max([s:count(a:prev, l:open) - s:count(a:prev, l:close), 0])
\ - max([s:count(a:cur, l:close) - s:count(a:cur, l:open), 0])) \ - max([s:count(a:cur, l:close) - s:count(a:cur, l:open), 0]))
endfunction endfunction

View File

@ -168,9 +168,8 @@ Expect tex (Verify):
distribution over $x^u$ when sampled at label $\vec x$ some time later; another distribution over $x^u$ when sampled at label $\vec x$ some time later; another
population started around $\vec x_1$ carries a different history when it, too, population started around $\vec x_1$ carries a different history when it, too,
visits $\vec x$ later. Therefore, for instance the effective drift $\vec v(\vec visits $\vec x$ later. Therefore, for instance the effective drift $\vec v(\vec
x)$ will be different in the two cases. We conclude that, if unobserved x)$ will be different in the two cases. We conclude that, if unobserved degrees
degrees of freedom have dynamics on the time scale of the experiment of freedom have dynamics on the time scale of the experiment eq.~\ref{eq:fpe}
eq.~\ref{eq:fpe} is an approximation whose coefficients become is an approximation whose coefficients become \emph{non-universal} (dependent
\emph{non-universal} (dependent on intial conditions) and on intial conditions) and \emph{time-dependent}.
\emph{time-dependent}.