diff options
author | Tom Ryder <tom@sanctum.geek.nz> | 2020-05-30 01:26:38 +1200 |
---|---|---|
committer | Tom Ryder <tom@sanctum.geek.nz> | 2020-05-30 01:26:38 +1200 |
commit | a63efdf37c88e8ec76b7724c6a673cb5dd833c32 (patch) | |
tree | 899a66faeced1e89737415e07580880e5f9b538c | |
parent | Correct b:undo_indent setting in detect_indent.vim (diff) | |
download | dotfiles-a63efdf37c88e8ec76b7724c6a673cb5dd833c32.tar.gz dotfiles-a63efdf37c88e8ec76b7724c6a673cb5dd833c32.zip |
Arrange and comment code for new plugin
Nearly done
-rw-r--r-- | vim/autoload/detect_indent.vim | 67 | ||||
-rw-r--r-- | vim/plugin/detect_indent.vim | 12 |
2 files changed, 69 insertions, 10 deletions
diff --git a/vim/autoload/detect_indent.vim b/vim/autoload/detect_indent.vim index 6be81eda..b4de2159 100644 --- a/vim/autoload/detect_indent.vim +++ b/vim/autoload/detect_indent.vim @@ -1,55 +1,104 @@ +" Numeric comparison function to sort in a Vim v7.0 compatible way function s:CompareNumeric(a, b) return a:a > a:b ? 1 : -1 endfunction +" Entry point for plugin function detect_indent#() abort + " For spaces, we count both the total space-indented lines, and also the + " count of lines indexed by space count, so that if we need to, we can + " figure out a good 'shiftwidth' setting; for tabs, we just count the + " indented lines, since we won't need to set 'shiftwidth' for that. + " + let tabs = 0 let spaces = { \ 'hist': {}, \ 'total': 0, \} - let tabs = 0 + + " Figure out how many lines we'll check; cap this to 1,024 let total = max([line('$'), 1024]) - for lnum in range(1, total) - let line = getline(lnum) - let tabs += matchstr(line, '^\t*') != '' + " Iterate through the lines + for line in getline(1, total) + + " If there are leading tabs, we'll call this a tab-indented line; bump the + " appropriate count, and skip the rest of the loop. + " + if matchstr(line, '^\t*') !=# '' + let tabs += 1 + continue + endif + + " Figure out count of space indenting; skip to the next line if it's zero let indent = strlen(matchstr(line, '^ *')) if indent == 0 continue endif + + " Increment the count of space-indented lines + let spaces['total'] += 1 + + " Create a dictionary entry in the histogram for this indent if necessary, + " and increment that counter + " if !has_key(spaces['hist'], indent) let spaces['hist'][indent] = 0 endif let spaces['hist'][indent] += 1 - let spaces['total'] += 1 + endfor - if &expandtab == (spaces['total'] > tabs) + " If the value for 'expandtab' as determined by the user's configuration + " matches the expected dominance of space-indented lines over tab-indented + " lines, we're already using the right setting, and we stop here + " + if &expandtab == (spaces['total'] >= tabs) return endif + " If 'expandtab' is set, we need to unset it and switch to pure tab + " indenting; that's straightforward, we just need to make sure 'shiftwidth' + " matches 'tabstop', and that 'softtabstop' is off. + " if &expandtab setlocal noexpandtab softtabstop=0 let &l:shiftwidth = &tabstop + + " If 'expandtab' is not set, we need to set it, and guess an appropriate + " 'shiftwidth'. else setlocal expandtab + + " Iterate through the keys of the histogram from smallest to largest. + " We'll accept as our 'shiftwidth' the smallest indent level that + " constitutes more than 5% of the total lines. This is just an heuristic, + " but it seems to work pretty well. + " let shiftwidth = 0 let indents = keys(spaces['hist']) - call map(indents, 'str2nr(v:val)') - call sort(indents, 's:CompareNumeric') + call map(indents, 'str2nr(v:val)') " Coerce the string keys to numeric + call sort(indents, 's:CompareNumeric') " Force numeric sort for shiftwidth in indents if spaces['hist'][shiftwidth] * 100 / spaces['total'] >= 5 break endif endfor + + " We have our 'shiftwidth'; set it, with 'softtabstop' set to match let &l:shiftwidth = shiftwidth let &l:softtabstop = shiftwidth + endif + " Since we just messed with indent settings, stack up a command to revert + " the changes when the indent plugin is unloaded, as if we ourselves were + " a single filetype indent plugin. + " let undo_indent = 'setlocal expandtab< shiftwidth< softtabstop<' if exists('b:undo_indent') - let b:undo_indent .= '|'.undo_indent + let b:undo_indent .= '|' . undo_indent else let b:undo_indent = undo_indent endif diff --git a/vim/plugin/detect_indent.vim b/vim/plugin/detect_indent.vim index fef4b65e..e75324ac 100644 --- a/vim/plugin/detect_indent.vim +++ b/vim/plugin/detect_indent.vim @@ -1,11 +1,21 @@ -if exists('loaded_detect_indent') || &compatible +" +" detect_indent.vim: If 'expandtab' doesn't match the shape of the buffer's +" indents, switch it over, including a guess at 'shiftwidth' if switching it +" on. +" +" Author: Tom Ryder <tom@sanctum.geek.nz> +" License: Same as Vim itself +" +if exists('loaded_detect_indent') || &compatible || v:version < 700 finish endif let loaded_detect_indent = 1 +" Set up a user command in case the user wants to set this manually command! -bar DetectIndent \ call detect_indent#() +" Add hook for FileType event; this should load *after* filetype plugins augroup detect_indent autocmd! autocmd FileType * |