" sleuth.vim - Heuristically set buffer options " Maintainer: Tim Pope " Version: 1.0 if exists("g:loaded_sleuth") || v:version < 700 || &cp finish endif let g:loaded_sleuth = 1 function! s:guess(lines) abort let options = {} let ccomment = 0 for line in a:lines if line =~# '^\s\+$' continue endif if line =~# '^\s*/\*' let ccomment = 1 endif if ccomment if line =~# '\*/' let ccomment = 0 endif continue endif let softtab = repeat(' ', 8) if line =~# '^\t' let options.expandtab = 0 elseif line =~# '^' . softtab let options.expandtab = 1 endif let indent = len(matchstr(substitute(line, '\t', softtab, 'g'), '^ *')) if indent > 1 && get(options, 'shiftwidth', 99) > indent let options.shiftwidth = indent endif endfor return options endfunction function! s:patterns_for(type) abort if a:type ==# '' return [] endif if !exists('s:patterns') redir => capture silent autocmd BufRead redir END let patterns = { \ 'c': ['*.c'], \ 'html': ['*.html'], \ 'sh': ['*.sh'], \ } let setfpattern = '\s\+\%(setf\%[iletype]\s\+\|set\%[local]\s\+\%(ft\|filetype\)=\|call SetFileTypeSH(["'']\%(ba\|k\)\=\%(sh\)\@=\)' for line in split(capture, "\n") let match = matchlist(line, '^\s*\(\S\+\)\='.setfpattern.'\(\w\+\)') if !empty(match) call extend(patterns, {match[2]: []}, 'keep') call extend(patterns[match[2]], [match[1] ==# '' ? last : match[1]]) endif let last = matchstr(line, '\S.*') endfor let s:patterns = patterns endif return copy(get(s:patterns, a:type, [])) endfunction function! s:apply_if_ready(options) abort if !has_key(a:options, 'expandtab') || !has_key(a:options, 'shiftwidth') return 0 else for [option, value] in items(a:options) call setbufvar('', '&'.option, value) endfor if &verbose echomsg string(a:options) endif return 1 endif endfunction function! s:detect() abort let options = s:guess(getline(1, 1024)) if s:apply_if_ready(options) return endif let patterns = s:patterns_for(&filetype) call filter(patterns, 'v:val !~# "/"') if !empty(patterns) let pattern = len(patterns) == 1 ? patterns[0] : '{'.join(patterns, ',').'}' let dir = expand('%:p:h') while isdirectory(dir) && dir !=# fnamemodify(dir, ':h') for neighbor in split(glob(dir.'/'.pattern), "\n") if neighbor !=# expand('%:p') call extend(options, s:guess(readfile(neighbor, '', 1024)), 'keep') endif if s:apply_if_ready(options) return endif endfor let dir = fnamemodify(dir, ':h') endwhile endif if has_key(options, 'shiftwidth') return s:apply_if_ready(extend({'expandtab': 1}, options)) endif endfunction setglobal smarttab if !exists('g:did_indent_on') filetype indent on endif augroup sleuth autocmd! autocmd FileType * call s:detect() augroup END " vim:set et sw=2: