Max
Max

Reputation: 156

Vim window resizing repetitively

I have key bindings in tmux which I really enjoy to manage split panes:

bind -r H resize-pane -L 5
bind -r J resize-pane -D 5
bind -r K resize-pane -U 5
bind -r L resize-pane -R 5

This allows me to hit L wit multiple Ls in a row. It also allows me to say the border (left, right, etc) I want to increase.

I'd like to have the same thing in vim however, vim does not seem to have the context of border:

"attempt 1
nnoremap <leader>L :vertical resize +5<cr><leader>
"attempt 2
nnoremap <leader>L :vertical resize +5<cr>

However, this only works if on the left most pane as when on the right pane, I'd like it to be decreasing the size by 5. Also, this does not allow me to do it repetitively. (I'd like to hit key once, then as many times as I need the "L".

I was wondering if anyone had found a way to do this.

Note: I put the tmux config so someone could play with it to see exactly what I meant.

Upvotes: 5

Views: 1086

Answers (2)

Limeth
Limeth

Reputation: 513

I've made myself a vim script to make the resizing similar to Tmux' behavior. It might be what you are looking for.

" Tmux-like window resizing
function! IsEdgeWindowSelected(direction)
    let l:curwindow = winnr()
    exec "wincmd ".a:direction
    let l:result = l:curwindow == winnr()

    if (!l:result)
        " Go back to the previous window
        exec l:curwindow."wincmd w"
    endif

    return l:result
endfunction

function! GetAction(direction)
    let l:keys = ['h', 'j', 'k', 'l']
    let l:actions = ['vertical resize -', 'resize +', 'resize -', 'vertical resize +']
    return get(l:actions, index(l:keys, a:direction))
endfunction

function! GetOpposite(direction)
    let l:keys = ['h', 'j', 'k', 'l']
    let l:opposites = ['l', 'k', 'j', 'h']
    return get(l:opposites, index(l:keys, a:direction))
endfunction

function! TmuxResize(direction, amount)
    " v >
    if (a:direction == 'j' || a:direction == 'l')
        if IsEdgeWindowSelected(a:direction)
            let l:opposite = GetOpposite(a:direction)
            let l:curwindow = winnr()
            exec 'wincmd '.l:opposite
            let l:action = GetAction(a:direction)
            exec l:action.a:amount
            exec l:curwindow.'wincmd w'
            return
        endif
    " < ^
    elseif (a:direction == 'h' || a:direction == 'k')
        let l:opposite = GetOpposite(a:direction)
        if IsEdgeWindowSelected(l:opposite)
            let l:curwindow = winnr()
            exec 'wincmd '.a:direction
            let l:action = GetAction(a:direction)
            exec l:action.a:amount
            exec l:curwindow.'wincmd w'
            return
        endif
    endif

    let l:action = GetAction(a:direction)
    exec l:action.a:amount
endfunction

" Map to buttons
nnoremap <M-h> :call TmuxResize('h', 1)<CR>
nnoremap <M-j> :call TmuxResize('j', 1)<CR>
nnoremap <M-k> :call TmuxResize('k', 1)<CR>
nnoremap <M-l> :call TmuxResize('l', 1)<CR>

You can use the TmuxResize function to map other keys to it. The first argument is the direction ('h', 'j', 'k' or 'l'), the second argument is how much should the split border move.

Upvotes: 5

Christian Brabandt
Christian Brabandt

Reputation: 8248

There are some plugins that do that. For example tinymode, submode and tinykeymap

At least for tinykeymap, that used to be default behaviour, that it would switch to the tmux behaviour when pressing Ctrl++ (and this was the reason, I finally uninstalled that plugin)

Upvotes: 0

Related Questions