Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
Use fennel to write the awesome-wm config

Fetch a recent Fennel version (the code here uses 0.8) and what else you need (e.g. I also use fun.fnl) into your ~/.config/awesome/ directory.

Then put just some bootstrap code to allow Fennel require files in the rc.lua:

local fennel = require("./fennel")
fennel.path = fennel.path .. ";.config/awesome/?.fnl"
table.insert(package.loaders or package.searchers, fennel.searcher)

Note: add the path to your config relative to your home directory.

After that block just require your Awesome Fennel at the end (in my case the file is named cfg.fnl and i use require("cfg").

(local fun (require "fun"))
(local gears (require "gears"))
(local awful (require "awful"))
(require "awful.autofocus")
(local naughty (require "naughty"))
{:with-selected-tag (fn [name body1 ...]
`(let [,name (. mouse.screen :selected_tag)]
(when ,name
(local focus-colors
; from
; ["#eb7070" "#fec771" "#e6e56c" "#64e291" ]
; from
; ["#f06868" "#fab57a" "#edf798" "#80d6ff" ]
; from
; ["#fffe9f" "#ffd480" "#fca180" "#f56262" ]
; from
["#cd4545" "#f16821" "#f3a333" "#fffe9a"]
(local background-color "#110022")
(local unfocus-color background-color)
(local focus-border-width 2)
; Tools
(fn notify
(naughty.notify {:text text}))
(fn debug
(notify (gears.debug.dump_return x)))
(fn cset
[k v]
(fn [c]
(tset c k v)))
(fn cinv
(fn [c]
(let [v (. c k)]
(tset c k (not v)))))
(local modifiers {:mod "Mod4"
:shift "Shift"
:ctrl "Control"})
(fn map-mods
(->> mods
( (partial . modifiers))
(fn key
[mods key-code fun]
(awful.key (map-mods mods) key-code fun))
(fn btn
[mods btn-code fun]
(awful.button (map-mods mods) btn-code fun))
(fn invert-screen
(os.execute "xcalib -c -a") ; clear
(when invert?
(os.execute "xcalib -i -a")))
; Tag managment
; each client gets an equal share over the width of workarea
(local layout-columns
(fn [p]
(let [t (or p.tag (. screen p.screen :selected_tag))
wa p.workarea
cs p.clients
nc (length cs)]
(when (< 0 nc)
(let [width (math.floor (/ wa.width nc))]
(fun.each (fn [x c]
(tset p :geometries c {:x (+ wa.x x)
:y wa.y
:width width
:height wa.height}))
( (fun.range 0 wa.width width) cs))))))})
(local layouts [
(local tags {})
(var current-tag-pos [0 0])
(fn set-tag-pos
[tag pos]
(let [[x y] pos]
(doto tag
(tset :x-pos x)
(tset :y-pos y))))
(fn get-tag-pos
[(. tag :x-pos) (. tag :y-pos)])
(fn translate-pos
[pos off]
(let [[x y] pos
[off-x off-y] off]
[(+ x off-x) (+ y off-y)]))
(fn tag-name
(let [[x y] pos ]
(.. "(" x " " y ")")))
(fn get-or-create-tag
(let [tn (tag-name pos)]
(when (not (. tags tn))
(let [[tag] (awful.tag [tn] mouse.screen (. layouts 1))]
(tset tags tn tag)
(set-tag-pos tag pos)))
(. tags tn)))
(fn current-tag
(get-or-create-tag current-tag-pos))
(fn view-current-tag
(: (current-tag) :view_only))
(local view-all-tag-name "view-all")
(local view-all-tag
(. (awful.tag [view-all-tag-name] mouse.screen awful.layout.suit.fair) 1))
(fn view-all-tags
(: view-all-tag :view_only))
(fn select-tag-by-focused-client
(->> (c:tags)
(fun.filter (partial not= view-all-tag))
(fun.each #(set current-tag-pos (get-tag-pos $1))))
(fn select-current-tag-by-offset
(with-selected-tag tag
(set current-tag-pos (get-tag-pos tag)))
(set current-tag-pos (translate-pos current-tag-pos off))
(fn move-client-relative
[off c]
(c:tags [(get-or-create-tag (translate-pos current-tag-pos off)) view-all-tag]))
(fn move-client-relative-and-select
[off c]
(move-client-relative off c)
(select-current-tag-by-offset off))
(fn move-all-clients-relative-and-select
(fun.each (partial move-client-relative off)
(select-current-tag-by-offset off))
(fn focus-client-by-offset
(awful.client.focus.byidx off)
(when client.focus
(fn is-inverted?
(if (. t :inverted?) true false))
(fn set-inverted
[t inverted?]
(tset t :inverted? inverted?)
(invert-screen inverted?))
(fn toggle-invert-screen
(with-selected-tag t
(let [inverted? (not (is-inverted? t))]
(set-inverted t inverted?))))
(fn arrange-tag
; focus from history
(when (not client.focus)
(let [c (awful.client.focus.history.get screen 0)]
(when c
(tset client :focus c))))
; set a border width, if there is more than one client on the tag
(let [cs (awful.client.visible screen)
bw (if (> (length cs) 1) focus-border-width 0)]
(fn [c focus-color]
(doto c
(tset :border_width bw)
(tset :focus_color focus-color)))
( cs (fun.cycle focus-colors))))
; set focus color for current client (focus event is before arrange and the colors are not there yet)
(let [c (. client :focus)]
(when c
(tset c :border_color (. c :focus_color))))
; set inverted screen state from tag
(with-selected-tag t
(invert-screen (is-inverted? t))))
(fn unminimize-tag
(fun.each (fn [client]
(tset client :minimized false)
;;; Main Config
(local global-keys
(key [:mod :shift :ctrl] "Escape" awesome.restart)
(key [:mod :shift] "a" view-all-tags)
(key [:mod :shift] "i" toggle-invert-screen)
(key [:mod] "h" #(select-current-tag-by-offset [-1 0]))
(key [:mod] "l" #(select-current-tag-by-offset [ 1 0]))
(key [:mod] "k" #(select-current-tag-by-offset [ 0 -1]))
(key [:mod] "j" #(select-current-tag-by-offset [ 0 1]))
(key [:mod :ctrl] "h" #(move-all-clients-relative-and-select [-1 0]))
(key [:mod :ctrl] "l" #(move-all-clients-relative-and-select [ 1 0]))
(key [:mod :ctrl] "k" #(move-all-clients-relative-and-select [ 0 -1]))
(key [:mod :ctrl] "j" #(move-all-clients-relative-and-select [ 0 1]))
(key [:mod] "space" #( layouts 1))
(key [:mod :shift] "space" #( layouts -1))
(key [:mod :ctrl] "space" awful.client.floating.toggle)
(key [:mod] "Tab" #(focus-client-by-offset 1))
(key [:mod :shift] "Tab" #(focus-client-by-offset -1))
(key [:mod :ctrl] "Tab" #(awful.client.swap.byidx 1))
(key [:mod :shift :ctrl] "Tab" #(awful.client.swap.byidx -1))
(key [:mod :shift] "BackSpace" #(unminimize-tag (awful.tag.selected)))
(local client-keys
(key [:mod] "Escape" (fn [c] (c:kill)))
(key [:mod] "a" select-tag-by-focused-client)
(key [:mod :shift] "f" (cinv :focusable))
(key [:mod :shift] "s" (cinv :sticky))
(key [:mod :shift] "x" (cinv :maximized_horizontal))
(key [:mod :shift] "y" (cinv :maximized_vertical))
(key [:mod :shift] "m" (cinv :maximized))
(key [:mod :shift] "h" (partial move-client-relative-and-select [-1 0]))
(key [:mod :shift] "l" (partial move-client-relative-and-select [ 1 0]))
(key [:mod :shift] "k" (partial move-client-relative-and-select [ 0 -1]))
(key [:mod :shift] "j" (partial move-client-relative-and-select [ 0 1]))
(local client-buttons
(btn [:mod] 1 awful.mouse.client.move)
(btn [:mod] 3 awful.mouse.client.resize)
(local rules [
{:rule {}
:properties {:focus true
:keys client-keys
:buttons client-buttons}}
(local client-event-handlers
{"manage" (fn [c]
(c:tags [(current-tag) view-all-tag]))
"mouse::enter" (fn [c]
; TODO if awful.layout.get(c.screen) ~= awful.layout.suit.magnifier and awful.client.focus.filter(c) then
(if (awful.client.focus.filter c)
(tset client :focus c)))
"focus" (fn [c]
(let [focus-color (. c :focus_color)]
; focus (e.g. from rules) is applied before arrange and the client might not yet have a color
(when focus-color
(tset c :border_color focus-color))))
"unfocus" (cset :border_color unfocus-color)})
; Wire everything up
(fun.each client.connect_signal client-event-handlers)
(fn [s]
(s:connect_signal "arrange" arrange-tag)))
(root.keys global-keys)
(tset awful.rules :rules rules)
(gears.wallpaper.set background-color)
local fennel = require("./fennel")
fennel.path = fennel.path .. ";.config/awesome/?.fnl"
table.insert(package.loaders or package.searchers, fennel.make_searcher({correlate=true}))

This comment has been minimized.

Copy link

@p-himik p-himik commented Sep 18, 2020

To any future reader - notice that getting the fennel.lua file now requires an additional step: bakpakin/Fennel@650f0ad


This comment has been minimized.

Copy link
Owner Author

@christoph-frick christoph-frick commented Jan 29, 2021

"Binary" distribution of fennel changed from around 0.5. Downloads including
a fennel.lua are published to -- but at the
time I switched to 0.8 that was not advertised publicly and I learned about it
in IRC.

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