Skip to content

Instantly share code, notes, and snippets.

@mijoharas
Last active December 21, 2021 16:28
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save mijoharas/b9d09daed9654ca8d0d081015209ecd0 to your computer and use it in GitHub Desktop.
Save mijoharas/b9d09daed9654ca8d0d081015209ecd0 to your computer and use it in GitHub Desktop.
navigate emacs or i3 depending on whether emacs is focussed.

i3-navigate-emacs

Usage:

Create bash file above and put it in your path. add these lines to your i3/config:

# change focus
bindsym $alt+$left exec i3-navigate-emacs left
bindsym $alt+$down exec i3-navigate-emacs down
bindsym $alt+$up exec i3-navigate-emacs up
bindsym $alt+$right exec i3-navigate-emacs right

# alternatively, you can use the cursor keys:
bindsym $alt+Left exec i3-navigate-emacs left
bindsym $alt+Down exec i3-navigate-emacs down
bindsym $alt+Up exec i3-navigate-emacs up
bindsym $alt+Right exec i3-navigate-emacs right

When you try and focus right with i3 it will first check if you have emacs focussed. If so it will try and navigate right in emacs. If that fails (which it will if you are in the rightmost pane in emacs) it will move the i3 focus to the right.

This means if you accidentally try and use i3 commands to move focus in emacs it will just work.

Requirements:

  • jq used to parse the json and figure out the focussed window in i3
  • i3-msg comes with i3, used to speak to i3
  • emacsclient used to speak to emacs
  • evil mode for emacs (I use the evil-move-right command in emacs, change it if you want I guess).
  • grep (if you don't have grep on your system things probably aren't gonna work great here).
#!/bin/bash
function get-focussed-window()
{
i3-msg -t get_tree | jq -r ".. | select(.focused? == true).window_properties.class"
}
function i3-move()
{
i3-msg focus "$1"
}
function emacs-move()
{
emacsclient -e "(evil-window-$1 1)"
}
function perform-move()
{
local focussed_workspace=$(get-focussed-window)
if [ "$focussed_workspace" = "Emacs" ]; then
emacs-move "$1"
local result=$?
if [ $result -ne 0 ]; then
i3-move "$1"
fi
else
i3-move "$1"
fi
}
case "$1" in
left) ;&
right) ;&
up) ;&
down)
perform-move "$1";;
*) echo "command not found";;
esac
@MarcoIeni
Copy link

Thank you for this piece of code, how can I make it work for the evil-window-move commands?

For example, if I type emacsclient -e "(evil-window-move-far-right)" from terminal it opens the *server* buffer instead of moving the window.

@mijoharas
Copy link
Author

@marcoleni Hey, sorry, never noticed comments on my gists. Hope half a year isn't too late for an answer! I just had a poke around and I get the same thing, where the pane moves and then gets replaced with a *server* buffer.

Unfortunately I don't really know the (evil-window-move-far-right) command so can't really say why it's happening, might be worth opening an issue with evil and seeing if they have any ideas? Obviously the other solution is to try and dig in and see what's going on yourself. Sorry I couldn't be any help, hope you figure it out.

@evandromurilo
Copy link

Thank you so much!

@yoricksijsling
Copy link

Thanks for this code! I've been using it for a while.

I had some issues with the emacs move failing when:

  • There are multiple emacs frames on one screen
  • The mouse is over emacs frame A
  • Emacs frame B has the focus, and there I try to move within the emacs frame

Under those circumstances, emacsclient would try to move within frame A instead of frame B. That would fail and it would fall back on moving i3 windows.

I have fixed it here:
https://github.com/yoricksijsling/dotfiles/blob/58c71785362a54ad5498db4eb47f1bf3d903a130/i3-navigate-emacs.sh

@mijoharas
Copy link
Author

@yoricksijsling Nice improvement! (I don't often use multiple frames so never noticed the issue.).

I hadn't looked at this code for a few years, but as I did, I noticed that I wasn't declaring the variables in the bash functions as local (bash makes variables global by default... yeah, I know 😒 ).

I changed that in my version in the last revision, I'd recommend you updating your bash functions as well (just stick local in front of every variable you declare and you'll be 👌 )

@jsilve24
Copy link

I love this. One thing I notice is a pretty notable latency compared to the default movements. Of course some latency is to be expected but I was wondering if anyone had had any luck speeding this up. Its such a great idea!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment