I try to normalize access to Vim's command line mode from any other mode in order to simplify my actual mappings. For example to make the <f6> key work from anywhere I define the following mappings:

noremap <script> <unique> <silent> <f6> <sid>:echomsg 'Hello World!'<cr>
noremap! <script> <unique> <silent> <f6> <sid>:echomsg 'Hello World!'<cr>

The above mappings remap to the <sid>: key mapping given below before they get down to work:

noremap <unique> <expr> <sid>: <sid>StartCmdLineMode()
noremap! <unique> <expr> <sid>: <sid>StartCmdLineMode()
function! s:StartCmdLineMode()
  let a=mode()
  if a ==# 'n' 
    return ':'
  " Type <c-v><c-v> to insert ^V. 
  elseif a =~ '[vV^V]'
    return ":\<c-u>"
  elseif a ==# 'no'
    return "\<c-c>:"
  elseif a ==# 'i' 
    return "\<c-o>:"
  elseif a ==# 'c' 
    let b=getcmdtype()
    if b ==# ':' 
      return "\<c-e>\<c-u>"
      return "\<c-c>:"
    return ''

Is there a staightforward way instead of my obfuscated approach?


When does the following not work?

nnoremap <F6> <ESC><ESC>:command<CR>

In the meantime I came up with the following approach:

noremap <script> <unique> <SID><\O> <Nop>
inoremap <script> <unique> <SID><\O> <C-\><C-O><SID><\O>
cnoremap <script> <unique> <SID><\O> <C-\><C-N><SID><\O>
noremap <script> <unique> <SID><\N> <Nop>
noremap! <script> <unique> <SID><\N> <C-\><C-N><SID><\N>

For each Vim mode the <SID><\O> key sequence is mapped in order to appropriately escape (e.g. <C-\><C-O>) from Vim's current mode (e.g. insert-mode) to its normal mode. The right hand side of each mapping ends in its left hand side (e.g. <SID><\O>) in order to recursively try to escape again. The script-local (<script>, <SID>) recursion stops as soon the last escape key sequence reaches Vim's normal mode in which the <SID><\O> key sequence is mapped to nothing (<Nop>).

Likewise the <SID><\N> key sequence is mapped to not only escape once (<SID><\O>) from e.g. insert-mode before returning back but permanently stay in normal-mode.

With the help of the above definitions I mapped the <F1> and <S-F1> function keys as follows:

noremap <script> <unique> <expr> <F1> <SID>ToggleHelp(':<C-U>help', '<SID>')
noremap! <script> <unique> <expr> <F1> <SID>ToggleHelp(':<C-U>help', '<SID>')
noremap <script> <unique> <expr> <S-F1> <SID>ToggleHelp(':<C-U>helpgrep', '<SID>')
noremap! <script> <unique> <expr> <S-F1> <SID>ToggleHelp(':<C-U>helpgrep', '<SID>')
function! s:ToggleHelp(cmd, sid)
  ToggleVar s:HelpCwordOn
  let a=s:HelpCwordOn ? '<cword>' : '<cWORD>'
  return a:sid . '<\O>' . a:cmd . ' ' . expand(a) . ' '
command! -bang -nargs=+ ToggleVar call <SID>ToggleVar(<bang>0, <f-args>)
function! s:ToggleVar(bang, var)
  let {a:var}=exists(a:var) ? !{a:var} : !a:bang

Instead of having the <F1> key simply open Vim's help in a new window, it starts the :help command with the inner word (<cword>) under the cursor. By consecutively pressing the <F1> key, one switches to the outer word (<cWORD>) and toggels back again.

The 4 mappings from the use case above could also be defined as follows in order to not repeat yourself; i.e. keeping it "dry":

let a='noremap'
let b='<script> <unique> <expr>'
let c='<F1>'
let d='<S-F1>'
let e='<SID>ToggleHelp('':<C-U>help'
let f='grep'
let g=''', ''<SID>'')'
let h=b . ' ' . c . ' ' . e . g
let i=b . ' ' . d . ' ' . e . f . g
exec a . ' ' . h
exec a . '! ' . h
exec a . ' ' . i
exec a . '! ' . i

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.