summaryrefslogtreecommitdiff
path: root/opt/sleuth/plugin/sleuth.vim
diff options
context:
space:
mode:
authorMichael Smith <mikesmiffy128@gmail.com>2022-05-22 22:47:23 +0100
committerMichael Smith <mikesmiffy128@gmail.com>2022-05-22 22:47:23 +0100
commit95aea6b533e71e478d61d18fac71cca116c56a4d (patch)
tree1a1f42f723772258cc54551495826768f374474a /opt/sleuth/plugin/sleuth.vim
Add all the plugins I currently use
Diffstat (limited to 'opt/sleuth/plugin/sleuth.vim')
-rw-r--r--opt/sleuth/plugin/sleuth.vim206
1 files changed, 206 insertions, 0 deletions
diff --git a/opt/sleuth/plugin/sleuth.vim b/opt/sleuth/plugin/sleuth.vim
new file mode 100644
index 0000000..e5f6355
--- /dev/null
+++ b/opt/sleuth/plugin/sleuth.vim
@@ -0,0 +1,206 @@
+" sleuth.vim - Heuristically set buffer options
+" Maintainer: Tim Pope <http://tpo.pe/>
+" Version: 1.1
+" GetLatestVimScripts: 4375 1 :AutoInstall: sleuth.vim
+
+if exists("g:loaded_sleuth") || v:version < 700 || &cp
+ finish
+endif
+let g:loaded_sleuth = 1
+
+function! s:guess(lines) abort
+ let options = {}
+ let heuristics = {'spaces': 0, 'hard': 0, 'soft': 0}
+ let ccomment = 0
+ let podcomment = 0
+ let triplequote = 0
+ let backtick = 0
+ let xmlcomment = 0
+ let softtab = repeat(' ', 8)
+
+ for line in a:lines
+ if !len(line) || line =~# '^\s*$'
+ continue
+ endif
+
+ if line =~# '^\s*/\*'
+ let ccomment = 1
+ endif
+ if ccomment
+ if line =~# '\*/'
+ let ccomment = 0
+ endif
+ continue
+ endif
+
+ if line =~# '^=\w'
+ let podcomment = 1
+ endif
+ if podcomment
+ if line =~# '^=\%(end\|cut\)\>'
+ let podcomment = 0
+ endif
+ continue
+ endif
+
+ if triplequote
+ if line =~# '^[^"]*"""[^"]*$'
+ let triplequote = 0
+ endif
+ continue
+ elseif line =~# '^[^"]*"""[^"]*$'
+ let triplequote = 1
+ endif
+
+ if backtick
+ if line =~# '^[^`]*`[^`]*$'
+ let backtick = 0
+ endif
+ continue
+ elseif line =~# '^[^`]*`[^`]*$'
+ let backtick = 1
+ endif
+
+ if line =~# '^\s*<\!--'
+ let xmlcomment = 1
+ endif
+ if xmlcomment
+ if line =~# '-->'
+ let xmlcomment = 0
+ endif
+ continue
+ endif
+
+ if line =~# '^\t'
+ let heuristics.hard += 1
+ elseif line =~# '^' . softtab
+ let heuristics.soft += 1
+ endif
+ if line =~# '^ '
+ let heuristics.spaces += 1
+ endif
+ let indent = len(matchstr(substitute(line, '\t', softtab, 'g'), '^ *'))
+ if indent > 1 && (indent < 4 || indent % 2 == 0) &&
+ \ get(options, 'shiftwidth', 99) > indent
+ let options.shiftwidth = indent
+ endif
+ endfor
+
+ if heuristics.hard && !heuristics.spaces
+ return {'expandtab': 0, 'shiftwidth': &tabstop}
+ elseif heuristics.soft != heuristics.hard
+ let options.expandtab = heuristics.soft > heuristics.hard
+ if heuristics.hard
+ let options.tabstop = 8
+ endif
+ endif
+
+ 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'],
+ \ 'vim': ['vimrc', '.vimrc', '_vimrc'],
+ \ }
+ 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
+ return 1
+ endif
+endfunction
+
+function! s:detect() abort
+ if &buftype ==# 'help'
+ return
+ endif
+
+ let options = s:guess(getline(1, 1024))
+ if s:apply_if_ready(options)
+ return
+ endif
+ let c = get(b:, 'sleuth_neighbor_limit', get(g:, 'sleuth_neighbor_limit', 20))
+ let patterns = c > 0 ? s:patterns_for(&filetype) : []
+ call filter(patterns, 'v:val !~# "/"')
+ let dir = expand('%:p:h')
+ while isdirectory(dir) && dir !=# fnamemodify(dir, ':h') && c > 0
+ for pattern in patterns
+ for neighbor in split(glob(dir.'/'.pattern), "\n")[0:7]
+ if neighbor !=# expand('%:p') && filereadable(neighbor)
+ call extend(options, s:guess(readfile(neighbor, '', 256)), 'keep')
+ let c -= 1
+ endif
+ if s:apply_if_ready(options)
+ let b:sleuth_culprit = neighbor
+ return
+ endif
+ if c <= 0
+ break
+ endif
+ endfor
+ if c <= 0
+ break
+ endif
+ endfor
+ let dir = fnamemodify(dir, ':h')
+ endwhile
+ 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
+
+function! SleuthIndicator() abort
+ let sw = &shiftwidth ? &shiftwidth : &tabstop
+ if &expandtab
+ return 'sw='.sw
+ elseif &tabstop == sw
+ return 'ts='.&tabstop
+ else
+ return 'sw='.sw.',ts='.&tabstop
+ endif
+endfunction
+
+augroup sleuth
+ autocmd!
+ autocmd FileType *
+ \ if get(b:, 'sleuth_automatic', get(g:, 'sleuth_automatic', 1))
+ \ | call s:detect() | endif
+ autocmd User Flags call Hoist('buffer', 5, 'SleuthIndicator')
+augroup END
+
+command! -bar -bang Sleuth call s:detect()
+
+" vim:set et sw=2: