Change the focus of windows within vim and i3 with the same keystroke

asked 2013-12-12 23:05:01 +0000

this post is marked as community wiki

This post is a wiki. Anyone with karma >100 is welcome to improve it.

I wrote some bits of glue to change the focus between windows in i3 and vim using the same keystroke (SuperL+ArrowKeys or hjkl). It consists of a C bit (It used to be written in python, but the new version of libxdo broke it in my setup), a plug-in for vim, and configurations for the vim and i3 mappings.

To use it you would need libxdo (part of xdotools).

The C bit (i put in ~/bin/i3_vim_focus):

/* File: i3_vim_focus.c
 *
 * Compile with:
 * gcc -lX11 -lxdo -o i3_vim_focus i3_vim_focus.c $(pkg-config --libs --cflags i3ipc-glib-1.0)
 *
 */

#include <stdio.h>

#include <strings.h>
#include <string.h>

#include <xdo.h>

#include <glib/gprintf.h>
#include <i3ipc-glib/i3ipc-glib.h>

int main(int argc, char *argv[]) {

    char cmd[20];

    unsigned char *name;
    int name_len;
    int name_type;
    Window window_ret;

    i3ipcConnection *conn;
    gchar *reply;

    if(argc < 2){
        printf("Missing argument\n");
        return 1;
    }

    xdo_t *xdo = xdo_new(NULL);
    xdo_get_active_window(xdo, &window_ret);
    xdo_get_window_name(xdo, window_ret, &name, &name_len, &name_type);

    if(strstr(name, "VIM")) 
    {
        strcpy(cmd, "Escape+g+w+");


        strcat(cmd, (argv[1][0] == 'l')? "h" :
                    (argv[1][0] == 'd')? "j" :
                    (argv[1][0] == 'u')? "k" :
                                         "l" );

        xdo_send_keysequence_window(xdo, window_ret, cmd, 0);
    }
    else
    {
        conn = i3ipc_connection_new(NULL, NULL);
        strcpy(cmd, "focus ");
        strcat(cmd, argv[1]);
        reply = i3ipc_connection_message(conn, I3IPC_MESSAGE_TYPE_COMMAND, cmd, NULL);
        g_free(reply);
        g_object_unref(conn);
    }

    XFree(name);
    return  0;
}

The vim-plugin (I put in ~/.vim/plugin/focus.vim):

func! Focus(comando,vim_comando)
  let oldw = winnr()
  silent exe 'wincmd ' . a:vim_comando
  let neww = winnr()
  if oldw == neww
    silent exe '!i3-msg -q focus ' . a:comando
    if !has("gui_running")
        redraw!
    endif
  endif
endfunction

The i3 configuration (~/.i3/config, I use Mod4 as $mod):

# change focus
bindsym $mod+h exec "i3_vim_focus left"
bindsym $mod+j exec "i3_vim_focus down"
bindsym $mod+k exec "i3_vim_focus up"
bindsym $mod+l exec "i3_vim_focus right"

# alternatively, you can use the cursor keys:
bindsym $mod+Left  exec "i3_vim_focus left"
bindsym $mod+Down  exec "i3_vim_focus down"
bindsym $mod+Up    exec "i3_vim_focus up"
bindsym $mod+Right exec "i3_vim_focus right"

The vim bindings (~/.vimrc):

" Focus!
map gwl :call Focus('right','l')<CR>
map gwh :call Focus('left','h')<CR>
map gwk :call Focus('up','k')<CR>
map gwj :call Focus('down','j')<CR>
edit retag flag offensive close merge delete

Comments

Just out of curiosity: Why would one let another application manage windows next to i3? Sounds a bit backward to me, but I am sure I am missing out on some cool stuff :)

joepd gravatar imagejoepd ( 2013-12-13 07:53:50 +0000 )edit

I usually edit many files in separate vim windows and keep a terminal with ipython, for example, next to gvim to do tests. With this I create the effect of the cursor jumping from one window to another, first within vim and then out of vim to the terminal, when I reach the border.

e gravatar imagee ( 2013-12-13 09:01:45 +0000 )edit

Thanks for sharing! I used this to seamlessly move between i3's windows, tmux's panes, and vim's splits with the same key binding! Pretty awesome.

rafi gravatar imagerafi ( 2014-07-01 10:01:26 +0000 )edit

joepd essentially if you run multiple vim windows each is a separate instance. There are several benefits of having them all running on the same instance of vim. Ex. completing words from other buffers saving your vim session including position of windows/tabs etc.

Michael Rose gravatar imageMichael Rose ( 2014-12-12 17:28:05 +0000 )edit

After using the vim-tmux-navigator plugin, I needed exactly this to switch from tmux to i3wm, so thanks very much! I changed it slightly to call out to xdotool, since xdo_keysequence seems to be missing from v3 of the library, but it's the same concept.

jacderida gravatar imagejacderida ( 2015-05-30 17:10:33 +0000 )edit