0

Under regular conditions, the tab key will insert a tab character and backspacing that tab deletes the whole tab character.

I have set up expandtab and softtabstop=4 so that when I hit tab it will insert 4 spaces and when I hit "ctrl-v-tab" it will insert a real tab. However, when I backspace real tabs, it will convert it to spaces and delete only 4 of those, leaving 4 behind (apparently backspace behavior is also affected by the softtabstop setup).

How can I set it up so that tab always deletes the whole tab character?

  • Is your tabstop set to 8? I believe your configuration is intended to do the exact opposite of what you want to do. If you :set tabstop=4 or :set softtabstop=8 it'd be a different story. – B Layer Jul 3 '17 at 14:47
  • Indeed tabstop is set to 8; I still want to see tabs as occupying 8 spaces but I want to insert indents with 4 spaces. I just would prefer it not to change backspace behavior. – Nordico Jul 3 '17 at 14:52
  • Right. But since the intended behavior of your configuration is to not allow the behavior you're seeking you'd probably have to do some key mapping or other personal customization to get there...which may be exactly what you're asking for. – B Layer Jul 3 '17 at 14:55
  • If no one has an easier way you might build something based on this :inoremap <BS> <C-O>X – B Layer Jul 3 '17 at 15:08
  • Not quite there because that seems to be deleting the character previous to the one I want to delete ('adf_' => 'af_'). I did think perhaps of mapping something like left arrow + supr to the backspace, which I'm not sure can be done and would be kind of dirty. – Nordico Jul 3 '17 at 19:07
1

For kicks and because I'm trying to learn some Vim scripting here is a more elaborate solution.

This will handle backspace the way you expect, even if cursor is in first column (in which case it will join with the preceding line).

First add this to your vimrc:

" Sends equivalent of backspace key in Insert mode unless preceding
" character is a Tab in which case a Normal mode 'X' is sent. Allows
" backspace to completely delete Tab even if 'softtabstop' is set to
" a value less than the 'tabstop' setting
function! SmartBackSpace()
  if getline('.')[col('.') - 2] == "\<Tab>"
    normal! X
  else
    call feedkeys("^H")
  endif
endfunction

^H is an actual control character entered by hitting Ctrl-V followed by Ctrl-H.

Then add this mapping:

inoremap <BS> <C-\><C-O>:call SmartBackSpace()<CR>
  • 1. why the <C-\> in your mapping? 2. you don't need exe in the first conditional branch. 3. you can use normal! ~ instead of call feedkeys("^C ~"). – Ryan Lue Jul 4 '17 at 13:35
  • (To be clear, exe is useful when you want to use a variable in a command, like let insert = col('.') == 1 ? 'i' : 'a'; exec 'normal! ' . insert . '^H'.) – Ryan Lue Jul 4 '17 at 13:39
  • For the second/third conditional 'normal!' is not working for all cases. However, it works for the first and in playing around with it further I combined second/third conditionals into a single feedkeys with just ctrl-H. Thanks for the direct improvement and indirectly leading me to the other improvement! – B Layer Jul 4 '17 at 13:54
  • The <C-\> was required to prevent cursor from moving when using <C-O>. See :help i_CTRL-\_CTRL-O – B Layer Jul 4 '17 at 14:00
1

This mapping will take you out of Insert mode briefly and delete the previous character with 'X' rather than backspace before re-entering Insert mode:

inoremap <BS> <C-\><C-O>X

It seems to do the trick for most cases though there may be some edge cases not yet discovered. If there are too many issues I imagine mapping backspace to a simple function that looks at the previous character before deciding whether to use X or BS. That's the only way, for example, that you could retain the ability of backspace to "unwrap" or delete from the beginning of a line to end of the previous line and such which folks often enable in their vimrc files with lines like set backspace=eol,start,indent

Note: I first suggested something like this mapping in a comment but I hadn't accounted for the cursor movement wonkiness when entering Normal mode (in the middle of the line behaves differently from the end of the line). The Ctrl-\ should take care of it.

  • Sorry to be such a nuisance, this almost gets it but the only problem is that now I cannot delete newline characters with backspace. (Note: also, I did see your other reply, but I would like to configure this only using vim customization without scripting). EDIT: now I see that you mention exactly this; are you sure there is no configurable way to do this? – Nordico Jul 4 '17 at 16:05
  • I don't know how it can be done without conditional logic of some kind. It may be possible to inline the function script in the key mapping. – B Layer Jul 4 '17 at 22:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.