I want to fold from "Copyright" to "CONNECTION" every time I open a .c or .h file, so I don't have to see it. The license does have newlines in it in my files, so selecting shouldn't be a problem. This is what I have:

autocmd FileType c call FoldLicense()
autocmd FileType h call FoldLicense()

function FoldLicense()
    normal /Copyright
    normal /CONNECTION
    visual zf
    normal /^$

The last line is to jump to the next blank line. I've been tweaking this for a while, and all I've gotten is either stuff in the last line or a blank buffer.

I would especially like if it didn't mess anything up for when a file doesn't have the license part, like: if (! /Copyright) {return} but in vimscript.


Instead of using the zf Normal mode command, it's easier if you use the :fold Ex command, which takes a range and fits naturally in a function. So you can easily fold the block starting on the first line that has Copyright and going up to the next line with CONNECTION using the following:

function! FoldLicense()
    silent! /Copyright/,/CONNECTION/fold

I added a silent! there so it fails silently if those strings are not found.

You can also add a /^$ to this function if you like. (You don't really need normal, since / works as an Ex command, only caveat is that it goes to the first character of the line, which should be totally fine in this particular case.)

Regarding file type matching, the *.h header files are not really mapped to a h FileType... Instead, they can map to either C, C++ or Objective-C, depending on some auto-detecting code and some global configuration variables.

If Objective-C is not detected (which is done by looking for Objective-C specific keywords such as @interface or @class), then it defaults to C++ (FileType cpp), but you can control that to have them use the C file type by setting global variable g:c_syntax_for_h to 1.

As a final polish to your code, it's best practice to always put your autocmds inside an augroup, so that if you end up sourcing your vimrc file (or script where you have them defined) again, you won't end up with duplicated autocmds.

So, putting it all together:

function! FoldLicense()
    silent! /Copyright/,/CONNECTION/fold

let g:c_syntax_for_h = 1

augroup vimrc_fold_license
    au FileType c call FoldLicense()
augroup END

For completeness, if you really wanted to use the zf Normal mode command to fold this block from a function, you would need something like this instead:

function! FoldLicense()
    execute "normal! zf/CONNECTION/e\<CR>"

Since the zf command takes a motion as an argument, you would have to use the search right after it. You should add a /e to move to the last character in the match, otherwise if C of CONNECTION is the the first character on the line, the fold would actually end on the line preceding it. You also need to add a <CR> to have it execute the search to complete the motion, so you need to use :execute to pass it to :normal!.

As mentioned above, using :fold is a much easier and reliable way to accomplish the same.

  • If I have multiple autocmds, could I skip the augroup by putting au! before all of them? – Not me Jul 9 '20 at 0:54
  • @MichaelChristensen Not really... That would erase all the autocmds, including the ones shipped by the Vim runtime, which allow it to detect filetypes and execute many plug-in actions... On the other hand, you might be able to use a single augroup for all the autocmd's coming from the same file (such as your vimrc). You can even reopen it as many times as you want and only erase it once at the start of the file. You can also pass aitocmd an optional argument for the group, so you should be able to do so with a single line (rather than 3). – filbranden Jul 9 '20 at 1:02
  • @MichaelChristensen Also, this matters if you :source your vimrc to reload it during runtime... If you never do that and don't intend to support that, then you might be able to get away with not using it... But, as mentioned, it's a good practice, it's good to adhere to it, doesn't cost much and prevents some issues that might be hard to debug. – filbranden Jul 9 '20 at 1:04
  • 1
    Could use /+ instead of /e i think – D. Ben Knoble Jul 9 '20 at 12:56

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.