0

I have a default header file that is loaded by the following command in my ~/.vimrc :

autocmd bufnewfile * so /home/username/.vim/header.txt

It looks like this:

######################################################
# File name:      
# File path:      
# Purpose:         
# Creation date:  
# Last modified: 
# Created by:      
######################################################

I want to update Last modified: with the date/time when saving (using autocmd BufWritePre). This is working as expected.

I also want to populate File name:, File Path:, Creation date:, and Created by: when a new file is created (using autocmd BufNewFile). This is not working. Nothing is added to the header when a new file is created.

This is my code for updating Last modified: when saving a file. I also added in updating Created by: just to test my pattern match, and this code updates both fields upon file save as expected:

autocmd! BufWritePre * :call s:timestamp()
" to update timestamp when saving if it's in the first 20 lines of a file
function! s:timestamp()
    let pat = '\(\(Last\)\?\s*\([Cc]hanged\?\|[Mm]odified\|[Uu]pdated\?\)\s*:\s*\).*'
    let rep = '\1' . strftime("%a %d %b %Y %I:%M:%S %p %Z")
    call s:subst(1, 20, pat, rep)  
    
    let pat = '\(Created by\?\s*:\s*\).*'
    let rep =  '\1' . $USER
    call s:subst(1, 20, pat, rep)
endfunction

This is my code for updating the File name:, File Path:, Creation date:, and Created by: fields when a new file is created. It does not work; the fields do not get updated and there is no error message.

autocmd! BufNewFile * :call s:creationdata()
function! s:creationdata()
  let pat = '\(\(Creation\)\s*\([Dd]ate\)\s*:\s*\).*'
  let rep =  '\1' . strftime("%a %d %b %Y %I:%M:%S %p %Z")
  call s:subst(1, 20, pat, rep)

  let pat = '\(\(File\)\?\s*\([Pp]ath\)\?\s*:\s*\).*'
  let rep =  '\1' .escape(expand("%:p:h"), '/\'. (&magic ? '&~' : ''))
  call s:subst(1, 20, pat, rep)

  let pat = '\(\(File\)\?\s*\([Nn]ame\)\?\s*:\s*\).*'
  let rep =  '\1' . expand("%")
  call s:subst(1, 20, pat, rep)

  let pat = '\(Created by\?\s*:\s*\).*'
  let rep =  '\1' . $USER
  call s:subst(1, 20, pat, rep)
endfunction

The subst function called by the functions above is defined as:

function! s:subst(start, end, pat, rep)
    let lineno = a:start
    while lineno <= a:end
    let curline = getline(lineno)
    if match(curline, a:pat) != -1
        let newline = substitute( curline, a:pat, a:rep, '' )
        if( newline != curline )
        " Only substitute if we made a change
        "silent! undojoin
        keepjumps call setline(lineno, newline)
        endif
    endif
    let lineno = lineno + 1
    endwhile
endfunction

I can't figure out why the BufNewFile autocmd doesn't work. I've tried several other methods that I found via googling, including:

"  Method 1:  doesn't work; not compatible with vim 7.4?  Gives Error:
"  E16: Invalid rangeError detected while processing BufNewFile Auto commands for "*":
"  E16: Invalid range: 1,10g/File name:.*/s//File name: foo
"  E16: Invalid range: 1,10g/Creation date:.*/s//Creation date: 13-12-2022      
autocmd bufnewfile * exe "1," . 10 . "g/File name:.*/s//File name: " .expand("%")
autocmd bufnewfile * exe "1," . 10 . "g/Creation date:.*/s//Creation date: " .strftime("%d-%m-%Y")

... and:

" Method 2:  only works on saving file, not on creating a new file.  No error message.
autocmd BufNewFile,BufWritePre,FileWritePre * ks|call LastMod()|'s
  fun LastMod()
    if line("$") > 20
      let l = 20
    else
      let l = line("$")
    endif
    exe "1," . l . "g/Last modified:/s/Last modified: .*/Last modified: " .
    \ strftime("%Y %b %d")
    exe "1," . l . "g/Creation date:/s/Creation date: .*/Creation date: " .
    \ strftime("%Y %b %d")
  endfun

It's as if BufNewFile is the wrong autocmd pattern or something. But I've checked the docs and online and I think it's correct.

randyest
  • 1
  • 2
  • Could you check that the autocommand that inserts the banner and the one that adds the data are executed in the right order? – romainl Dec 13 '22 at 21:05
  • @romainl Adding the banner was after adding the data in my .vimrc -- thanks for getting me to check that. But if I move the `autocmd bufnewfile * so /home/rthomas/.vim/header.txt` command to before the data adding functions, no banner/header gets inserted at all. – randyest Dec 13 '22 at 21:24
  • You should do everything in one go: one function that inserts the full banner with all the fields already populated. – romainl Dec 13 '22 at 21:48
  • @romainl it's not clear how to do that. I have a command to load the header, then commands to search/replace fields in the header. They are seperate commands, and I can't search/replace until the header is inserted. – randyest Dec 13 '22 at 22:27
  • Well, I am suggesting a refactoring. Make separate functions that output the date, the username, etc. and use them in your banner template. Make separate functions that check if the file was modified, etc. Inserting an empty banner and then inserting data into it is bad design. – romainl Dec 14 '22 at 05:45
  • @romainl Thanks for the reply. Are you suggesting something like a bash wrapper around vim that generates and updates the header? Or somehow have vim make a copy of the default template, populate it, then insert it? – randyest Dec 14 '22 at 20:48

0 Answers0