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 at 2:35
  • The == 0 is a vestige of debugging, trying several different expressions in searching for the issue. I'll remove it. – Brent Faust Feb 14 at 15:53

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). – Brent Faust Feb 14 at 15:52
  • I've clarified the question. Is it impossible? – Brent Faust Feb 14 at 16:28
  • 1
    @BrentFaust See my latest update – Ralf Feb 15 at 5:43
  • Nice! Or, the one-liner: execute "normal \<C-W>" . (RightPane() ? a:right : a:left) – Brent Faust Feb 15 at 20:26

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.