When expandtab is set, how to let the indent function defined in file vim/indent/xxx.vim use tabs, rather than spaces to indent lines?


Here is the background. I have use vim's built-in CHANGELOG syntax to write some change log, using a tab to indent but use spaces to align (|------> means a tab):

1.0.1 - 2021-03-21  lxvs

|------>* BUGFIX: some-bug...
|------>* IMPROVEMENT: quite a long long long
|------>               improvement.

I want to let vim auto format the line 5 as shown above by means of the indent function and thought of a workaround that let the line indent one less space and insert a tab into the begining of the line:

function! ClogIndent(lnum)
    let l:prevlnum = prevnonblank(a:lnum-1)
    if l:prevlnum == 0
        return 0

    let l:prevl = getline(l:prevlnum)
    let l:thisl = getline(a:lnum)
    let l:previ = indent(l:prevlnum)

    let l:ind = l:previ

    if l:thisl =~ '\*\s\a\+:\s'
        return l:ind

    if l:prevl =~ '\*\s\a\+:\s'
        if matchstr(l:thisl, '\%1c.') !~ '\t'
            call setline(a:lnum, substitute(l:thisl, '^', '\t', ""))
        let l:word = match(l:prevl, '\(\*\s\a\+:\s\)\@<=\w')
        let l:ind = l:word - 1

    return l:ind

I'm quite sure that call setline(a:lnum, substitute(l:thisl, '^', '\t', "")) was called, but it seems has no effect. Howevert, it works well when typed manually. Why is that?


The question is invalid. Maybe XY problem or something.

If &indentexpr is set to some function then that function calculates on-the-fly the number of spaces to indent a line. If also &expandtab is not set then Vim is allowed to minimize that number by outputting tabs - one hard tab per &tabstop spaces.

But if you set expandtab then you say: "I don't want any hard tabs to be auto-generated" and so whenever Vim is told to fill in some space (no matter if beginning or middle of a line) it outputs only spaces one by one.


  1. indentexpr is calculated right before reformatting a line. Hence your attempt to setline from within it is invalid.

  2. I still don't see why it's so important to have "exactly one hard tab" at a beginning of a line. Say, simply having setl noet will only differ in "improvement" indented by two or three tabs and, maybe, few spaces. Doesn't look too bad, IMO.

  3. It's possible to setl et and force replace of leading spaces by a tab upon autocmd BufWrite or even by manual typing appropriate :%s command. Looks ugly to me, but such stuff always works.

  4. Another option is to setl copyindent (and also probably setl preserveindent), so Vim would try to replicate indent structure of a previous line. And so copyindent practically gets a preference over expandtab if previous line already has tab(s). The drawback is that every time you start a new paragraph, you have to force the very first hard tab manually (<c-v><tab>).

  • Thanks for your explanation and sorry for the confusion. I edited my question. Do you have any idea? – lxvs Mar 21 at 2:32

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.