From 41ecf7764d0b0022484543a3f61629edf20eabf9 Mon Sep 17 00:00:00 2001 From: David Briscoe Date: Wed, 25 Feb 2015 13:18:57 -0800 Subject: [PATCH 1/4] Use a single method to set indentation Add s:SetIndent() so we can set our desired indentation consistently. It always sets expandtab and sets widths only if valid (positive nonzero). I'm following the advice laid out on the 'tabstop' help about when softtabstop is set and ensuring some settings have the same value. That documentation recommends using softtabstop with noexpandtab and not with expandtab. (Whereas detectindent used to do the opposite.) TODO: I'm no longer convinced that my reading is correct in this case since softtabstop isn't useful when tabstop and shiftwidth are the same. Maybe I should always set it? --- plugin/detectindent.vim | 55 ++++++++++++++++++++++++----------------- 1 file changed, 33 insertions(+), 22 deletions(-) diff --git a/plugin/detectindent.vim b/plugin/detectindent.vim index d903948..22dd976 100644 --- a/plugin/detectindent.vim +++ b/plugin/detectindent.vim @@ -56,6 +56,33 @@ fun! s:GetValue(option) endif endfun +fun! s:SetIndent(expandtab, desired_tabstop) + let &l:expandtab = a:expandtab + + " Only modify tabs if we have a valid value. + if a:desired_tabstop > 0 + " See advice on `:help 'tabstop'` for logic of which values are set for + " what values of expandtab. + + let &l:tabstop = a:desired_tabstop + if v:version >= 704 + " Zero automatically keeps in sync with tabstop in Vim 7.4+. + setl shiftwidth=0 + else + let &l:shiftwidth = a:desired_tabstop + endif + + if !a:expandtab + if v:version >= 704 + " Negative value automatically keeps in sync with shiftwidth in Vim 7.4+. + setl softtabstop=-1 + else + let &l:softtabstop = a:desired_tabstop + endif + endif + endif +endfun + fun! DetectIndent() let l:has_leading_tabs = 0 let l:has_leading_spaces = 0 @@ -138,24 +165,21 @@ fun! DetectIndent() if l:has_leading_tabs && ! l:has_leading_spaces " tabs only, no spaces let l:verbose_msg = "Detected tabs only and no spaces" - setl noexpandtab if s:GetValue("detectindent_preferred_indent") - let &l:shiftwidth = g:detectindent_preferred_indent - let &l:tabstop = g:detectindent_preferred_indent + call s:SetIndent(0, g:detectindent_preferred_indent) + else + setl noexpandtab 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 + call s:SetIndent(1, l:shortest_leading_spaces_run) elseif l:has_leading_spaces && l:has_leading_tabs && ! s:GetValue("detectindent_preferred_when_mixed") " spaces and tabs let l:verbose_msg = "Detected spaces and tabs" - setl noexpandtab - let &l:shiftwidth = l:shortest_leading_spaces_run + call s:SetIndent(0, l:shortest_leading_spaces_run) " mmmm, time to guess how big tabs are if l:longest_leading_spaces_run <= 2 @@ -169,20 +193,7 @@ fun! DetectIndent() else " no spaces, no tabs let l:verbose_msg = s:GetValue("detectindent_preferred_when_mixed") ? "preferred_when_mixed is active" : "Detected no spaces and no tabs" - if s:GetValue("detectindent_preferred_indent") && - \ (s:GetValue("detectindent_preferred_expandtab")) - setl expandtab - let &l:shiftwidth = g:detectindent_preferred_indent - let &l:softtabstop = g:detectindent_preferred_indent - elseif s:GetValue("detectindent_preferred_indent") - setl noexpandtab - let &l:shiftwidth = g:detectindent_preferred_indent - let &l:tabstop = g:detectindent_preferred_indent - elseif s:GetValue("detectindent_preferred_expandtab") - setl expandtab - else - setl noexpandtab - endif + call s:SetIndent(s:GetValue("detectindent_preferred_expandtab"), s:GetValue("detectindent_preferred_indent")) endif From 294ae712971352b7154fa87da13024830bf898b5 Mon Sep 17 00:00:00 2001 From: David Briscoe Date: Wed, 25 Feb 2015 13:32:03 -0800 Subject: [PATCH 2/4] Do not use shiftwidth=0 shiftwidth=0 keeps it in sync with tabstop, but that breaks many indentation plugins that read 'sw' instead of calling the new shiftwidth(). See https://github.com/tpope/vim-sleuth/issues/25 Or try indenting this vimscript file on Vim 7.4. --- plugin/detectindent.vim | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/plugin/detectindent.vim b/plugin/detectindent.vim index 22dd976..1b2604e 100644 --- a/plugin/detectindent.vim +++ b/plugin/detectindent.vim @@ -65,12 +65,11 @@ fun! s:SetIndent(expandtab, desired_tabstop) " what values of expandtab. let &l:tabstop = a:desired_tabstop - if v:version >= 704 - " Zero automatically keeps in sync with tabstop in Vim 7.4+. - setl shiftwidth=0 - else - let &l:shiftwidth = a:desired_tabstop - endif + " NOTE: shiftwidth=0 keeps it in sync with tabstop, but that breaks + " many indentation plugins that read 'sw' instead of calling the new + " shiftwidth(). See + " https://github.com/tpope/vim-sleuth/issues/25 + let &l:shiftwidth = a:desired_tabstop if !a:expandtab if v:version >= 704 From 33f4522c80c1a155d0e4f4f8fc15c7145c6dcd5a Mon Sep 17 00:00:00 2001 From: David Briscoe Date: Wed, 25 Feb 2015 13:41:28 -0800 Subject: [PATCH 3/4] Better conform to tabstop help guidelines Always set softtabstop. This is more consistent with previous behavior and from reading the softtabstop help seems to make more sense that we set all of these values to the same thing. In the case where we find both tabs and spaces, now we set expandtab as described in #2: 2. Set 'tabstop' and 'shiftwidth' to whatever you prefer and use 'expandtab'. This way you will always insert spaces. The formatting will never be messed up when 'tabstop' is changed. Alternatively, we could follow #1 and set tabstop=8 (instead of guessing) and use noexpandtab: 1. Always keep 'tabstop' at 8, set 'softtabstop' and 'shiftwidth' to 4 (or 3 or whatever you prefer) and use 'noexpandtab'. Then Vim will use a mix of tabs and spaces, but typing and will behave like a tab appears every 4 (or 3) characters. That's what vim-sleuth does, so why copy their recipe? Guessing is probably more useful to users. --- plugin/detectindent.vim | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/plugin/detectindent.vim b/plugin/detectindent.vim index 1b2604e..a23fe9e 100644 --- a/plugin/detectindent.vim +++ b/plugin/detectindent.vim @@ -61,8 +61,8 @@ fun! s:SetIndent(expandtab, desired_tabstop) " Only modify tabs if we have a valid value. if a:desired_tabstop > 0 - " See advice on `:help 'tabstop'` for logic of which values are set for - " what values of expandtab. + " See `:help 'tabstop'`. We generally adhere to #1 or #4, but when + " guessing what to do for mixed tabs and spaces we use #2. let &l:tabstop = a:desired_tabstop " NOTE: shiftwidth=0 keeps it in sync with tabstop, but that breaks @@ -71,13 +71,11 @@ fun! s:SetIndent(expandtab, desired_tabstop) " https://github.com/tpope/vim-sleuth/issues/25 let &l:shiftwidth = a:desired_tabstop - if !a:expandtab - if v:version >= 704 - " Negative value automatically keeps in sync with shiftwidth in Vim 7.4+. - setl softtabstop=-1 - else - let &l:softtabstop = a:desired_tabstop - endif + if v:version >= 704 + " Negative value automatically keeps in sync with shiftwidth in Vim 7.4+. + setl softtabstop=-1 + else + let &l:softtabstop = a:desired_tabstop endif endif endfun @@ -178,7 +176,7 @@ fun! DetectIndent() elseif l:has_leading_spaces && l:has_leading_tabs && ! s:GetValue("detectindent_preferred_when_mixed") " spaces and tabs let l:verbose_msg = "Detected spaces and tabs" - call s:SetIndent(0, l:shortest_leading_spaces_run) + call s:SetIndent(1, l:shortest_leading_spaces_run) " mmmm, time to guess how big tabs are if l:longest_leading_spaces_run <= 2 From e6442a0222a2283c95d661bb86f40bf569835a2d Mon Sep 17 00:00:00 2001 From: David Briscoe Date: Wed, 4 Oct 2017 18:25:45 -0700 Subject: [PATCH 4/4] Ensure tab settings match on tabs-only file Default detectindent_preferred_indent behavior (0) is to retain current tabstop. But on a file containing only tabs, and user's default is to use shiftwidth=4, we end up with softtabstop=4, shiftwidth=4, tabstop=8, noexpandtabs Which means we insert tabs, but indent with >> inserts only half a tab (inserting 4 spaces). This madness occurs in python files containing tabs with g:python_recommended_style undefined or 1. --- plugin/detectindent.vim | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/plugin/detectindent.vim b/plugin/detectindent.vim index a23fe9e..9f43e45 100644 --- a/plugin/detectindent.vim +++ b/plugin/detectindent.vim @@ -162,11 +162,13 @@ fun! DetectIndent() if l:has_leading_tabs && ! l:has_leading_spaces " tabs only, no spaces let l:verbose_msg = "Detected tabs only and no spaces" - if s:GetValue("detectindent_preferred_indent") - call s:SetIndent(0, g:detectindent_preferred_indent) - else - setl noexpandtab + let indent = s:GetValue("detectindent_preferred_indent") + if indent == 0 + " Default behavior is to retain current tabstop. Still need to set + " it to ensure softtabstop, shiftwidth, tabstop are in sync. + let indent = &l:tabstop endif + call s:SetIndent(0, indent) elseif l:has_leading_spaces && ! l:has_leading_tabs " spaces only, no tabs