Question

It seems if we enable 'ai', vim will fill the the leading space with tabstop. I can make it fill with just space with 'et'. I don't like a C file mixed with space and tabstop.

My vimrc:

set ts=4 et
set ai
set hlsearch
syntax on
filetype plugin indent on
autocmd FileType make setlocal noexpandtab

However, in some condition I do need to input tabstop when I hit the 'TAB' on keyboard, for example, in makefile and some others. The 'autocmd FileType' command is not good: I can't add every file type in vimrc.

What I want is simple:

  1. autoindent to fill leading area with space;
  2. when hit 'TAB' on keyboard, tabstop input, not space (so no 'et')

How to do it?

Was it helpful?

Solution

inoremap <expr> <tab> ((getline('.')[:col('.')-2]=~'\S')?("\<C-v>\t"):(repeat(' ', &ts-((virtcol('.')-1)%&ts))))

It does the same as @Lynch answer if I read it correctly.

You can also use <C-v><Tab>: this will insert <Tab> without invoking any mappings and ignores expandtab unless you remapped <C-v> or <C-v><Tab> for some reason.

If you want to just insert tab do

inoremap <Tab> <C-v><Tab>

It will ignore expandtab setting.

OTHER TIPS

I did it using a function. I tested it, but maybe in some particular case you will have to fix some bugs. Try adding this to your vimrc:

set et

function! Inserttab()
    let insert = ""
    let line = getline('.')
    let pos = getpos('.')[2]
    let before = ""
    let after = line
    if pos != 1
        let before = line[ 0: pos - 1]  
        let after = line[pos : strlen(line) ]
    endif
    if pos != 1 && substitute(before, "[ \t]", "", "g") != "" 
         let insert = "\t"
    else
         let insert = "    "
    endif
    let line = before . insert . after 
    call setline('.', line)
    call cursor(line('.'), strlen(before . insert))
endfunction

inoremap <tab> <esc>:call Inserttab()<CR>a

Basicaly it does remap your key in visual mode to the function Inserttab(). Also note that if you change ts for something other than 4 it will still output 4 spaces instead of two because the value is hard coded.

Also im not very familiar with vim scripts, but I think all the variables used will be global which is a bad thing.

I forgot to mention that to "see" white spaces you can use set list. You disable this with set nolist. Also in normal mode you can use ga to see information about the character your cursor is on.

Edit I realise that you may want to insert tab at the beginin of the line. My script insert space at the begining and tab anywhere else.

If you really want a tab every time you hit tab key you could simply use this:

set et

function! Inserttab()
    let insert = ""
    let line = getline('.')
    let pos = getpos('.')[2]
    let before = ""
    let after = line
    if pos != 1
        let before = line[ 0: pos - 1]  
        let after = line[pos : strlen(line) ]
    endif
    let insert = "\t"
    let line = before . insert . after 
    call setline('.', line)
    call cursor(line('.'), strlen(before . insert))
endfunction

inoremap <tab> <esc>:call Inserttab()<CR>a

But I dont see the point, with this version you will never be able to indent manually from insert mode.

One way to do it is

  1. :set sw=4 (or whatever you want)
  2. :set ts=46 (or some large number)

Then autoindent will not insert tabs unless you reach 46 spaces, in which case you can put in a higher number.

Only drag about this is if someone else is using tabs, then you have to reset ts to agree with the file you are editing. On the other hand, it will make the tabs immediately obvious, which can be desirable as well.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top