How can a keypress dynamically change its behavior, depending upon which split pane has focus?

(Specifically, whether the pane containing the cursor has another split pane to the right, or not.)

map <expr> Can be used to map the keypress to the result of an expression, such as:

noremap <expr> <F2> RightPane() ? ':echom RightPane()' : 'Never happens'

But the rightmost result is never returned! When F2 is pressed with the cursor/focus in the left split pane:

  • the expression :echom RightPane() is displayed in the status bar.
  • Pressing CR then always evaluates properly, as either 0 or 1.
  • 'Never happens' is never shown, however

Can the function respond differently, based on the pane with the cursor, each time F2 is pressed?

The function is defined as follows:

func! RightPane()    
  let saveW = winnr() 
  silent! exe "normal! \<c-w>l"
  let rightW = winnr()
  silent! exe saveW.'wincmd w'
  return saveW == rightW

Example Use-Case

Resize Panes Using Ctrl-Arrow Keys:

func! RightPane()    
  let saveW = winnr() 
  exe "normal! \<c-w>l"
  let rightW = winnr()
  exe saveW.'wincmd w'
  return saveW == rightW

" Resize split panes using Ctrl-Arrow
noremap <expr> <C-Left>  RightPane() ? '<C-W>>' : '<C-W><'
noremap <expr> <C-Right> RightPane() ? '<C-W><' : '<C-W>>'
noremap <expr> <C-Up>    BottomPane() ? '<C-W>+' : '<C-W>-'
noremap <expr> <C-Down>  BottomPane() ? '<C-W>-' : '<C-W>+'
  • Why == 0 ? That seems redundant. Also I feel like there may be missing <CR>s there. None of this explains the behavior though. Unless the entire expr needs quoted?
    – D. Ben Knoble
    Feb 14, 2019 at 2:35
  • The == 0 is a vestige of debugging, trying several different expressions in searching for the issue. I'll remove it. Feb 14, 2019 at 15:53

1 Answer 1


In a map-<expr> the allowed actions are limited. You explicitly suppressed error messages with silent!. If you remove this, you get the error message:

Error detected while processing function RightPane:
line    2:
E523: Not allowed here

Using :normal is not allowed in a map-<expr>. See :help map-<expr>.

BTW: You could replace that with wincmd l, but that isn't allowed either.

Note that the second call to RightPane() is not within the context of map-<expr>, so it returns the expected value.

Update: You could work with a "normal" map, like:

function! DoVertResize(left, right)
    if RightPane()
        execute "normal \<C-W>" . a:right
        execute "normal \<C-W>" . a:left

nnoremap <C-Right> :call DoVertResize('>','<')<CR>
nnoremap <C-Left> :call DoVertResize('<','>')<CR>
  • Excellent insight. The map <expr> is being re-evaluated each time (but is hitting errors). Feb 14, 2019 at 15:52
  • I've clarified the question. Is it impossible? Feb 14, 2019 at 16:28
  • 1
    @BrentFaust See my latest update
    – Ralf
    Feb 15, 2019 at 5:43
  • Nice! Or, the one-liner: execute "normal \<C-W>" . (RightPane() ? a:right : a:left) Feb 15, 2019 at 20:26

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.