aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Ryder <tom@sanctum.geek.nz>2020-05-30 01:26:38 +1200
committerTom Ryder <tom@sanctum.geek.nz>2020-05-30 01:26:38 +1200
commita63efdf37c88e8ec76b7724c6a673cb5dd833c32 (patch)
tree899a66faeced1e89737415e07580880e5f9b538c
parentCorrect b:undo_indent setting in detect_indent.vim (diff)
downloaddotfiles-a63efdf37c88e8ec76b7724c6a673cb5dd833c32.tar.gz
dotfiles-a63efdf37c88e8ec76b7724c6a673cb5dd833c32.zip
Arrange and comment code for new plugin
Nearly done
-rw-r--r--vim/autoload/detect_indent.vim67
-rw-r--r--vim/plugin/detect_indent.vim12
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 *