feat(emacs-i3): publish

This commit is contained in:
Pavel Korytov 2021-10-06 16:19:21 +03:00
parent 3337054e5e
commit 4ba4b4b543
14 changed files with 453 additions and 31 deletions

View file

@ -64,7 +64,7 @@ And here is a simple macro to do the Emacs -> i3 part:
Now we have to handle the required set of i3 commands. It is worth noting here that I'm not trying to implement a general mechanism to apply i3 commands to Emacs, rather I'm implementing a small subset that I use in my i3 configuration and that maps reasonably to the Emacs concepts.
Also, I use [evil-mode](https://github.com/emacs-evil/evil) and generally configure the software to have vim-style bindings where possible. So if you don't use evil-mode you'd have to detangle the given functions from evil, but then I guess you do not use super+hjkl to manage windows either.
Also, I use [evil-mode](https://github.com/emacs-evil/evil) and generally configure the software to have vim-style bindings where possible. So if you don't use evil-mode you'd have to detangle the given functions from evil, but then, I guess, you do not use super+hjkl to manage windows either.
### `focus` {#focus}
@ -306,4 +306,4 @@ bindsym $mod+comma exec i3-switch-tabs left
So, how does all of that feel? Actually, I got used to that setup pretty quickly. Using `<s-Q>` to quit windows and the `<s-r>` submode to resize them is particularly nice. I've seen people making hydras in Emacs to do the latter.
All of that would probably be easier to do in a WM which is configured in a programming language rather than a self-cooked DSL, so I may try to replicate that somewhere else in an unknown time in the future. Meanwhile, it's pretty good.
All of that would probably be easier to do in a WM which is configured in a programming language rather than in a self-cooked DSL, so I may try to replicate that somewhere else in an unknown time in the future. Meanwhile, it's pretty good.

View file

@ -56,7 +56,7 @@ And here is a simple macro to do the Emacs -> i3 part:
* Handling i3 commands
Now we have to handle the required set of i3 commands. It is worth noting here that I'm not trying to implement a general mechanism to apply i3 commands to Emacs, rather I'm implementing a small subset that I use in my i3 configuration and that maps reasonably to the Emacs concepts.
Also, I use [[https://github.com/emacs-evil/evil][evil-mode]] and generally configure the software to have vim-style bindings where possible. So if you don't use evil-mode you'd have to detangle the given functions from evil, but then I guess you do not use super+hjkl to manage windows either.
Also, I use [[https://github.com/emacs-evil/evil][evil-mode]] and generally configure the software to have vim-style bindings where possible. So if you don't use evil-mode you'd have to detangle the given functions from evil, but then, I guess, you do not use super+hjkl to manage windows either.
** =focus=
First, for the =focus= command I want to move to an Emacs window in the given direction if there is one, otherwise move to an X window in the same direction. Fortunately, i3 and =windmove= have the same names for directions, so the function is rather straightforward.
@ -268,4 +268,4 @@ bindsym $mod+comma exec i3-switch-tabs left
* Conclusion
So, how does all of that feel? Actually, I got used to that setup pretty quickly. Using =<s-Q>= to quit windows and the =<s-r>= submode to resize them is particularly nice. I've seen people making hydras in Emacs to do the latter.
All of that would probably be easier to do in a WM which is configured in a programming language rather than a self-cooked DSL, so I may try to replicate that somewhere else in an unknown time in the future. Meanwhile, it's pretty good.
All of that would probably be easier to do in a WM which is configured in a programming language rather than in a self-cooked DSL, so I may try to replicate that somewhere else in an unknown time in the future. Meanwhile, it's pretty good.

View file

@ -6,7 +6,17 @@
<description>Recent content in Index on SqrtMinusOne</description>
<generator>Hugo -- gohugo.io</generator>
<language>en-us</language>
<lastBuildDate>Wed, 08 Sep 2021 00:00:00 +0000</lastBuildDate><atom:link href="https://sqrtminusone.xyz/index.xml" rel="self" type="application/rss+xml" />
<lastBuildDate>Wed, 06 Oct 2021 00:00:00 +0000</lastBuildDate><atom:link href="https://sqrtminusone.xyz/index.xml" rel="self" type="application/rss+xml" />
<item>
<title>Getting a consistent set of keybindings between i3 and Emacs</title>
<link>https://sqrtminusone.xyz/posts/2021-10-04-emacs-i3/</link>
<pubDate>Wed, 06 Oct 2021 00:00:00 +0000</pubDate>
<guid>https://sqrtminusone.xyz/posts/2021-10-04-emacs-i3/</guid>
<description>Intro One advantage of EXWM for an Emacs user is that EXWM gives one set of keybindings to manage both Emacs windows and X windows. In every other WM, like my preferred i3wm, two orthogonal keymaps seem to be necessary. But, as both programs are quite customizable, I want to see whether I can replicate at least some part of the EXWM goodness in i3.
But why not just use EXWM?</description>
</item>
<item>
<title>My EMMS and elfeed setup</title>
<link>https://sqrtminusone.xyz/posts/2021-09-07-emms/</link>

Binary file not shown.

View file

@ -0,0 +1,267 @@
<!DOCTYPE html>
<html lang=""><head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>Getting a consistent set of keybindings between i3 and Emacs</title>
<meta name="description" content="Freedom is a state of mind">
<meta name="author" content='SqrtMinusOne'>
<link href="https://fonts.googleapis.com/css2?family=Inconsolata:wght@400;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css" integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css" integrity="sha512-iBBXm8fW90+nuLcSKlbmrPcLa0OT92xO1BIsZ+ywDWZCvqsWgccV3gFoRBv0z+8dLJgyAHIhR35VZc2oM/gI1w==" crossorigin="anonymous">
<link rel="stylesheet" href="/sass/researcher.min.css">
<link rel="icon" type="image/ico" href="https://sqrtminusone.xyz/favicon.ico">
</head>
<body><div class="container mt-5">
<nav class="navbar navbar-expand-sm flex-column flex-sm-row text-nowrap p-0">
<a class="navbar-brand mx-0 mr-sm-auto" href="https://sqrtminusone.xyz/" title="SqrtMinusOne">
SqrtMinusOne
</a>
<div class="navbar-nav flex-row flex-wrap justify-content-center">
<a class="nav-item nav-link" href="/" title="Index">
Index
</a>
<span class="nav-item navbar-text mx-1">/</span>
<a class="nav-item nav-link" href="/posts/" title="Posts">
Posts
</a>
<span class="nav-item navbar-text mx-1">/</span>
<a class="nav-item nav-link" href="/configs/readme" title="Configs">
Configs
</a>
</div>
</nav>
</div>
<hr>
<div id="content">
<div class="container">
<h2 id="intro">Intro</h2>
<p>One advantage of EXWM for an Emacs user is that EXWM gives one set of keybindings to manage both Emacs windows and X windows. In every other WM, like my preferred <a href="https://i3wm.org">i3wm</a>, two orthogonal keymaps seem to be necessary. But, as both programs are quite customizable, I want to see whether I can replicate at least some part of the EXWM goodness in i3.</p>
<p>But why not just use EXWM? One key reason is that to my taste (and perhaps on my hardware) EXWM didn&rsquo;t feel snappy enough. Also, I really like i3&rsquo;s tree-based layout structure; I feel like it fits my workflow much better than anything else I tried, including the master/stack paradigm of <a href="https://xmonad.org/">XMonad</a>, for instance.</p>
<p>One common point of criticism of i3 is that it is not extensible enough, especially compared to WMs that are configured in an actual programing language, like the mentioned XMonad, <a href="http://www.qtile.org/">Qtile</a>, <a href="https://awesomewm.org/">Awesome</a>, etc. But I think i3&rsquo;s extensibility is underappreciated, although the contents of this article may lie closer to the limits of how far one can go there.</p>
<p>Here is a small demo of how it currently works:</p>
<video controls width="100%">
<source src="/ox-hugo/i3-emacs-demo.mp4" type="video/mp4">
</video>
<h2 id="emacs-integration">Emacs integration</h2>
<p>What I&rsquo;m trying to do is actually quite simple, so I&rsquo;m somewhat surprised I didn&rsquo;t find anything similar on the Internet. But I didn&rsquo;t look too hard.</p>
<p>The basic idea is to launch a normal i3 command with <code>i3-msg</code> in case the current window is not Emacs, otherwise pass that command to Emacs with <code>emacsclient</code>. In Emacs, execute the command if possible, otherwise pass the command back to i3.</p>
<p>This may seem like a lot of overhead, but I didn&rsquo;t feel it even in the worst case (i3 -&gt; Emacs -&gt; i3), so at least in that regard, the interaction feels seamless. The only concern is that this command flow is vulnerable to Emacs getting stuck, but it is still much less of a problem than with EXWM.</p>
<p>One interesting observation here is that Emacs windows and X windows are sort of one-level entities, so I can talk just about &ldquo;windows&rdquo;.</p>
<p>At any rate, we need a script to do the i3 -&gt; Emacs part:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash"><span style="color:#66d9ef">if</span> <span style="color:#f92672">[[</span> <span style="color:#66d9ef">$(</span>xdotool getactivewindow getwindowname<span style="color:#66d9ef">)</span> <span style="color:#f92672">=</span>~ ^emacs<span style="color:#f92672">(</span>:.*<span style="color:#f92672">)</span>?@.* <span style="color:#f92672">]]</span>; <span style="color:#66d9ef">then</span>
command<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;(my/emacs-i3-integration \&#34;</span>$@<span style="color:#e6db74">\&#34;)&#34;</span>
emacsclient -e <span style="color:#e6db74">&#34;</span>$command<span style="color:#e6db74">&#34;</span>
<span style="color:#66d9ef">else</span>
i3-msg $@
<span style="color:#66d9ef">fi</span>
</code></pre></div><p>My <a href="https://sqrtminusone.xyz/configs/emacs/#custom-frame-title">Emacs frame title is set</a> to <code>emacs[:&lt;projectile-project-name&gt;]@&lt;hostname&gt;</code>, hence the regex. The script is saved to an executable called <code>emacs-i3-integration</code>.</p>
<p>For this to work, we need to make sure that Emacs starts a server, so here is an expression to do just that:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(add-hook <span style="color:#e6db74">&#39;after-init-hook</span> <span style="color:#a6e22e">#&#39;</span>server-start)
</code></pre></div><p>The function <code>my/emacs-i3-integration</code>, which is an entrypoint for the i3 integration, will be defined a bit later.</p>
<p>And here is a simple macro to do the Emacs -&gt; i3 part:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(defmacro i3-msg (<span style="color:#66d9ef">&amp;rest</span> args)
<span style="color:#f92672">`</span>(<span style="color:#a6e22e">start-process</span> <span style="color:#e6db74">&#34;emacs-i3-windmove&#34;</span> <span style="color:#66d9ef">nil</span> <span style="color:#e6db74">&#34;i3-msg&#34;</span> <span style="color:#f92672">,@</span>args))
</code></pre></div><h2 id="handling-i3-commands">Handling i3 commands</h2>
<p>Now we have to handle the required set of i3 commands. It is worth noting here that I&rsquo;m not trying to implement a general mechanism to apply i3 commands to Emacs, rather I&rsquo;m implementing a small subset that I use in my i3 configuration and that maps reasonably to the Emacs concepts.</p>
<p>Also, I use <a href="https://github.com/emacs-evil/evil">evil-mode</a> and generally configure the software to have vim-style bindings where possible. So if you don&rsquo;t use evil-mode you&rsquo;d have to detangle the given functions from evil, but then, I guess, you do not use super+hjkl to manage windows either.</p>
<h3 id="focus"><code>focus</code></h3>
<p>First, for the <code>focus</code> command I want to move to an Emacs window in the given direction if there is one, otherwise move to an X window in the same direction. Fortunately, i3 and <code>windmove</code> have the same names for directions, so the function is rather straightforward.</p>
<p>One caveat here is that the minibuffer is always the bottom-most Emacs window, so it is necessary to check for that as well.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(defun my/emacs-i3-windmove (dir)
(let ((other-window (windmove-find-other-window dir)))
(if (or (<span style="color:#a6e22e">null</span> other-window) (<span style="color:#a6e22e">window-minibuffer-p</span> other-window))
(i3-msg <span style="color:#e6db74">&#34;focus&#34;</span> (<span style="color:#a6e22e">symbol-name</span> dir))
(windmove-do-window-select dir))))
</code></pre></div><p>The relevant section of the i3 config looks like this:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">bindsym $mod+h exec emacs-i3-integration focus left
bindsym $mod+j exec emacs-i3-integration focus down
bindsym $mod+k exec emacs-i3-integration focus up
bindsym $mod+l exec emacs-i3-integration focus right
bindsym $mod+Left exec emacs-i3-integration focus left
bindsym $mod+Down exec emacs-i3-integration focus down
bindsym $mod+Up exec emacs-i3-integration focus up
bindsym $mod+Right exec emacs-i3-integration focus right
</code></pre></div><p>The Emacs function has to be called like that:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(my/emacs-i3-windmove <span style="color:#e6db74">&#39;right</span>)
</code></pre></div><h3 id="move"><code>move</code></h3>
<p>For the <code>move</code> command I want the following behavior:</p>
<ul>
<li>if there is space in the required direction, move the Emacs window there;</li>
<li>if there is no space in the required direction, but space in the orthogonal directions, move the Emacs window so that there is no more space in the orthogonal directions;</li>
<li>otherwise, move an X window (which has to be an Emacs frame).</li>
</ul>
<p>For the first part, <code>window-swap-states</code> with <code>windmove-find-other-window</code> do well enough.</p>
<p><code>evil-move-window</code> works well for the second part. By itself it doesn&rsquo;t behave quite like i3, for instance, <code>(evil-move-window 'right)</code> in a three-column split would move the window from the far left side to the far right side (bypassing center). Hence the combination as described here.</p>
<p>So here is a simple predicate which checks whether there is space in the given direction.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(defun my/emacs-i3-direction-exists-p (dir)
(some (lambda (dir)
(let ((win (windmove-find-other-window dir)))
(and win (not (<span style="color:#a6e22e">window-minibuffer-p</span> win)))))
(pcase dir
(<span style="color:#e6db74">&#39;width</span> <span style="color:#f92672">&#39;</span>(left right))
(<span style="color:#e6db74">&#39;height</span> <span style="color:#f92672">&#39;</span>(up down)))))
</code></pre></div><p>And the implementation of the move command.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(defun my/emacs-i3-move-window (dir)
(let ((other-window (windmove-find-other-window dir))
(other-direction (my/emacs-i3-direction-exists-p
(pcase dir
(<span style="color:#e6db74">&#39;up</span> <span style="color:#e6db74">&#39;width</span>)
(<span style="color:#e6db74">&#39;down</span> <span style="color:#e6db74">&#39;width</span>)
(<span style="color:#e6db74">&#39;left</span> <span style="color:#e6db74">&#39;height</span>)
(<span style="color:#e6db74">&#39;right</span> <span style="color:#e6db74">&#39;height</span>)))))
(cond
((and other-window (not (<span style="color:#a6e22e">window-minibuffer-p</span> other-window)))
(window-swap-states (<span style="color:#a6e22e">selected-window</span>) other-window))
(other-direction
(evil-move-window dir))
(<span style="color:#66d9ef">t</span> (i3-msg <span style="color:#e6db74">&#34;move&#34;</span> (<span style="color:#a6e22e">symbol-name</span> dir))))))
</code></pre></div><p>The relevant section of the i3 config:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">bindsym $mod+Shift+h exec emacs-i3-integration move left
bindsym $mod+Shift+j exec emacs-i3-integration move down
bindsym $mod+Shift+k exec emacs-i3-integration move up
bindsym $mod+Shift+l exec emacs-i3-integration move right
bindsym $mod+Shift+Left exec emacs-i3-integration move left
bindsym $mod+Shift+Down exec emacs-i3-integration move down
bindsym $mod+Shift+Up exec emacs-i3-integration move up
bindsym $mod+Shift+Right exec emacs-i3-integration move right
</code></pre></div><h3 id="resize-and-balance-windows"><code>resize</code> and balance windows</h3>
<p>Next on the line are <code>resize grow</code> and <code>resize shrink</code>. <code>evil-window-</code> functions do nicely for this task.</p>
<p>This function also checks whether there is space to resize in the given direction with the help of the predicate defined above. The command is forwarded back to i3 if there is not.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(defun my/emacs-i3-resize-window (dir kind value)
(if (or (one-window-p)
(not (my/emacs-i3-direction-exists-p dir)))
(i3-msg <span style="color:#e6db74">&#34;resize&#34;</span> (<span style="color:#a6e22e">symbol-name</span> kind) (<span style="color:#a6e22e">symbol-name</span> dir)
(<span style="color:#a6e22e">format</span> <span style="color:#e6db74">&#34;%s px or %s ppt&#34;</span> value value))
(setq value (<span style="color:#a6e22e">/</span> value <span style="color:#ae81ff">2</span>))
(pcase kind
(<span style="color:#e6db74">&#39;shrink</span>
(pcase dir
(<span style="color:#e6db74">&#39;width</span>
(evil-window-decrease-width value))
(<span style="color:#e6db74">&#39;height</span>
(evil-window-decrease-height value))))
(<span style="color:#e6db74">&#39;grow</span>
(pcase dir
(<span style="color:#e6db74">&#39;width</span>
(evil-window-increase-width value))
(<span style="color:#e6db74">&#39;height</span>
(evil-window-increase-height value)))))))
</code></pre></div><p>Here I&rsquo;m following the default configuration of i3, which creates a &ldquo;submode&rdquo; to resize windows.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">mode <span style="color:#e6db74">&#34;resize&#34;</span> <span style="color:#f92672">{</span>
bindsym h exec emacs-i3-integration resize shrink width <span style="color:#ae81ff">10</span> px or <span style="color:#ae81ff">10</span> ppt
bindsym j exec emacs-i3-integration resize grow height <span style="color:#ae81ff">10</span> px or <span style="color:#ae81ff">10</span> ppt
bindsym k exec emacs-i3-integration resize shrink height <span style="color:#ae81ff">10</span> px or <span style="color:#ae81ff">10</span> ppt
bindsym l exec emacs-i3-integration resize grow width <span style="color:#ae81ff">10</span> px or <span style="color:#ae81ff">10</span> ppt
bindsym Shift+h exec emacs-i3-integration resize shrink width <span style="color:#ae81ff">100</span> px or <span style="color:#ae81ff">100</span> ppt
bindsym Shift+j exec emacs-i3-integration resize grow height <span style="color:#ae81ff">100</span> px or <span style="color:#ae81ff">100</span> ppt
bindsym Shift+k exec emacs-i3-integration resize shrink height <span style="color:#ae81ff">100</span> px or <span style="color:#ae81ff">100</span> ppt
bindsym Shift+l exec emacs-i3-integration resize grow width <span style="color:#ae81ff">100</span> px or <span style="color:#ae81ff">100</span> ppt
<span style="color:#75715e"># same bindings, but for the arrow keys</span>
bindsym Left exec emacs-i3-integration resize shrink width <span style="color:#ae81ff">10</span> px or <span style="color:#ae81ff">10</span> ppt
bindsym Down exec emacs-i3-integration resize grow height <span style="color:#ae81ff">10</span> px or <span style="color:#ae81ff">10</span> ppt
bindsym Up exec emacs-i3-integration resize shrink height <span style="color:#ae81ff">10</span> px or <span style="color:#ae81ff">10</span> ppt
bindsym Right exec emacs-i3-integration resize grow width <span style="color:#ae81ff">10</span> px or <span style="color:#ae81ff">10</span> ppt
bindsym Shift+Left exec emacs-i3-integration resize shrink width <span style="color:#ae81ff">100</span> px or <span style="color:#ae81ff">100</span> ppt
bindsym Shift+Down exec emacs-i3-integration resize grow height <span style="color:#ae81ff">100</span> px or <span style="color:#ae81ff">100</span> ppt
bindsym Shift+Up exec emacs-i3-integration resize shrink height <span style="color:#ae81ff">100</span> px or <span style="color:#ae81ff">100</span> ppt
bindsym Shift+Right exec emacs-i3-integration resize grow width <span style="color:#ae81ff">100</span> px or <span style="color:#ae81ff">100</span> ppt
bindsym equal exec i3-emacs-balance-windows
<span style="color:#75715e"># back to normal: Enter or Escape</span>
bindsym Return mode <span style="color:#e6db74">&#34;default&#34;</span>
bindsym Escape mode <span style="color:#e6db74">&#34;default&#34;</span>
<span style="color:#f92672">}</span>
</code></pre></div><p>Next, Emacs has a built-in function called <code>balance-windows</code>, but i3 doesn&rsquo;t. Fortunately, there is a Python package called <a href="https://github.com/atreyasha/i3-balance-workspace">i3-balance-workspace</a>, which performs a similar operation with i3&rsquo;s IPC. If you use Guix as I do, I&rsquo;ve written a <a href="https://github.com/SqrtMinusOne/channel-q/blob/master/i3-balance-workspace.scm">package definition</a>.</p>
<p>So here is a small wrapper which calls <code>i3_balance_workspace</code> and <code>M-x balance-windows</code> if the current window is Emacs.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash"><span style="color:#66d9ef">if</span> <span style="color:#f92672">[[</span> <span style="color:#66d9ef">$(</span>xdotool getactivewindow getwindowname<span style="color:#66d9ef">)</span> <span style="color:#f92672">=</span>~ ^emacs<span style="color:#f92672">(</span>:.*<span style="color:#f92672">)</span>?@.* <span style="color:#f92672">]]</span>; <span style="color:#66d9ef">then</span>
emacsclient -e <span style="color:#e6db74">&#34;(balance-windows)&#34;</span> &amp;
<span style="color:#66d9ef">fi</span>
i3_balance_workspace
</code></pre></div><h3 id="layout-toggle-split"><code>layout toggle split</code></h3>
<p><a href="https://github.com/emacsorphanage/transpose-frame">transpose-frame</a> is a package to &ldquo;transpose&rdquo; the current Emacs windows layout, which behaves somewhat similar to the <code>layout toggle split</code> command in i3, so I&rsquo;ll use it as well.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(use-package transpose-frame
:straight <span style="color:#66d9ef">t</span>
:commands (transpose-frame))
</code></pre></div><p>The i3 config for this command:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">bindsym $mod+e exec emacs-i3-integration layout toggle split
</code></pre></div><h3 id="the-entrypoint">The entrypoint</h3>
<p>Finally, the entrypoint for the Emacs integration. In addition to the commands defined above, it processes <code>split</code> and <code>kill</code> commands and passes every other command back to i3.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(defun my/emacs-i3-integration (command)
(pcase command
((rx bos <span style="color:#e6db74">&#34;focus&#34;</span>)
(my/emacs-i3-windmove
(<span style="color:#a6e22e">intern</span> (<span style="color:#a6e22e">elt</span> (split-string command) <span style="color:#ae81ff">1</span>))))
((rx bos <span style="color:#e6db74">&#34;move&#34;</span>)
(my/emacs-i3-move-window
(<span style="color:#a6e22e">intern</span> (<span style="color:#a6e22e">elt</span> (split-string command) <span style="color:#ae81ff">1</span>))))
((rx bos <span style="color:#e6db74">&#34;resize&#34;</span>)
(my/emacs-i3-resize-window
(<span style="color:#a6e22e">intern</span> (<span style="color:#a6e22e">elt</span> (split-string command) <span style="color:#ae81ff">2</span>))
(<span style="color:#a6e22e">intern</span> (<span style="color:#a6e22e">elt</span> (split-string command) <span style="color:#ae81ff">1</span>))
(<span style="color:#a6e22e">string-to-number</span> (<span style="color:#a6e22e">elt</span> (split-string command) <span style="color:#ae81ff">3</span>))))
(<span style="color:#e6db74">&#34;layout toggle split&#34;</span> (transpose-frame))
(<span style="color:#e6db74">&#34;split h&#34;</span> (evil-window-split))
(<span style="color:#e6db74">&#34;split v&#34;</span> (evil-window-vsplit))
(<span style="color:#e6db74">&#34;kill&#34;</span> (evil-quit))
(<span style="color:#a6e22e">-</span> (i3-msg command))))
</code></pre></div><p>The rest of the relevant i3 config to do the splits:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">bindsym $mod+s exec emacs-i3-integration split h
bindsym $mod+v exec emacs-i3-integration split v
</code></pre></div><p>And to kill the window:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">bindsym $mod+Shift+q exec emacs-i3-integration kill
</code></pre></div><h3 id="switching-i3-tabs">Switching i3 tabs</h3>
<p>As I use i3&rsquo;s tabbed layout quite extensively, occasionally I want to switch out of the Emacs tab with one button, and that&rsquo;s where my integration may interfere.</p>
<p>As a workaround, I found a small Rust program called <a href="https://github.com/nikola-kocic/i3-switch-tabs">i3-switch-tabs</a>, which also communicates with i3 via its IPC to switch the top-level tab. I&rsquo;ve written a <a href="https://github.com/SqrtMinusOne/channel-q/blob/master/i3-switch-tabs.scm">Guix package definition</a> for that as well.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">bindsym $mod+period exec i3-switch-tabs right
bindsym $mod+comma exec i3-switch-tabs left
</code></pre></div><h2 id="conclusion">Conclusion</h2>
<p>So, how does all of that feel? Actually, I got used to that setup pretty quickly. Using <code>&lt;s-Q&gt;</code> to quit windows and the <code>&lt;s-r&gt;</code> submode to resize them is particularly nice. I&rsquo;ve seen people making hydras in Emacs to do the latter.</p>
<p>All of that would probably be easier to do in a WM which is configured in a programming language rather than in a self-cooked DSL, so I may try to replicate that somewhere else in an unknown time in the future. Meanwhile, it&rsquo;s pretty good.</p>
</div>
</div><div id="footer" class="mb-5">
<hr>
<div class="container text-center">
</div>
<div class="container text-center">
<a href="https://sqrtminusone.xyz/" title="Pavel Korytov, 2021"><small>Pavel Korytov, 2021</small></a>
</div>
</div>
</body>
</html>

View file

@ -63,6 +63,8 @@
<h1>Posts</h1>
<ul>
<li><a href="https://sqrtminusone.xyz/posts/2021-10-04-emacs-i3/">2021-10-06 | Getting a consistent set of keybindings between i3 and Emacs</a></li>
<li><a href="https://sqrtminusone.xyz/posts/2021-09-07-emms/">2021-09-08 | My EMMS and elfeed setup</a></li>
<li><a href="https://sqrtminusone.xyz/posts/2021-05-01-org-python/">2021-05-01 | Replacing Jupyter Notebook with Org Mode</a></li>

View file

@ -6,7 +6,17 @@
<description>Recent content in Posts on SqrtMinusOne</description>
<generator>Hugo -- gohugo.io</generator>
<language>en-us</language>
<lastBuildDate>Wed, 08 Sep 2021 00:00:00 +0000</lastBuildDate><atom:link href="https://sqrtminusone.xyz/posts/index.xml" rel="self" type="application/rss+xml" />
<lastBuildDate>Wed, 06 Oct 2021 00:00:00 +0000</lastBuildDate><atom:link href="https://sqrtminusone.xyz/posts/index.xml" rel="self" type="application/rss+xml" />
<item>
<title>Getting a consistent set of keybindings between i3 and Emacs</title>
<link>https://sqrtminusone.xyz/posts/2021-10-04-emacs-i3/</link>
<pubDate>Wed, 06 Oct 2021 00:00:00 +0000</pubDate>
<guid>https://sqrtminusone.xyz/posts/2021-10-04-emacs-i3/</guid>
<description>Intro One advantage of EXWM for an Emacs user is that EXWM gives one set of keybindings to manage both Emacs windows and X windows. In every other WM, like my preferred i3wm, two orthogonal keymaps seem to be necessary. But, as both programs are quite customizable, I want to see whether I can replicate at least some part of the EXWM goodness in i3.
But why not just use EXWM?</description>
</item>
<item>
<title>My EMMS and elfeed setup</title>
<link>https://sqrtminusone.xyz/posts/2021-09-07-emms/</link>

View file

@ -2,26 +2,32 @@
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
xmlns:xhtml="http://www.w3.org/1999/xhtml">
<url>
<loc>https://sqrtminusone.xyz/tags/elfeed/</loc>
<lastmod>2021-09-08T00:00:00+00:00</lastmod>
</url><url>
<loc>https://sqrtminusone.xyz/tags/emacs/</loc>
<lastmod>2021-10-06T00:00:00+00:00</lastmod>
</url><url>
<loc>https://sqrtminusone.xyz/posts/2021-10-04-emacs-i3/</loc>
<lastmod>2021-10-06T00:00:00+00:00</lastmod>
</url><url>
<loc>https://sqrtminusone.xyz/tags/i3wm/</loc>
<lastmod>2021-10-06T00:00:00+00:00</lastmod>
</url><url>
<loc>https://sqrtminusone.xyz/</loc>
<lastmod>2021-10-06T00:00:00+00:00</lastmod>
</url><url>
<loc>https://sqrtminusone.xyz/posts/</loc>
<lastmod>2021-10-06T00:00:00+00:00</lastmod>
</url><url>
<loc>https://sqrtminusone.xyz/tags/</loc>
<lastmod>2021-10-06T00:00:00+00:00</lastmod>
</url><url>
<loc>https://sqrtminusone.xyz/tags/elfeed/</loc>
<lastmod>2021-09-08T00:00:00+00:00</lastmod>
</url><url>
<loc>https://sqrtminusone.xyz/tags/emms/</loc>
<lastmod>2021-09-08T00:00:00+00:00</lastmod>
</url><url>
<loc>https://sqrtminusone.xyz/</loc>
<lastmod>2021-09-08T00:00:00+00:00</lastmod>
</url><url>
<loc>https://sqrtminusone.xyz/posts/2021-09-07-emms/</loc>
<lastmod>2021-09-08T00:00:00+00:00</lastmod>
</url><url>
<loc>https://sqrtminusone.xyz/posts/</loc>
<lastmod>2021-09-08T00:00:00+00:00</lastmod>
</url><url>
<loc>https://sqrtminusone.xyz/tags/</loc>
<lastmod>2021-09-08T00:00:00+00:00</lastmod>
</url><url>
<loc>https://sqrtminusone.xyz/tags/org/</loc>
<lastmod>2021-05-01T00:00:00+00:00</lastmod>

View file

@ -63,6 +63,8 @@
<h1>emacs</h1>
<ul>
<li><a href="https://sqrtminusone.xyz/posts/2021-10-04-emacs-i3/">2021-10-06 | Getting a consistent set of keybindings between i3 and Emacs</a></li>
<li><a href="https://sqrtminusone.xyz/posts/2021-09-07-emms/">2021-09-08 | My EMMS and elfeed setup</a></li>
<li><a href="https://sqrtminusone.xyz/posts/2021-05-01-org-python/">2021-05-01 | Replacing Jupyter Notebook with Org Mode</a></li>

View file

@ -6,7 +6,17 @@
<description>Recent content in emacs on SqrtMinusOne</description>
<generator>Hugo -- gohugo.io</generator>
<language>en-us</language>
<lastBuildDate>Wed, 08 Sep 2021 00:00:00 +0000</lastBuildDate><atom:link href="https://sqrtminusone.xyz/tags/emacs/index.xml" rel="self" type="application/rss+xml" />
<lastBuildDate>Wed, 06 Oct 2021 00:00:00 +0000</lastBuildDate><atom:link href="https://sqrtminusone.xyz/tags/emacs/index.xml" rel="self" type="application/rss+xml" />
<item>
<title>Getting a consistent set of keybindings between i3 and Emacs</title>
<link>https://sqrtminusone.xyz/posts/2021-10-04-emacs-i3/</link>
<pubDate>Wed, 06 Oct 2021 00:00:00 +0000</pubDate>
<guid>https://sqrtminusone.xyz/posts/2021-10-04-emacs-i3/</guid>
<description>Intro One advantage of EXWM for an Emacs user is that EXWM gives one set of keybindings to manage both Emacs windows and X windows. In every other WM, like my preferred i3wm, two orthogonal keymaps seem to be necessary. But, as both programs are quite customizable, I want to see whether I can replicate at least some part of the EXWM goodness in i3.
But why not just use EXWM?</description>
</item>
<item>
<title>My EMMS and elfeed setup</title>
<link>https://sqrtminusone.xyz/posts/2021-09-07-emms/</link>

View file

@ -0,0 +1,83 @@
<!DOCTYPE html>
<html lang=""><head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>i3wm</title>
<meta name="description" content="Freedom is a state of mind">
<meta name="author" content='SqrtMinusOne'>
<link href="https://fonts.googleapis.com/css2?family=Inconsolata:wght@400;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css" integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css" integrity="sha512-iBBXm8fW90+nuLcSKlbmrPcLa0OT92xO1BIsZ+ywDWZCvqsWgccV3gFoRBv0z+8dLJgyAHIhR35VZc2oM/gI1w==" crossorigin="anonymous">
<link rel="stylesheet" href="/sass/researcher.min.css">
<link rel="icon" type="image/ico" href="https://sqrtminusone.xyz/favicon.ico">
<link rel="alternate" type="application/rss+xml" href="https://sqrtminusone.xyz/tags/i3wm/index.xml" title="SqrtMinusOne" />
</head>
<body><div class="container mt-5">
<nav class="navbar navbar-expand-sm flex-column flex-sm-row text-nowrap p-0">
<a class="navbar-brand mx-0 mr-sm-auto" href="https://sqrtminusone.xyz/" title="SqrtMinusOne">
SqrtMinusOne
</a>
<div class="navbar-nav flex-row flex-wrap justify-content-center">
<a class="nav-item nav-link" href="/" title="Index">
Index
</a>
<span class="nav-item navbar-text mx-1">/</span>
<a class="nav-item nav-link" href="/posts/" title="Posts">
Posts
</a>
<span class="nav-item navbar-text mx-1">/</span>
<a class="nav-item nav-link" href="/configs/readme" title="Configs">
Configs
</a>
</div>
</nav>
</div>
<hr>
<div id="content">
<div class="container">
<h1>i3wm</h1>
<ul>
<li><a href="https://sqrtminusone.xyz/posts/2021-10-04-emacs-i3/">2021-10-06 | Getting a consistent set of keybindings between i3 and Emacs</a></li>
</ul>
</div>
</div><div id="footer" class="mb-5">
<hr>
<div class="container text-center">
</div>
<div class="container text-center">
<a href="https://sqrtminusone.xyz/" title="Pavel Korytov, 2021"><small>Pavel Korytov, 2021</small></a>
</div>
</div>
</body>
</html>

View file

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>i3wm on SqrtMinusOne</title>
<link>https://sqrtminusone.xyz/tags/i3wm/</link>
<description>Recent content in i3wm on SqrtMinusOne</description>
<generator>Hugo -- gohugo.io</generator>
<language>en-us</language>
<lastBuildDate>Wed, 06 Oct 2021 00:00:00 +0000</lastBuildDate><atom:link href="https://sqrtminusone.xyz/tags/i3wm/index.xml" rel="self" type="application/rss+xml" />
<item>
<title>Getting a consistent set of keybindings between i3 and Emacs</title>
<link>https://sqrtminusone.xyz/posts/2021-10-04-emacs-i3/</link>
<pubDate>Wed, 06 Oct 2021 00:00:00 +0000</pubDate>
<guid>https://sqrtminusone.xyz/posts/2021-10-04-emacs-i3/</guid>
<description>Intro One advantage of EXWM for an Emacs user is that EXWM gives one set of keybindings to manage both Emacs windows and X windows. In every other WM, like my preferred i3wm, two orthogonal keymaps seem to be necessary. But, as both programs are quite customizable, I want to see whether I can replicate at least some part of the EXWM goodness in i3.
But why not just use EXWM?</description>
</item>
</channel>
</rss>

View file

@ -63,9 +63,11 @@
<h1>Tags</h1>
<ul>
<li><a href="https://sqrtminusone.xyz/tags/elfeed/">2021-09-08 | elfeed</a></li>
<li><a href="https://sqrtminusone.xyz/tags/emacs/">2021-10-06 | emacs</a></li>
<li><a href="https://sqrtminusone.xyz/tags/emacs/">2021-09-08 | emacs</a></li>
<li><a href="https://sqrtminusone.xyz/tags/i3wm/">2021-10-06 | i3wm</a></li>
<li><a href="https://sqrtminusone.xyz/tags/elfeed/">2021-09-08 | elfeed</a></li>
<li><a href="https://sqrtminusone.xyz/tags/emms/">2021-09-08 | emms</a></li>

View file

@ -6,7 +6,25 @@
<description>Recent content in Tags on SqrtMinusOne</description>
<generator>Hugo -- gohugo.io</generator>
<language>en-us</language>
<lastBuildDate>Wed, 08 Sep 2021 00:00:00 +0000</lastBuildDate><atom:link href="https://sqrtminusone.xyz/tags/index.xml" rel="self" type="application/rss+xml" />
<lastBuildDate>Wed, 06 Oct 2021 00:00:00 +0000</lastBuildDate><atom:link href="https://sqrtminusone.xyz/tags/index.xml" rel="self" type="application/rss+xml" />
<item>
<title>emacs</title>
<link>https://sqrtminusone.xyz/tags/emacs/</link>
<pubDate>Wed, 06 Oct 2021 00:00:00 +0000</pubDate>
<guid>https://sqrtminusone.xyz/tags/emacs/</guid>
<description></description>
</item>
<item>
<title>i3wm</title>
<link>https://sqrtminusone.xyz/tags/i3wm/</link>
<pubDate>Wed, 06 Oct 2021 00:00:00 +0000</pubDate>
<guid>https://sqrtminusone.xyz/tags/i3wm/</guid>
<description></description>
</item>
<item>
<title>elfeed</title>
<link>https://sqrtminusone.xyz/tags/elfeed/</link>
@ -16,15 +34,6 @@
<description></description>
</item>
<item>
<title>emacs</title>
<link>https://sqrtminusone.xyz/tags/emacs/</link>
<pubDate>Wed, 08 Sep 2021 00:00:00 +0000</pubDate>
<guid>https://sqrtminusone.xyz/tags/emacs/</guid>
<description></description>
</item>
<item>
<title>emms</title>
<link>https://sqrtminusone.xyz/tags/emms/</link>