benknoble / wiki-md

A file- and syntax-agnostic wiki built on vanilla vim. Pairs best with markdown and universal ctags.
BSD 3-Clause "New" or "Revised" License
3 stars 0 forks source link

@benknoble's custom setup #5

Open benknoble opened 4 years ago

benknoble commented 4 years ago

Who are you?

@benknoble , the author of the plugin.

How are you using wiki-md?

Here are some mappings and commands I'm using. I mostly invoke the commands via the <leader>w mapping, which handily defaults to using a popup where available. (I'm also using my custom b:undo_ftplugin generator, which you can probably ignore.) My Dotfiles always have the most up-to-date version (and all the details).

Jump down to the next comment if you need a more in-depth explanation, or just browse the code below.

Here's the ftplugin

" ~/.vim/after/ftplugin/wiki.vim
nnoremap <buffer> gf :call wiki#goto(expand('<cfile>'), 'edit')<CR>
nnoremap <buffer> <C-w>f :call wiki#goto(expand('<cfile>'), 'split')<CR>
nnoremap <buffer> <C-w><C-f> :call wiki#goto(expand('<cfile>'), 'vert')<CR>
nnoremap <buffer> <C-w>gf :call wiki#goto(expand('<cfile>'), 'tab')<CR>

const s:mapped_c_h = "\<C-h>" isnot# "\<BS>"
if s:mapped_c_h
  inoremap <buffer> <C-h> <C-r>=wiki#ins_complete_wikis()<CR>
endif

let b:undo_ftplugin = ftplugin#undo({
      \ 'maps': [
      \   ['n', 'gf'],
      \   ['n', '<C-w>f'],
      \   ['n', '<C-w><C-f>'],
      \   ['n', '<C-w>gf'],
      \ ] + (s:mapped_c_h ? [['i', '<C-h>']] : []),
      \ })

And some global stuff

" ~/.vim/after/plugin/config/wiki.vim
if !exists('g:wiki_root')
  finish
endif

command -nargs=1 -complete=customlist,wiki#complete_wikis Ewiki execute 'edit' g:wiki_root.'/<args>'
command -nargs=1 -complete=customlist,wiki#complete_wikis Swiki execute '<mods> split' g:wiki_root.'/<args>'
command -nargs=1 -complete=customlist,wiki#complete_wikis Vwiki vertical Swiki <args>
command -nargs=1 -complete=customlist,wiki#complete_wikis Twiki tab Swiki <args>

call popsikey#register('<Leader>w', [
      \ #{
      \   key:    'w',
      \   info:   'edit root',
      \   action: ":call wiki#edit_root('split')\<CR>",
      \ },
      \ #{
      \   key:    '/',
      \   info:   'search wiki',
      \   action: ":execute 'grep' input('wiki-grep: ') g:wiki_root\<CR>",
      \ },
      \ #{
      \   key:    'e',
      \   info:   'edit wiki',
      \   action: ":Ewiki\<space>",
      \ },
      \ #{
      \   key:    's',
      \   info:   'split wiki',
      \   action: ":Swiki\<space>",
      \ },
      \ #{
      \   key:    'v',
      \   info:   'vsplit wiki',
      \   action: ":Vwiki\<space>",
      \ },
      \ #{
      \   key:    't',
      \   info:   'tabedit wiki',
      \   action: ":Twiki\<space>",
      \ },
      \ #{
      \   key:    'n',
      \   info:   'edit notepad',
      \   action: ":Ewiki notepad\<CR>",
      \ },
      \ ],
      \ #{
      \   title: ' Wiki ',
      \ })
benknoble commented 4 years ago

Breaking it down

We're going to cover first the ftplugin, then the global setup.

Ftplugin

You need to know that, with filetype plugin on, code in ~/.vim/after/ftplugin/<filetype>.vim will run, allowing you to customize keymappings and settings per-filetype. Vim comes with reasonable defaults for many filetypes, but I tend to customize things pretty heavily.

Next, you need to know that all your wiki documents will have the wiki filetype (and their regular filetypes, like markdown or javascript or C). So we are going to use ~/.vim/after/ftplugin/wiki.vim for all of our wiki-specific customization.

These are the first four lines of mine:

