I would like to have a mapping that opens a buffer with all the lines containing the word under the cursor.

I know such a mapping already exists in vanilla vim in normal mode [I.
But I don't like the output, the controls to move seem limited and I don't know how to edit it like a normal buffer.

I've come up with the following code:

function! LinesWithWordUnderCursor()

    " Clear register a
    let @a=""
    " Save cursor position
    let save_cursor = getcurpos()

    " Copy all the lines containing the word under cursor with format :
    " line number <space> line <CR>
    " Resulting command :
    " g/{cword}/let @a = @a . line('.') . ' ' . getline('.') . '\r'

    execute "g/" . expand("<cword>") . "/let @a = @a . line('.') . ' ' . getline('.') . '\r'"

    " Put the cursor back where it was
    call setpos('.', save_cursor)
    " Open a new tab
    " Set buffer as temporary
    setlocal buftype=nofile noswapfile nobuflisted bufhidden=wipe nomodified
    " Paste register a
    put =@a


nnoremap [I :<c-u>call LinesWithWordUnderCursor()<cr>

The function appends all the lines inside the register a. I would like the following formatting :

{the line number} {a tab character} {the line} {a newline character}

The function works, but I don't know how to insert a control character like a tab or a newline on each copied line.
The command responsible for copying and formatting a line is:

execute "g/" . expand("<cword>") . "/let @a = @a . line('.') . ' ' . getline('.') . '\r'"

I've tried adding \t and \n in different ways (escaping the double quotes, using single quotes, using the string() function ...), but it always ends with an error or with undesirable single quote characters.

I'm trying to build a global command by concatenating a few strings and then execute it with execute.

At the end of the concatenation, execute should execute something like this :

g/{word under cursor}/let @a = @a . line('.') . "\t" . getline('.') . "\n"

For the moment I use a litteral space instead of a tab character, and a carriage return (\r) instead of a newline (which produces a weird output with the caret notation ^M at the end of every line).

How can I modify the concatenation of strings executed by the execute command so that it integrates a tab character instead of a space and a newline character instead of a carriage return ?

2 Answers 2


You command looks like follow without the :execute:

:g/pat/let @a.= line('.') . "\t" . getline('.') . "\n"

Adding in the :execute means you need to quote things correctly. The real trick is to use single quote. Also properly escape your single quotes or switching to double quotes.

 :execute 'g/' . expand('<cword>') . '/let @a.= line(".") . "\t" . getline(".") . "\n"'

For more help see:

:h expr-string
:h literal-string

Instead of \t, you can capture a control character by first typing CTRL-v followed by the character you want. For sake of this example, let's say that <TAB> means "press the tab key", and <RETURN> means "press the return key".

To capture a tab character in your function definition: CTRL-v<TAB>. To capture a newline: CTRL-v<RETURN>.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.