5

I have this in my .vimrc

function HeaderTpl(fchar, boxchar, width)
    let sfile = expand("%:p")
    return a:fchar . " " . repeat(a:boxchar, a:width) . "\n"
            \ . a:fchar . " " . sfile . "\n"
            \ . a:fchar . "\n"
            \ . a:fchar . " " . strftime("%FT%T %z") . "\n"
            \ . a:fchar . " " . repeat(a:boxchar, a:width) . "\n"
endfunction

imap <silent>  ###  <C-R>=HeaderTpl('#', '-', 71)<CR>
imap <silent>  ///  <C-R>=HeaderTpl('//', '-', 70)<CR>

This works almost perfectly as if I type ### in blank file I get this header

# -----------------------------------------------------------------------
# /path/to/current/file.conf
#
# 2017-01-03T20:02:50 +0100
# -----------------------------------------------------------------------

but if the file type is defined (something like vim python_script.py) then I get something like this:

# -----------------------------------------------------------------------
# # /path/to/current/file.conf
# #
# # 2017-01-03T20:02:50 +0100
# # -----------------------------------------------------------------------
#

I think that additional # is caused by the autoindent or smartindent.

My question: how do I prevent this additional # to be inserted? One of my ideas was to temporary switch off autoindent and smartindent but how to do it?

$ vim --version
VIM - Vi IMproved 7.4 (2013 Aug 10, compiled Nov 24 2016 16:44:48)
Included patches: 1-1689
Extra patches: 8.0.0056
  • 1
    <C-R>= inserts as if typed. Try :put =.... Example at :h :put. – Antony Jan 3 '17 at 22:54
4

This is caused by the r flag in formatoptions. See How can I get vim to stop putting comments in front of new lines?.

One way to fix it is to:

  • Check if r is in formatoptions (with stridx(&formatoptions, 'r')
  • Remove it from formatoptions if it is with set formatoptions-=r and storing a local variable to track if it was set.
  • Add it back with set formatoptions+=r at the end if it was set.

As mentioned in the comments, you can also use the paste option to avoid some other side-effects that may occur.

However, this method won't work very well with your insert mode mapping, since that relies on the return value of the function. It can be done, but a better way is probably to use setline():

function! HeaderTpl(fchar, boxchar, width)
    let sfile = expand("%:p")
    call setline('.', [a:fchar . " " . repeat(a:boxchar, a:width),
        \ a:fchar . " " . sfile,
        \ a:fchar,
        \ a:fchar . " " . strftime("%FT%T %z"),
        \ a:fchar . " " . repeat(a:boxchar, a:width)
    \ ])

    return ''
endfunction

inoremap <silent> ### <C-R>=HeaderTpl('#', '-', 71)<CR>
inoremap <silent> /// <C-R>=HeaderTpl('//', '-', 70)<CR>

setline() will set the line in the first argument to the text in the second argument. . refers to the current line. You can set multiple lines by passing a list (using \n won't work).

  • Well setline is not good too as it overwrites lines below current line. My header is 5 lines so 4 line below current one are overwritten. – Dawid Jan 4 '17 at 20:19

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.