A simple vim scriptie for those who are interested. It is triggered when new C/C++ files are created (e.g. via vim new-file.cxx
), and fills it in with boilerplate unit code. What’s special about it is that it tries to find tips about that code in other files in that or parent directory.
The templates
The template used for .c/.cxx files is:
/* header-comment
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
While for .h/.hxx files the following is used:
/* header-comment
*/
#pragma once
#ifndef PREFIX_FN_H
#define PREFIX_FN_H 1
#endif /*PREFIX_FN_H*/
In order to simplify the work flow, the following magic is done:
- header-comment is actually copied from any other file with the same suffix,
- FN_H is substituted for actual filename,
- PREFIX is copied from any other file with the same suffix,
- if no file is found in the same directory as the new file, the scripts falls back to parent directory, and appends the subdirectory name to PREFIX.
The script
Just a dirty, quick vimrc. Feel free to improve:
function CTemplate()
let fext = expand('%:e')
let ucext = toupper(fext)
let myprefix = substitute(toupper(expand('%')), '[^A-Z0-9]', '_', 'g')
let head_done = 0
let head_line = 0
let prefix_done = 0
if fext =~ '^h'
call append(1, '#pragma once')
call append(2, '')
call append(3, '#ifndef @fn@')
call append(4, '#define @fn@ 1')
call append(5, '')
call append(6, '#endif /*@fn@*/')
else
call append(1, '#ifdef HAVE_CONFIG_H')
call append(2, '# include "config.h"')
call append(3, '#endif')
let prefix_done = 1
endif
let mywd = expand("%:p:h")
echo mywd
let myfiles = glob(mywd . '/*.' . fext, 0, 1)
let myfiles += glob(mywd . '/../*.' . fext, 0, 1)
for myfile in myfiles
if filereadable(myfile)
for myline in readfile(myfile)
if !head_done
if head_line != 0
call append(head_line, myline)
if myline =~ '[*][/]'
let head_done = 1
else
let head_line += 1
endif
endif
if head_line == 0 && myline =~ '^[/][*]'
call append(0, myline)
let head_line += 1
if myline =~ '[*][/]'
let head_done = 1
endif
endif
endif
if !prefix_done && myline =~ '^#ifndef .*_'.ucext
if myfile =~ '^../'
let mydir = toupper(expand('%:p:h:t'))
let myprefix = mydir . '_' . myprefix
endif
let myprefix = substitute(myline[8:],
\ '[^_]*_[^_]*$', '', '') . myprefix
let prefix_done = 1
endif
endfor
endif
if head_done && prefix_done
break
endif
endfor
if fext =~ '^h'
exec '%s/@fn@/'.myprefix.'/'
endif
endfunction
Quoting [17.6.4.3.2 Global names] from the C++ standard: “Each name that contains a double underscore _ _ or begins with an underscore followed by an uppercase letter (2.12) is reserved to the implementation for any use.” – Referring to your _PREFIX_FN_H identifier.
Looking at the context, I’m not sure if that strictly applies to macros or to symbols only. In any case, using
_FOO_BAR_H
for header guards is more than common…A macro name is a global name, which is covered by the section I quoted. It may be common, but still goes against the language specification.
I’ve modified the script and removed the leading
_
.