I've been trying to get a more emacs~/~stumpwm
-y feel in my window manager since I discovered that I can use xbindkeys
to create
emacs
-like keybindings.
Today I got a little closer to that. I had some bash
scripts that
helped my xbindkeys
setup with things like switching tags and moving
windows, since that involved gathering some information and piping it
into dmenu
.
I figured out how I should do that, though. So now I've changed my
~/.xbindkeys.scm
to include some functions to do that for me. You
could look at it here.
I was having some trouble with calling dmenu
though. I started with
trying to use open-pipe
with OPEN_BOTH
argument so I could first write
to and afterwards read from it. I didn't get it to work, I think it's
because I didn't send an EOF
at the end of the input, but I haven't
found out how to do that yet. I ended up building a string that looks
like echo 'value1\nvalue2\nvalue3\n' | dmenu
and using that with
open-input-pipe
and using read-line
on it. This looks like:
(define list '("value1" "value2" "value3")) (let* ((file (open-input-pipe (string-append "echo '" (string-join list "\n") "' | dmenu"))) (tag (read-line file))) (close-port file)) (display tag)
That will give the result of the dmenu
call, it can be seen in the
choose-tag
function.
Of course you shouldn't forget that tag can still be nil
or something
that isn't in the list, so I use the string?
and member
functions to
check whether I got something at all and if it exists in list
.
Next up will be seeing what I can do with the information at
hand. First idea is to reorder the tags and such as they do in
emacs. I can (easily) keep track of the last picked value and I could
keep an eye on the current value. Another idea, not directly related
to all this is run-or-raise functionality, if I keep track what is
started/moved where I might be able to do that as well, although that
is not emacs
related.
Heh, I only realized later that I'd posted snippets from my strange herbstluftwm config without explaining it. So you get lispy commands instead of bashy ones.
First, I'll say something to those people who don't know herbstluftwm, or its configuration method.
herbstluftwm uses a special program to send commands to the window manager while it's running. And the only configuration you can do is actually calling that program multiple times during startup. This may sound limiting in the way that I'm saying it, but it really isn't.
herbstluftwm calls the ~~/.config/herbstluftwm/autostart~ file. This file should contain some shell-executable code and should be executable by you. This means that it can be pretty much anything as long as it sends the right commands to the window manager.
By default a nice bash script is provided, as a starting point if you will. Now, as I'm almost certainly crazy (even just for trying this), I have replaced that original bash script with a guile script. Guile is the official GNU Extension Language and is an implementation of scheme, which is a lisp dialect. Since using emacs I have come to find lisp very interesting, and I've heard good things about guile, so I've always wanted to work with it more. Since I'm not really writing much at the moment, I'm looking for other ways to use it, like this one.
It wasn't all that hard, guile has some very nice and easy process
management functions, and all I needed to do, really, was call the
herbstclient
program over and over again. So I wrote a function for
that:
(define (hc command) "Calls the herbstclient program to execute a command" (system (string-append "herbstclient " command)))
This basically just calls the herbstclient
program and appends the
string command
to it.
Then, there are some functions to help with setting up all the settings:
(define (keybind modkey key command) "Binds a keyboard key to a command, also prints it for testing purposes" (display (string-append "keybind " modkey "-" key " " command "\n")) (hc (string-append "keybind " modkey "-" key " " command))) (define (mousebind modkey button command) "Binds a mouse button to a command" (hc (string-append "mousebind " modkey "-" button " " command))) (define (add-tag name) "Create a new tag" (hc (string-append "add " name))) (define (set variable value) "Set the value of a variable" (hc (string-append "set " variable " " value))) (define (unrule) "Clear all rules from memory" (hc "unrule -F")) (define (rule spec) "Add a new rule" (hc (string-append "rule " spec))) (define modkey "Mod4") (define (create-tag name) (add-tag name) (keybind modkey name (string-append "use " name)) (keybind modkey (string-append "Shift-" name) (string-append "move " name))) (define (dmenu-command fn nb nf) (string-append "dmenu_run -fn '" fn "' -nb '" nb "' -nf '" nf "'")) (define (set-layout layout) (display (string-append "set_layout " layout "\n")) (hc (string-append "set_layout " layout)))
I've given them some docstrings, they should be fairly self
explanatory that way. For the ones that don't have a docstring:
create-tag
creates a new tag (desktop) to be used, dmenu-command
as a
function I use to more easily change the values dmenu uses, set-layout
sets a certain layout to be used and prints this for testing purposes.
This makes it easy to do many things, although having to do everything with strings is probably not very effici��nt. I'm still looking into creating a guile extension for herbstluftwm, but I have very little experience with IPCs, guile and X programming, so I'm not going very fast with that.
I hope that explains the lispy config snippets in my last post.