Writing a map to find header under cursor for markdown link.

## heading {#foo}
[click on link](#foo) <- `cursur above this foo`

What I am doing:

nnoremap gO :lvimgrep "\v^#+.*(#.*)" %<CR>:lopen<CR>

What I am looking for:

nnoremap gO :lvimgrep "\v^#+.*(#<cword>)" %<CR>:lopen<CR>

There's a lot missing there. Ignoring the part after the first <CR> for now...

First, there are some contexts, i.e. where a filename is expected, where you can use <cword> bare. But in many cases, including this one, you need to force it to be resolved or "expanded". That can be done with, naturally, expand('<cword>'). Unfortunately, you can't just stick this in between your delimiters (")...:lvimgrep only accepts a clean, static string there.

The standard way to deal with dynamic/variable components on the command line is to make a string out of the command and pass it to :exec.

Within the string divide things into static and dynamic parts and concatenate them together. Separating into static/dynamic/delimiter parts:

  1. lvimgrep
  2. delimiter
  3. \v^#+.*(
  4. expand('<cword>')
  5. )
  6. delimeter
  7. %

Note that I removed # from #3 because it's going to be picked up by <cword>.

Now we use single quotes around the static parts to avoid any extra evaluation/interpretation that double quotes may cause. This is just the pattern part (#3-5):

'\v^#+.*(' . expand('<cword>') . ')'

Bringing in the rest including delimiters (I'm using / to avoid complications of quotes) and passing to :exec...

nnoremap gO :exec 'lvimgrep /\v^#+.*(' . expand('<cword>') . ')/ %'

Now you need the second command. That has to be separated from the preceding part with | and in mappings that must be escaped as \| or <bar>...

nnoremap gO :exec 'lvimgrep /\v^#+.*(' . expand('<cword>') . ')/ %' \| :lopen<CR>

Note that the first <CR> you had was unnecessary as the | takes care of submitting both commands.

FYI, I tested this and, if I'm understanding your use case correctly, it worked fine.

  • I guess it worked for you. :) Given how complicated this is I was sure there'd be a snag or two. Glad there isn't. – B Layer Feb 15 at 6:56
  • In a single post you cleared many doubts I had. Thanks. It worked perfectly :) – me_astr Feb 15 at 6:58
  • Nice! You're welcome. – B Layer Feb 15 at 6:59

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.