I'm getting some really weird behavior when trying to write a simple keybinding in my vimrc. the following key map:

nnoremap <F2> gdi

only works if the cursor is not over the first declaration of a variable. If it is, it won't go into insert mode.

This is the code sample I'm working with:

hangman :: IO ()
hangman = do word <- getLine
         guessword word $ concat $ replicate (length word) "-"

guessword :: String -> String -> IO ()
guessword a b = do putStrLn b
           guess <- getLine

If I open the file and run the command on the first instance of "hangman", it just won't enter insert mode. If I run it on the second instance, it will.

But if I just type gdi manually (without using the key binding), it will always enter insert mode, wherever I type it.

Why this discrepancy between running the key binding and actually typing the command in Vim? Can anyone else reproduce this issue?

I'm using neovim if it matters.

EDIT: It appears that the key binding is actually dropping any key presses after gd. Anything I add to the key binding after gd is disregarded, but only if I'm on the first instance of the match.

To get around this, I'm using the following workaround using a regex:

nnoremap <expr> <leader>r "gg:/\\<" .expand("<cword>") . "\\>/<CR>

which allows me do what I was originally intending to do, which was write a key binding that renames a variable. The following works for me:

nnoremap <expr> <leader>r "gg:/\\<" .expand("<cword>") . "\\>/<CR>cgn" . input("Enter new name: ") . "<esc>:%norm .<CR><C-O>"
  • 1
    Does gd cause an error on the first match (e.g., you see a screen flash/bell ring/have errors in :messages)? If so, the mapping gets aborted
    – D. Ben Knoble
    Commented Feb 19, 2020 at 4:24
  • @D.BenKnoble no, it doesn't appear to. I have no error messages when typing the command or running the key binding. Commented Feb 19, 2020 at 4:36

1 Answer 1


It seems that gd actually fails if you're in the definition itself (even though Vim doesn't print an error message.)

You can see that somewhat if you use gd on the middle of the definition keyword, while I'd expect it to move to the beginning of the word, it keeps the cursor where it is. So together with the other evidence, I take it that this command is failing. It's unclear to me why it fails in this particular case, whether the authors decided it should fail in this case and for what reason. The documentation doesn't seem to spell out this particular case either.

In any case, when a command fails, a mapping is interrupted and the commands that follow will not be executed.

You mentioned at the end of your question that your actual objective is to replace the first occurrence of the word under the cursor.

You can accomplish that easily in a mapping, for example using:

nnoremap <silent> <F2> :let @/ = '\V\<'.escape(expand('<cword>'), '\').'\>'<CR>ggcgn

Setting the @/ makes it the search term. Using \< and \> around the word means you'll only match whole words only. Using \V (very non-magic) means only the backslash character will be special, and for extra care we're escaping the backslashes in the current word (even though it's very unlikely you'd get them anyways, unless you redefined 'iskeyword' to include backslashes, but hey let's be super safe here.)

This part of the mapping is similar to what the * command does. (In fact, implementing the mapping by simply using *ggcgn is probably possible too.) The main difference is that setting @/ will not jump to the next search term, while * does. (But that might not matter, since you're jumping back to the beginning of the buffer right afterwards.)

After setting the default search term, we execute gg to go to the top and cgn to start replacing the next occurrence of the search term, leaving you in insert mode ready to replace that identifier.

  • 1
    Thanks, that is strange that gd would fail in that case. Commented Feb 19, 2020 at 8:21
  • 1
    I knew it! Well done
    – D. Ben Knoble
    Commented Feb 19, 2020 at 13:05

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.