I want to make several keybinds and options set for certain files based on their location. Is there a more elegant way than...

autocmd BufRead,BufNewFile /tmp/wiki-tag-reports/* nnoremap <Enter> :DiaryTagBrowser <E
autocmd BufRead,BufNewFile /tmp/wiki-tag-reports/* nnoremap <Backspace> :bd! <Enter>
autocmd BufRead,BufNewFile /tmp/wiki-tag-reports/* nnoremap q :q!<CR>
autocmd BufRead,BufNewFile /tmp/wiki-tag-reports/* set ft=vimwiki

...to avoid repeating autocmd BufRead,BufNewFile /tmp/wiki-tag-reports/* each time?


You can use line continuations (lines after the first starting with a backslash) and using |s to separate commands.

Something like this might work for you (but I haven't tested it, so it might be missing some escaping):

autocmd BufRead,BufNewFile /tmp/wiki-tag-reports/*
    \   nnoremap <Enter> :DiaryTagBrowser <Enter>
    \ | nnoremap <Backspace> :bd! <Enter>
    \ | nnoremap q :q!<CR>
    \ | set ft=vimwiki

But this approach can be pretty fragile, particularly due to the rules around escaping |s (see :help :bar and :help :execute, which is often used to work around it.)

A much saner approach is to just define a function with all commands you want to execute and call that function from your autocmd, there are no pitfalls with escaping in that case and it's much easier to include complex logic (including conditional statements.)

For example:

function! SetupWikiTagReports()
  nnoremap <buffer> <Enter> :DiaryTagBrowser <Enter>
  nnoremap <buffer> <Backspace> :bd! <Enter>
  nnoremap <buffer> q :q!<CR>
  set ft=vimwiki

autocmd BufRead,BufNewFile /tmp/wiki-tag-reports/* call SetupWikiTagReports()

Note that I also added <buffer> tags to your mappings here, since you only want those mappings on the buffers which are editing files of these types. You don't want those mappings to be global. If you edit multiple files that match that pattern, the autocmd will execute for each of them and create the mappings on all buffers.

I see you're also setting a filetype in your autocmd. Do you intend these mappings to be set only for files in /to/wiki-tag-reports? Or for every file of type vimwiki? If the latter, then consider simply setting a filetype based on the autocmd with the filename pattern (you could do so in a ~/.vim/ftdetect/*.vim file, which gets loaded automatically from Vim's filetype detection code), and then creating a ~/.vim/after/ftplugin/vimwiki.vim with the mappings (still using <buffer> mappings there.) That file is sourced every time a file gets filetype vimwiki, so that would be an easy approach to create the mappings consistently.

  • 1
    Correct me if I'm wrong, but doesn't this approach mean that once the function is called, then the maps will apply to any file in vim, not just the wiki-tag-reports? Would you have to explicitly unmap them (with a second function) like I do in my answer?
    – mattb
    Jun 27 at 15:42
  • 1
    @mattb I added <buffer> exactly to make the mappings buffer-local (in the second example). There's an issue with unmapping in BufLeave in that the mappings won't be set again when you come back to the buffer, you would need BufEnter too for that to happen... I tend to find that buffer-local mappings are a cleaner approach than mapping/unmapping based on every buffer event...
    – filbranden
    Jun 27 at 16:08
  • In nnoremap <buffer> <Enter> do you mean "<buffer>" literally? Like those are the literal characters to have there and it's not just a placeholder?
    – alec
    Jun 27 at 16:13
  • 1
    @alec Yes, correct. <buffer> is a valid modifier for the map commands. See :help :map-local.
    – filbranden
    Jun 27 at 16:16
  • Awesome. Thanks <buffer> looks like an important detail that I was unaware of. These commands are only for the wiki-tag-reports and not for all wiki files.
    – alec
    Jun 27 at 16:20

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.