nnoremap <buffer> gf :call wiki#goto(expand('<cfile>'), 'edit')<CR>
nnoremap <buffer> <C-w>f :call wiki#goto(expand('<cfile>'), 'split')<CR>
nnoremap <buffer> <C-w><C-f> :call wiki#goto(expand('<cfile>'), 'vert')<CR>
nnoremap <buffer> <C-w>gf :call wiki#goto(expand('<cfile>'), 'tab')<CR>

These lines emulate the default gf-style mappings (go to file). You may not need these mappings at all! wiki-md already sets 'path' so that gf and friends will take you to existing wikis that match the word under the cursor. But the provided autoload functions will also create the wiki if it doesn't exist, so this provides an experience more like the larger plugins, where tapping enter twice will create a new entry and jump to it. We use <cfile> to grab the filename under the cursor, and provide the second argument to control how the file is opened in vim.

Again, if you don't want gf to create new files for you, I wouldn't recommend these mappings.

After that, we have a conditional <C-h> mapping in insert-mode to create links:

const s:mapped_c_h = "\<C-h>" isnot# "\<BS>"
if s:mapped_c_h
  inoremap <buffer> <C-h> <C-r>=wiki#ins_complete_wikis()<CR>
endif

Next up, we have some boilerplate to set b:undo_ftplugin correctly. That's code from my Dotfiles, and you can ignore if you wish.

let b:undo_ftplugin = ftplugin#undo({
      \ 'maps': [
      \   ['n', 'gf'],
      \   ['n', '<C-w>f'],
      \   ['n', '<C-w><C-f>'],
      \   ['n', '<C-w>gf'],
      \ ] + (s:mapped_c_h ? [['i', '<C-h>']] : []),
      \ })

Global plugin

Now you need to know that any .vim file in ~/.vim/plugin and ~/.vim/after/plugin will be run at startup (in a particular order). I use ~/.vim/after/plugin/config for configuration files for plugins that I use--here, it is important to distinguish between plugin as a .vim file and plugin as a collection of vimscripts.

At any rate, our wiki configuration will live in ~/.vim/after/plugin/config/wiki.vim. First, we check if we even have the wiki-md plugin, and skip the rest if we don't:

if !exists('g:wiki_root')
  finish
endif

Then, we create some custom commands that can jump to a wiki:

command -nargs=1 -complete=customlist,wiki#complete_wikis Ewiki execute 'edit' g:wiki_root.'/<args>'
command -nargs=1 -complete=customlist,wiki#complete_wikis Swiki execute '<mods> split' g:wiki_root.'/<args>'
command -nargs=1 -complete=customlist,wiki#complete_wikis Vwiki vertical Swiki <args>
command -nargs=1 -complete=customlist,wiki#complete_wikis Twiki tab Swiki <args>

I use <mods> to enable some reuse between the commands, and -complete to provide completion of wikis on the command line via an autoload function built for that purpose.

Then, I use my popsikey plugin to create a data-driven set of mappings that are all prefixed with <leader>w. If popups are available, that prefix creates a popup with key-triggers for the corresponding actions. Otherwise, it creates regular nnoremap mappings that do the same. So, <leader>ww edits the wiki root, while <leader>wv primes me at the command line for :Vwiki. <leader>wn gets reserved for my "notepad."

call popsikey#register('<Leader>w', [
      \ #{
      \   key:    'w',
      \   info:   'edit root',
      \   action: ":call wiki#edit_root('split')\<CR>",
      \ },
      \ #{
      \   key:    '/',
      \   info:   'search wiki',
      \   action: ":execute 'grep' input('wiki-grep: ') g:wiki_root\<CR>",
      \ },
      \ #{
      \   key:    'e',
      \   info:   'edit wiki',
      \   action: ":Ewiki\<space>",
      \ },
      \ #{
      \   key:    's',
      \   info:   'split wiki',
      \   action: ":Swiki\<space>",
      \ },
      \ #{
      \   key:    'v',
      \   info:   'vsplit wiki',
      \   action: ":Vwiki\<space>",
      \ },
      \ #{
      \   key:    't',
      \   info:   'tabedit wiki',
      \   action: ":Twiki\<space>",
      \ },
      \ #{
      \   key:    'n',
      \   info:   'edit notepad',
      \   action: ":Ewiki notepad\<CR>",
      \ },
      \ ],
      \ #{
      \   title: ' Wiki ',
      \ })