Change the focus of windows within vim and i3 with the same keystroke
asked 2013-12-12 23:05:01 +0000
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>
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 :)
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.
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.
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.
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.