diff --git a/plugin/detectindent.vim b/plugin/detectindent.vim index 4801de1..b4024b5 100644 --- a/plugin/detectindent.vim +++ b/plugin/detectindent.vim @@ -17,7 +17,12 @@ " " impossible: " :let g:detectindent_preferred_indent = 4 " -" Requirements: Untested on Vim versions below 6.2 +" Requirements: Does not work on Vim versions below 7.0 + +" Bail out if we're on an old version of vim +if version < 700 + finish +endif if exists("loaded_detectindent") finish @@ -29,7 +34,7 @@ if !exists('g:detectindent_verbosity') endif fun! HasCStyleComments() - return index(["c", "cpp", "java", "javascript", "php"], &ft) != -1 + return index(["c", "cpp", "h", "java", "javascript", "php"], &ft) != -1 endfun fun! IsCommentStart(line) @@ -45,12 +50,22 @@ fun! IsCommentLine(line) return HasCStyleComments() && a:line =~ '^\s\+//' endfun +fun! GCD(x, y) + let l:a = a:x + let l:b = a:y + while l:b > 0 + let l:temp = l:b + let l:b = l:a % l:b + let l:a = l:temp + endwhile + return l:a +endfun + fun! DetectIndent() - let l:has_leading_tabs = 0 - let l:has_leading_spaces = 0 - let l:shortest_leading_spaces_run = 0 - let l:shortest_leading_spaces_idx = 0 - let l:longest_leading_spaces_run = 0 + let l:leading_tab_count = 0 + let l:leading_space_count = 0 + let l:leading_space_dict = {} + let l:leading_spaces_gcd = 0 let l:max_lines = 1024 if exists("g:detectindent_max_lines_to_analyse") let l:max_lines = g:detectindent_max_lines_to_analyse @@ -94,22 +109,15 @@ fun! DetectIndent() let l:leading_char = strpart(l:line, 0, 1) if l:leading_char == "\t" - let l:has_leading_tabs = 1 + let l:leading_tab_count = l:leading_tab_count + 1 elseif l:leading_char == " " " only interested if we don't have a run of spaces followed by a " tab. if -1 == match(l:line, '^ \+\t') - let l:has_leading_spaces = 1 + let l:leading_space_count = l:leading_space_count + 1 let l:spaces = strlen(matchstr(l:line, '^ \+')) - if l:shortest_leading_spaces_run == 0 || - \ l:spaces < l:shortest_leading_spaces_run - let l:shortest_leading_spaces_run = l:spaces - let l:shortest_leading_spaces_idx = l:idx - endif - if l:spaces > l:longest_leading_spaces_run - let l:longest_leading_spaces_run = l:spaces - endif + let l:leading_space_dict[l:spaces] = get(l:leading_space_dict, l:spaces) + 1 endif endif @@ -124,40 +132,36 @@ fun! DetectIndent() endwhile - if l:has_leading_tabs && ! l:has_leading_spaces - " tabs only, no spaces - let l:verbose_msg = "Detected tabs only and no spaces" + if l:leading_tab_count > l:leading_space_count + let l:verbose_msg = "Use tab to indent." setl noexpandtab if exists("g:detectindent_preferred_indent") let &l:shiftwidth = g:detectindent_preferred_indent let &l:tabstop = g:detectindent_preferred_indent endif - elseif l:has_leading_spaces && ! l:has_leading_tabs - " spaces only, no tabs - let l:verbose_msg = "Detected spaces only and no tabs" - setl expandtab - let &l:shiftwidth = l:shortest_leading_spaces_run - let &l:softtabstop = l:shortest_leading_spaces_run - - elseif l:has_leading_spaces && l:has_leading_tabs - " spaces and tabs - let l:verbose_msg = "Detected spaces and tabs" - setl noexpandtab - let &l:shiftwidth = l:shortest_leading_spaces_run + elseif l:leading_space_count > l:leading_tab_count + " Filter out those tab stops which occurred in < 10% of the lines + call filter(l:leading_space_dict, '100*v:val/l:leading_space_count >= 10') + + " Find the greatest common divisor of the remaining tab stop lengths + let l:leading_spaces_gcd = 0 + for length in keys(l:leading_space_dict) + if l:leading_spaces_gcd == 0 + let l:leading_spaces_gcd = length + else + let l:leading_spaces_gcd = GCD(length, l:leading_spaces_gcd) + endif + endfor - " mmmm, time to guess how big tabs are - if l:longest_leading_spaces_run <= 2 - let &l:tabstop = 2 - elseif l:longest_leading_spaces_run <= 4 - let &l:tabstop = 4 - else - let &l:tabstop = 8 + if l:leading_spaces_gcd != 0 + let l:verbose_msg = "Use space to indent." + setl expandtab + let &l:shiftwidth = l:leading_spaces_gcd + let &l:softtabstop = l:leading_spaces_gcd endif - else - " no spaces, no tabs - let l:verbose_msg = "Detected no spaces and no tabs" + let l:verbose_msg = "Cannot determine indent. Use default to indent." if exists("g:detectindent_preferred_indent") && \ exists("g:detectindent_preferred_expandtab") setl expandtab @@ -177,11 +181,9 @@ fun! DetectIndent() if &verbose >= g:detectindent_verbosity echo l:verbose_msg - \ ."; has_leading_tabs:" l:has_leading_tabs - \ .", has_leading_spaces:" l:has_leading_spaces - \ .", shortest_leading_spaces_run:" l:shortest_leading_spaces_run - \ .", shortest_leading_spaces_idx:" l:shortest_leading_spaces_idx - \ .", longest_leading_spaces_run:" l:longest_leading_spaces_run + \ ."; leading_tab_count:" l:leading_tab_count + \ .", leading_space_count:" l:leading_space_count + \ .", leading_spaces_gcd:" l:leading_spaces_gcd let changed_msg = [] for [setting, oldval] in items(b:detectindent_cursettings)