summaryrefslogtreecommitdiffstats
path: root/plugin
diff options
context:
space:
mode:
Diffstat (limited to 'plugin')
-rw-r--r--plugin/sleuth.vim164
1 files changed, 164 insertions, 0 deletions
diff --git a/plugin/sleuth.vim b/plugin/sleuth.vim
new file mode 100644
index 00000000..12086173
--- /dev/null
+++ b/plugin/sleuth.vim
@@ -0,0 +1,164 @@
+" Heuristically set buffer options
+"
+" Modified version of vim-sleuth:
+" - softtab and tabstop reduced from 8 to 2
+" - number of considered lines reduced from 1024 to 64
+" - maximum 6 other files are checked instead of 20
+" - check maximum of files 2 per directory level instead of 8
+" - maximum of 3 directory levels are checked
+" - globs are concatenated for performance
+
+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(' ', 2)
+
+ 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 &filetype ==# 'go' && 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 = 2
+ endif
+ endif
+
+ return options
+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, 64))
+ if s:apply_if_ready(options)
+ return
+ endif
+ let c = 6
+ let pattern = c > 0 ? sleuth#GlobForFiletype(&filetype) : ''
+ let dir = expand('%:p:h')
+ let level = 3
+ while isdirectory(dir) && dir !=# fnamemodify(dir, ':h') && c > 0 && level > 0
+ let level -= 1
+ for neighbor in glob(dir.'/'.pattern,0,1)[0:1]
+ if neighbor !=# expand('%:p') && filereadable(neighbor)
+ call extend(options, s:guess(readfile(neighbor, '', 32)), '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
+ 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
+
+augroup polyglot
+ autocmd!
+ autocmd FileType * call s:detect()
+augroup END