Skip to content

Instantly share code, notes, and snippets.

@adscriven
Last active February 22, 2020 23:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save adscriven/60888c29d8928ccad773d3452ce05953 to your computer and use it in GitHub Desktop.
Save adscriven/60888c29d8928ccad773d3452ce05953 to your computer and use it in GitHub Desktop.
Vim: guess indentation
" guessindent.vim -- Guess indentation settings.
" [ ] Don't match continuation lines
" This works better for code rather than for arbitrarily formatted files
" such as the help files, though it sometimes gets those right too. If
" somebody has edited with `set noet ts=4` in a file where `set et sw=4`
" should be used, there's no easy way to detect that. You'll probably
" get ts=8 in that situation, but the file will need fixing anyway.
fun! s:guessindent()
let view = winsaveview()
" Try to avoid funky formatting at the start of a file by
" starting at line 100 or midway, whichever is sooner.
let mid = line('$') / 2
exe mid > 100 ? 100 : mid
call search('^\\\@!\S.*\(\s*\n\)*\s*\S', 'b')
let tabindent = search('^\t\s*\S', 'cn')
let &l:et = !tabindent
" Shortest run of spaces for indentation. Ignore <2 and >8.
let shortpat = '^ \{2,8}\ze\\\@!\S'
let short = len(matchstr(getline(search(shortpat, 'cn')), shortpat))
" Longest run of spaces before a tab.
let longpat = '^ \+\ze\S.*\n\%(\s*\n\)*\t'
let long = len(matchstr(getline(search(longpat, 'cn')), longpat))
" If we've a short run of spaces, that must be the 'sw'.
" If there are tabs but no spaces, set 'sw' to zero.
" Otherwise give up and use the existing value of 'sw'.
let &l:sw = short ? short : (tabindent ? 0 : &sw)
" Let 'sts' track 'sw'. Don't overcomplicate matters.
let &l:sts = -1
" If there are spaces as well as tabs for indentation,
" 'ts' is probably the shortest run plus the longest, since
" 'sw' < 'ts' was probably used with 'noet' when creating the
" file (e.g. `set ts=8 sw=2 noet`).
let ts = short + long
" Sanity check for this fool's errand.
" 'ts' has to be a multiple of four and > 'sw'. Otherwise default to 8.
let &l:ts = ts%4 || ts<=&l:sw ? 8 : ts
call winrestview(view)
endfun
augroup guessindent
au!
au stdinreadpost,filterreadpost,filereadpost,bufreadpost,bufwritepost
\ * call s:guessindent()
augroup END
com! Guessindent call s:guessindent()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment