[StumpWM] Reorganize some code, better keybinds and modeline

Some modules loaded in init.lisp are instead loaded in modeline.lisp,
as it makes more sense.

Update modeline’s format.

Update groups’ number and name, they now have an actual name and
visible purpose. Their definition is also made at the same time as the
definition of the windows linked to these groups, generated by
different Elisp code blocks but from the same table.

Used fonts are also updated, loading more than one doesn’t seem to
have an effect. This commit also adds a comment on OTF fonts.

More keybinds and keymaps are now defined through tables to make them
more readable and easier to maintain.

Some keybinds are removed to make more sense between my Emacs keybinds
and keychords and StumpWM’s. Some move from window keychords to buffer
keychords.

Some Elisp functions are hidden in a dedicated noexport heading.
This commit is contained in:
2021-09-01 21:34:02 +02:00
parent b47dcbca37
commit 22bbd61ed1
+433 -228
View File
@@ -3,7 +3,8 @@
#+OPTIONS: auto-id:t #+OPTIONS: auto-id:t
#+HTML_HEAD_EXTRA: <meta name="description" content="Phundrak's StumpWM config" /> #+HTML_HEAD_EXTRA: <meta name="description" content="Phundrak's StumpWM config" />
#+HTML_HEAD_EXTRA: <meta property="og:title" content="Phundrak's StumpWM config" /> #+HTML_HEAD_EXTRA: <meta property="og:title" content="Phundrak's StumpWM config" />
#+HTML_HEAD_EXTRA: <meta property="og:description" content="Description of the Stump config files of Phundrak" /> #+HTML_HEAD_EXTRA: <meta property="og:description" content="Description of the Stump Window Manager configuration files of Phundrak" />
#+property: header-args:emacs-lisp :tangle no :exports results :cache yes :noweb yes
* Introduction * Introduction
:PROPERTIES: :PROPERTIES:
@@ -140,7 +141,7 @@ Now, we’ll load a couple of my custom files that will be described below:
| modeline.lisp | | modeline.lisp |
#+name: gen-load-files #+name: gen-load-files
#+headers: :tangle no :exports results :wrap src lisp :cache yes #+headers: :wrap src lisp
#+begin_src emacs-lisp :var files=first-loaded-files #+begin_src emacs-lisp :var files=first-loaded-files
(mapconcat (lambda (file) (mapconcat (lambda (file)
(format "(load \"~/.stumpwm.d/%s\")" (car file))) (format "(load \"~/.stumpwm.d/%s\")" (car file)))
@@ -175,23 +176,20 @@ windows.
#+end_src #+end_src
Next, some modules will be loaded from the ~stumpwm-contrib~ package Next, some modules will be loaded from the ~stumpwm-contrib~ package
(which is included in ~stumpwm-git~). Here is a short list including a (which is included in ~stumpwm-git~ in the AUR). Here is a short list
short description of what they are for: including a short description of what they are for:
#+name: loaded-modules #+name: loaded-modules
| Module Name | Why It Is Loaded | | Module Name | Why It Is Loaded |
|------------------+------------------------------------------------------------| |-----------------+------------------------------------------------------------|
| alert-me | Creates notifications, can also create timed notifications | | alert-me | Creates notifications, can also create timed notifications |
| battery-portable | Get information on the battery level of a laptop | | beckon | Bring the mouse cursor to the current window |
| beckon | Bring the mouse cursor to the current window | | end-session | Gracefully end programs when ending user session |
| cpu | Get the CPU usage of the computer | | globalwindows | Navigate between windows from all workspaces |
| end-session | Gracefully end programs when ending user session | | stump-backlight | Native management of backlight in StumpWM |
| globalwindows | Navigate between windows from all workspaces | | urgentwindows | Get urgent windows |
| mem | Get the memory usage of the computer |
| stump-backlight | Native management of backlight in StumpWM |
| urgentwindows | Get urgent windows |
#+name: gen-load-modules #+name: gen-load-modules
#+headers: :tangle no :exports results :wrap src lisp :cache yes #+headers: :wrap src lisp
#+begin_src emacs-lisp :var modules=loaded-modules #+begin_src emacs-lisp :var modules=loaded-modules
(mapconcat (lambda (module) (mapconcat (lambda (module)
(format "(load-module \"%s\")" (car module))) (format "(load-module \"%s\")" (car module)))
@@ -199,15 +197,12 @@ short description of what they are for:
"\n") "\n")
#+end_src #+end_src
#+RESULTS[1978f17a99db4ca68780c378e5e5d9d58f9e08bc]: gen-load-modules #+RESULTS[508e36f9747f1da901bbee63582416a8a6ba2c2f]: gen-load-modules
#+begin_src lisp #+begin_src lisp
(load-module "alert-me") (load-module "alert-me")
(load-module "battery-portable")
(load-module "beckon") (load-module "beckon")
(load-module "cpu")
(load-module "end-session") (load-module "end-session")
(load-module "globalwindows") (load-module "globalwindows")
(load-module "mem")
(load-module "stump-backlight") (load-module "stump-backlight")
(load-module "urgentwindows") (load-module "urgentwindows")
#+end_src #+end_src
@@ -224,17 +219,41 @@ And it’s done! We can now move on to the creation of the other CLisp files.
:CUSTOM_ID: Commands-1wagy001v5j0 :CUSTOM_ID: Commands-1wagy001v5j0
:header-args:lisp: :mkdirp :tangle ~/.stumpwm.d/commands.lisp :header-args:lisp: :mkdirp :tangle ~/.stumpwm.d/commands.lisp
:END: :END:
This file is going to be short. The only two custom command I have is
for Firefox, in order to either invoke a new Firefox window, or raise The first command I declare in this file is a command that will avoid
it if it already exists, and for Emacs to invoke the Emacs client or a me invoking too many Firefox instances. Either Firefox is not already
new Emacs instance if the server isn’t running. This is done like so: running and an instance is launched, or one already is and we are
brought to it. This is done like so:
#+begin_src lisp #+begin_src lisp
(defcommand firefox () () (defcommand firefox () ()
"Run or raise Firefox." "Run or raise Firefox."
(run-or-raise "firefox" '(:class "Firefox") t nil)) (run-or-raise "firefox" '(:class "Firefox") t nil))
#+end_src #+end_src
And done, next! Next, this command will not only close the current window, but it will
also close the current frame.
#+begin_src lisp
(defcommand delete-window-and-frame () ()
"Delete the current frame with its window."
(delete-window)
(remove-split))
#+end_src
The two following commands will create a new frame to the right and
below the current frame respectively, then focus it.
#+begin_src lisp
(defcommand hsplit-and-focus () ()
"Create a new frame on the right and focus it."
(hsplit)
(move-focus :right))
(defcommand vsplit-and-focus () ()
"Create a new frame below and move focus to it."
(vsplit)
(move-focus :down))
#+end_src
And done! Next!
* Colors * Colors
:PROPERTIES: :PROPERTIES:
@@ -268,7 +287,7 @@ I’ll prefix the variables’ name with ~phundrak-~ just in case it might
conflict with another package I might use in the future, so the CLisp conflict with another package I might use in the future, so the CLisp
code looks like so: code looks like so:
#+name: gen-colors #+name: gen-colors
#+headers: :tangle no :exports results :wrap src lisp :cache yes #+headers: :wrap src lisp
#+begin_src emacs-lisp :var colors=nord-colors #+begin_src emacs-lisp :var colors=nord-colors
(mapconcat (lambda (color) (mapconcat (lambda (color)
(format "(defvar phundrak-%s \"%s\")" (car color) (cadr color))) (format "(defvar phundrak-%s \"%s\")" (car color) (cadr color)))
@@ -337,7 +356,7 @@ format indicated in the manpage of ~date~.
Let’s also indicate how the groupname is displayed. Let’s also indicate how the groupname is displayed.
#+begin_src lisp #+begin_src lisp
(setf *group-format* " %t ") (setf *group-format* "%t")
#+end_src #+end_src
The window format should display first its window number, then its The window format should display first its window number, then its
@@ -346,6 +365,30 @@ titled, limited to 30 characters.
(setf *window-format* "%n: %30t") (setf *window-format* "%n: %30t")
#+end_src #+end_src
Here are some modules that we will load for the modeline:
#+name: modeline-modules
| Module Name | Why It Is Loaded |
|------------------+--------------------------------------------------|
| battery-portable | Get information on the battery level of a laptop |
| cpu | Get the CPU usage of the computer |
| mem | Get the memory usage of the computer |
#+name: gen-load-modeline-modules
#+headers: :wrap src lisp
#+begin_src emacs-lisp :var modules=modeline-modules
(mapconcat (lambda (module)
(format "(load-module \"%s\")" (car module)))
modules
"\n")
#+end_src
#+RESULTS[75023085d7c69ae09044826218830e6b678d5959]: gen-load-modeline-modules
#+begin_src lisp
(load-module "battery-portable")
(load-module "cpu")
(load-module "mem")
#+end_src
We can indicate what to display in our modeline. Be aware the ~^>~ We can indicate what to display in our modeline. Be aware the ~^>~
string will align the rest of the string to the right of the modeline. string will align the rest of the string to the right of the modeline.
~%g~ will display the group list, while ~%v~ will display the list of ~%g~ will display the group list, while ~%v~ will display the list of
@@ -354,7 +397,7 @@ highlighted, and ~%u~ will display urgent windows if there are any. ~%d~
on the other hand will display the date in the format set above, while on the other hand will display the date in the format set above, while
~%B~ will display the battery level of the laptop. ~%B~ will display the battery level of the laptop.
#+begin_src lisp #+begin_src lisp
(setf *screen-mode-line-format* (list "%g %v ^> %C | %M | %B | %d")) (setf *screen-mode-line-format* (list "%g %v %u ^> %C | %M | %B | %d"))
#+end_src #+end_src
This variable as you can see is a list of elements, although here I am This variable as you can see is a list of elements, although here I am
@@ -363,6 +406,15 @@ CLisp code in here that returns some string if the user needs some
code to return data that cannot be easily accesible otherwise. I might code to return data that cannot be easily accesible otherwise. I might
add some at some point, but not today yet. add some at some point, but not today yet.
For some reason, the ~stumptray~ module does not work for me, I get an
error saying a certain value is of type ~NIL~ and not of type
~STUMPWM:MODELINE~. I should investigate this.
** TODO Investigate why ~stumptray~ doesn’t work :noexport:
:PROPERTIES:
:CUSTOM_ID: Modeline-Investigate-why-stumptray-doesn-t-work-0juh13g0m6j0
:END:
# Also, let’s enable a system tray. # Also, let’s enable a system tray.
# #+begin_src lisp # #+begin_src lisp
# (load-module "stumptray") # (load-module "stumptray")
@@ -381,42 +433,36 @@ I’ve been used to ten groups, or workspaces, or tags, since I began
using tiling window managers. I shall then continue this habit. Here using tiling window managers. I shall then continue this habit. Here
is the list of groups I will be using: is the list of groups I will be using:
#+name: list-groups #+name: list-groups
| Groups | | Groups | Number | Windows |
|----------| |---------+--------+----------------------------|
| term | | [SYS] | 1 | |
| emacs | | [DEV] | 2 | Emacs, Virt-manager |
| www | | [WWW] | 3 | Firefox |
| files | | [FILES] | 4 | Nemo |
| media | | [MEDIA] | 5 | Gimp |
| graphics | | [SOC] | 6 | Signal, discord, lightcord |
| VMs | | [PRIV] | 7 | |
| games |
| private |
| discord |
#+name: gen-groups #+name: gen-groups
#+headers: :tangle no :exports none :cache yes #+headers: :tangle no :exports none :cache yes
#+begin_src emacs-lisp :var groups=list-groups #+begin_src emacs-lisp :var groups=list-groups
(string-join `(,(format "(grename \"%s\")" (car (car groups))) (string-trim (string-join `(,(format "(grename \"%s\")" (car (car groups)))
,@(mapcar (lambda (group) ,@(mapcar (lambda (group)
(format "(gnewbg \"%s\")" (car group))) (format "(gnewbg \"%s\")" (car group)))
(cdr groups))) (cdr groups)))
"\n") "\n")
"[[:space:]]*"
"[[:space:]]*")
#+end_src #+end_src
#+RESULTS[ed2b45d9a542233061373da32e830bd27a68d61b]: gen-groups #+RESULTS[caa45af7c6ee092f88acb86d974cf0c9c93b2a3e]: gen-groups
#+begin_example : (grename "[SYS]")
(grename "term") : (gnewbg "[DEV]")
(gnewbg "emacs") : (gnewbg "[WWW]")
(gnewbg "www") : (gnewbg "[FILES]")
(gnewbg "files") : (gnewbg "[MEDIA]")
(gnewbg "media") : (gnewbg "[SOC]")
(gnewbg "graphics") : (gnewbg "[PRIV]")
(gnewbg "VMs")
(gnewbg "games")
(gnewbg "private")
(gnewbg "discord")
#+end_example
Groups are specified this way: Groups are specified this way:
#+begin_src lisp #+begin_src lisp
@@ -430,51 +476,46 @@ this will avoid unexpected and hard-to-debug behavior.
(clear-window-placement-rules) (clear-window-placement-rules)
#+end_src #+end_src
Now we can define our window placement preferences. For now, all rely As you can see in the table [[list-groups]] above, I also indicated my
on the window’s class, so it will be pretty straightforward to write. window placement preferences. For now, they all rely on the window’s
#+name: frame-preferences class, so it will be pretty straightforward to the corresponding code.
| Window Class | Group |
|--------------+---------|
| Emacs | emacs |
| Firefox | browser |
| Nemo | files |
| Gimp | media |
| Signal | private |
| lightcord | discord |
| Steam | games |
| Virt-manager | VMs |
#+name: gen-rules #+name: gen-rules
#+headers: :tangle no :exports results :cache yes :wrap src lisp #+headers: :tangle no :exports results :cache yes :wrap src lisp
#+begin_src emacs-lisp :var rules=frame-preferences #+begin_src emacs-lisp :var rules=list-groups
(mapconcat (lambda (rule) (require 'seq)
(let ((class (car rule)) (let ((output "")
(group (cadr rule))) (rules (seq-filter (lambda (rule) rule)
(format "(define-frame-preference \"%s\" (mapcar (lambda (line)
(nil t t :class \"%s\"))" group class))) (let ((classes (caddr line)))
rules (unless (string= "" classes)
"\n") (cons
(split-string classes "," t "[[:space:]]*")
(car line)))))
rules))))
(progn
(seq-do (lambda (rule)
(let ((classes (car rule))
(group (cdr rule)))
(dolist (class classes)
(setf output (format "%s\n%s"
`(define-frame-preference ,(format "\"%s\"" group)
(nil t t :class ,(format "\"%s\"" class)))
output)))))
rules)
output))
#+end_src #+end_src
This can be written this way: This can be written this way:
#+RESULTS[b493d3cb9cae1fc97cdb4eb5dc56c9440fde0b2b]: gen-rules #+RESULTS[1c9490c15e3cc7d2c8ed1c508cab844567232afc]: gen-rules
#+begin_src lisp #+begin_src lisp
(define-frame-preference "emacs" (define-frame-preference "[SOC]" (nil t t :class "lightcord"))
(nil t t :class "Emacs")) (define-frame-preference "[SOC]" (nil t t :class "discord"))
(define-frame-preference "browser" (define-frame-preference "[SOC]" (nil t t :class "Signal"))
(nil t t :class "Firefox")) (define-frame-preference "[MEDIA]" (nil t t :class "Gimp"))
(define-frame-preference "files" (define-frame-preference "[FILES]" (nil t t :class "Nemo"))
(nil t t :class "Nemo")) (define-frame-preference "[WWW]" (nil t t :class "Firefox"))
(define-frame-preference "media" (define-frame-preference "[DEV]" (nil t t :class "Virt-manager"))
(nil t t :class "Gimp")) (define-frame-preference "[DEV]" (nil t t :class "Emacs"))
(define-frame-preference "private"
(nil t t :class "Signal"))
(define-frame-preference "discord"
(nil t t :class "lightcord"))
(define-frame-preference "games"
(nil t t :class "Steam"))
(define-frame-preference "VMs"
(nil t t :class "Virt-manager"))
#+end_src #+end_src
* Theme * Theme
@@ -511,24 +552,29 @@ again src_lisp[:exports code]{(ql:quickload :clx-truetype)} without an
issue (running it again is necessary to install its dependencies). issue (running it again is necessary to install its dependencies).
Now that this is out of the way, let’s add two lines so we can use TTF Now that this is out of the way, let’s add two lines so we can use TTF
and OTF fonts: fonts:
#+begin_src lisp #+begin_src lisp
(ql:quickload :clx-truetype) (ql:quickload :clx-truetype)
(load-module "ttf-fonts") (load-module "ttf-fonts")
#+end_src #+end_src
The documentation says we should be able to also use OTF fonts, but so
far I’ve had no luck loading one. Loading more than one font to use
some fallback fonts also doesn’t seem to work, unlike specified in the
documentation (I wanted to use a CJK font, but it doesn’t appear to
work).
Something that didn’t click immediately for me (and I think StumpWM’s # Something that didn’t click immediately for me (and I think StumpWM’s
documentation on this could be improved) is that ~set-font~ can be used # documentation on this could be improved) is that ~set-font~ can be used
to set either one main font for StumpWM, as one might guess reading # to set either one main font for StumpWM, as one might guess reading
the documentation --- or you can set a list of them! And this is # the documentation --- or you can set a list of them! And this is
great, since my main font does not support some characters I regularly # great, since my main font does not support some characters I regularly
have in my windows’ title, such as CJK characters, emojis and all! # have in my windows’ title, such as CJK characters, emojis and all!
Here is my list of fonts I want loaded: # Here is my list of fonts I want loaded:
#+name: list-fonts #+name: list-fonts
| Family | Subfamily | Size | | Family | Subfamily | Size |
|-------------+-----------+------| |------------------+-----------+------|
| DejaVu Sans | Book | 9 | | DejaVu Sans Mono | Book | 8 |
| IPAMincho | Regular | 11 | # | IPAMincho | Regular | 11 |
#+name: gen-fonts #+name: gen-fonts
#+headers: :tangle no :exports results :cache yes :wrap src lisp #+headers: :tangle no :exports results :cache yes :wrap src lisp
@@ -548,10 +594,9 @@ Here is my list of fonts I want loaded:
#+end_src #+end_src
The code equivalent of this table can be seen below: The code equivalent of this table can be seen below:
#+RESULTS[054585246a49cd88836d4c5ea1aad66c1bc97f8a]: gen-fonts #+RESULTS[ca1ca106ad10eea84a34362acfc543eba559260c]: gen-fonts
#+begin_src lisp #+begin_src lisp
(set-font `(,(make-instance 'xft:font :family "DejaVu Sans" :subfamily "Book" :size 11 :antialias t) (set-font `(,(make-instance 'xft:font :family "DejaVu Sans Mono" :subfamily "Book" :size 8 :antialias t)))
,(make-instance 'xft:font :family "IPAMincho" :subfamily "Regular" :size 11 :antialias t)))
#+end_src #+end_src
*** TODO Font error in modeline with Japanese :noexport: *** TODO Font error in modeline with Japanese :noexport:
@@ -691,26 +736,143 @@ Also, let’s enable ~which-key~:
(which-key-mode) (which-key-mode)
#+end_src #+end_src
#+name: keybinds-gen Lastly, before we get more into details, keep in mind that I use the
#+headers: :tangle no :exports none :cache yes :noweb yes [[https://bepo.fr][bépo]] layout, as I often say in my different documents. This means the
#+begin_src emacs-lisp :var map="m" keybinds=frames-float characters found in the numbers’ row when pressing shift are actually
(mapconcat (lambda (keybind) the numbers themselves. Below are the following characters:
(format "%s" (let ((key (string-replace "~" "" (car keybind))) #+name: number-to-char-table
(function (string-replace "~" "" (cadr keybind)))) | Number | Character |
`(define-key ,map |--------+-----------|
(kbd ,(format "\"%s\"" key)) | 1 | ~"~ |
,(if (string-prefix-p "'" function t) | 2 | ~«~ |
function | 3 | ~»~ |
(format "\"%s\"" function)))))) | 4 | ~(~ |
keybinds | 5 | ~)~ |
"\n") | 6 | ~@~ |
| 7 | ~+~ |
| 8 | ~-~ |
| 9 | ~/~ |
| 0 | ~*~ |
So if you see any weird keybind involving these characters, this is
because of my layout.
** Applications
:PROPERTIES:
:CUSTOM_ID: Keybinds-Applications-2t512k00w5j0
:END:
When I speak about applications, I speak about programs and scripts in
general. With these keymaps, I can launch programs I often have use
for, but I can also launch some scripts as well as take screenshots.
First, let’s create my ~rofi~ scripts keymap.
#+name: rofi-scripts
#+caption: ~*my-rofi-keymap*~
| Keychord | Function |
|----------+-----------------------------------------------|
| ~a~ | ~exec awiki~ |
| ~r~ | ~exec rofi -combi-modi drun,window -show combi~ |
| ~s~ | ~exec rofi -show ssh~ |
| ~p~ | ~exec rofi-pass -t~ |
| ~P~ | ~exec rofi-pass~ |
| ~e~ | ~exec rofi-emoji~ |
| ~m~ | ~exec rofi-mount~ |
| ~u~ | ~exec rofi-umount~ |
| ~w~ | ~exec wacom-setup~ |
| ~y~ | ~exec ytplay~ |
| ~Y~ | ~exec rofi-ytdl~ |
Here’s the equivalent in Common Lisp.
#+begin_src lisp
(defvar *my-rofi-keymap*
(let ((m (make-sparse-keymap)))
<<keybinds-gen(map="m", keybinds=rofi-scripts)>>
m))
#+end_src #+end_src
#+RESULTS[5938b2a6efd9c8b565416f9a687bc0d6a4a5f77e]: keybinds-gen Let’s also create a keymap for screenshots.
: (define-key m (kbd "f") "float-this") #+name: screenshot-keymap
: (define-key m (kbd "F") "unfloat-this") #+caption: ~*my-screenshot-keymap*~
: (define-key m (kbd "u") "unfloat-this") | Keychord | Function |
: (define-key m (kbd "C-f") "flatten-floats") |----------+------------------------------------------------------|
| ~d~ | ~exec scrot -d 3 -e 'mv $f ~/Pictures/Screenshots'~ |
| ~s~ | ~exec scrot -e 'mv $f ~/Pictures/Screenshots'~ |
| ~S~ | ~exec scrot -s -e 'mv $f ~/Pictures/Screenshots'~ |
| ~g~ | ~exec scrot -e 'gimp $f; mv $f ~/Pictures/Screenshots'~ |
Here’s the equivalent in Common Lisp.
#+begin_src lisp
(defvar *my-screenshot-keymap*
(let ((m (make-sparse-keymap)))
<<keybinds-gen(map="m", keybinds=screenshot-keymap)>>
m))
#+end_src
We can now define our applications keymap which will reference both
the above keymaps.
#+name: application-keymap
#+caption: ~*my-applications-keymap*~
| Keychord | Function |
|----------+-------------------------|
| ~b~ | ~firefox~ |
| ~d~ | ~exec lightcord~ |
| ~e~ | ~exec emacsclient -c~ |
| ~g~ | ~exec gimp~ |
| ~n~ | ~exec nemo~ |
| ~r~ | ~'*my-rofi-keymap*~ |
| ~s~ | ~'*my-screenshot-keymap*~ |
This translates to:
#+begin_src lisp
(defvar *my-applications-keymap*
(let ((m (make-sparse-keymap)))
<<keybinds-gen(map="m", keybinds=application-keymap)>>
m))
#+end_src
The application keymap can now be bound to the top map like so:
#+begin_src lisp
(define-key *top-map* (kbd "s-a") '*my-applications-keymap*)
#+end_src
I will also bind to the top map ~s-RET~ in order to open a new terminal
window. The screenshot keymap is also bound to the ScreenPrint key.
#+begin_src lisp
(define-key *top-map* (kbd "s-RET") "exec kitty")
(define-key *top-map* (kbd "Print") '*my-screenshot-keymap*)
#+end_src
** End of Session, Powering Off, and the Likes
:PROPERTIES:
:CUSTOM_ID: Keybinds-End-of-Session-Powering-Off-and-the-Likes-mgz02z40w5j0
:END:
The module ~end-session~ provides functions for gracefully ending the
user session, powering off, restarting, and suspending the computer.
It also provides a function that interactively asks what the user
whishes to do.
#+name: end-session-keymap
| Keychord | Function |
|----------+-------------------|
| ~q~ | ~end-session~ |
| ~l~ | ~logout~ |
| ~s~ | ~suspend-computer~ |
| ~S~ | ~shutdown-computer~ |
| ~r~ | ~loadrc~ |
| ~R~ | ~restart-hard~ |
| ~C-r~ | ~restart-computer~ |
This translates to:
#+begin_src lisp
(defvar *my-end-session-keymap*
(let ((m (make-sparse-keymap)))
<<keybinds-gen(map="m", keybinds=end-session-keymap)>>
m))
#+end_src
Which is bound in the root map to ~q~:
#+begin_src lisp
(define-key *root-map* (kbd "q") '*my-end-session-keymap*)
#+end_src
** Frames and Windows management ** Frames and Windows management
:PROPERTIES: :PROPERTIES:
@@ -748,10 +910,8 @@ We can now pass onto ~*my-frames-management-keymap*~. My keybinds are organized
| ~C-t~ | ~exchange-direction down~ | | ~C-t~ | ~exchange-direction down~ |
| ~C-s~ | ~exchange-direction up~ | | ~C-s~ | ~exchange-direction up~ |
| ~C-r~ | ~exchange-direction right~ | | ~C-r~ | ~exchange-direction right~ |
| ~n~ | ~next~ | | ~/~ | ~hsplit-and-focus~ |
| ~p~ | ~prev~ | | ~-~ | ~vsplit-and-focus~ |
| ~/~ | ~hsplit~ |
| ~-~ | ~vsplit~ |
| ~h~ | ~hsplit~ | | ~h~ | ~hsplit~ |
| ~v~ | ~vsplit~ | | ~v~ | ~vsplit~ |
| ~H~ | ~hsplit-equally~ | | ~H~ | ~hsplit-equally~ |
@@ -765,9 +925,6 @@ We can now pass onto ~*my-frames-management-keymap*~. My keybinds are organized
| ~i~ | ~info~ | | ~i~ | ~info~ |
| ~I~ | ~show-window-properties~ | | ~I~ | ~show-window-properties~ |
| ~m~ | ~meta~ | | ~m~ | ~meta~ |
| ~o~ | ~other-window~ |
| ~q~ | ~delete-window~ |
| ~Q~ | ~kill-window~ |
| ~s~ | ~sibling~ | | ~s~ | ~sibling~ |
| ~u~ | ~next-urgent~ | | ~u~ | ~next-urgent~ |
| ~U~ | ~unmaximize~ | | ~U~ | ~unmaximize~ |
@@ -833,119 +990,113 @@ redefine it:
((kbd "r") "resize-direction right")) ((kbd "r") "resize-direction right"))
#+end_src #+end_src
** Applications ** Windows management
:PROPERTIES: :PROPERTIES:
:CUSTOM_ID: Keybinds-Applications-2t512k00w5j0 :CUSTOM_ID: Keybinds-Windows-management-ylf903j0x5j0
:END: :END:
When I speak about applications, I speak about programs and scripts in When it comes to windows management, I will treat them a bit like I do
general. With these keymaps, I can launch programs I often have use with Emacs’ buffers.
for, but I can also launch some scripts as well as take screenshots.
First, let’s create my ~rofi~ scripts keymap. #+name: window-management
#+name: rofi-scripts #+caption: ~*my-buffers-management-keymap*~
#+caption: ~*my-rofi-keymap*~
| Keychord | Function |
|----------+-----------------------------------------------|
| ~a~ | ~exec awiki~ |
| ~r~ | ~exec rofi -combi-modi drun,window -show combi~ |
| ~s~ | ~exec rofi -show ssh~ |
| ~p~ | ~exec rofi-pass -t~ |
| ~P~ | ~exec rofi-pass~ |
| ~e~ | ~exec rofi-emoji~ |
| ~m~ | ~exec rofi-mount~ |
| ~u~ | ~exec rofi-umount~ |
| ~w~ | ~exec wacom-setup~ |
| ~y~ | ~exec ytplay~ |
| ~Y~ | ~exec rofi-ytdl~ |
Here’s the equivalent in Common Lisp.
#+begin_src lisp
(defvar *my-rofi-keymap*
(let ((m (make-sparse-keymap)))
<<keybinds-gen(map="m", keybinds=rofi-scripts)>>
m))
#+end_src
Let’s also create a keymap for screenshots.
#+name: screenshot-keymap
#+caption: ~*my-screenshot-keymap*~
| Keychord | Function |
|----------+------------------------------------------------------|
| ~d~ | ~exec scrot -d 3 -e 'mv $f ~/Pictures/Screenshots'~ |
| ~s~ | ~exec scrot -e 'mv $f ~/Pictures/Screenshots'~ |
| ~S~ | ~exec scrot -s -e 'mv $f ~/Pictures/Screenshots'~ |
| ~g~ | ~exec scrot -e 'gimp $f; mv $f ~/Pictures/Screenshots'~ |
Here’s the equivalent in Common Lisp.
#+begin_src lisp
(defvar *my-screenshot-keymap*
(let ((m (make-sparse-keymap)))
<<keybinds-gen(map="m", keybinds=screenshot-keymap)>>
m))
#+end_src
We can now define our applications keymap which will reference both
the above keymaps.
#+name: application-keymap
#+caption: ~*my-applications-keymap*~
| Keychord | Function | | Keychord | Function |
|----------+-------------------------| |----------+-------------------------|
| ~b~ | ~firefox~ | | ~b~ | ~windowlist~ |
| ~d~ | ~exec lightcord~ | | ~d~ | ~delete-window~ |
| ~e~ | ~emacs~ | | ~D~ | ~window-window-and-frame~ |
| ~g~ | ~exec gimp~ | | ~k~ | ~kill-window~ |
| ~n~ | ~exec nemo~ | | ~n~ | ~next~ |
| ~r~ | ~'*my-rofi-keymap*~ | | ~o~ | ~other-window~ |
| ~s~ | ~'*my-screenshot-keymap*~ | | ~p~ | ~prev~ |
This translates to:
#+begin_src lisp #+begin_src lisp
(defvar *my-applications-keymap* (defvar *my-buffers-management-keymap*
(let ((m (make-sparse-keymap))) (let ((m (make-sparse-keymap)))
<<keybinds-gen(map="m", keybinds=application-keymap)>> <<keybinds-gen(map="m", keybinds=window-management)>>
m)) m))
(define-key *root-map* (kbd "b") '*my-buffers-management-keymap*)
#+end_src #+end_src
The application keymap can now be bound to the top map like so: ** Media and Media Control
#+begin_src lisp
(define-key *top-map* (kbd "s-a") '*my-applications-keymap*)
#+end_src
I will also bind to the top map ~s-RET~ in order to open a new terminal
window. The screenshot keymap is also bound to the ScreenPrint key.
#+begin_src lisp
(define-key *top-map* (kbd "s-RET") "exec kitty")
(define-key *top-map* (kbd "Print") '*my-screenshot-keymap*)
#+end_src
** End of Session, Powering Off, and the Likes
:PROPERTIES: :PROPERTIES:
:CUSTOM_ID: Keybinds-End-of-Session-Powering-Off-and-the-Likes-mgz02z40w5j0 :CUSTOM_ID: Keybinds-Media-and-Media-Control-hbv5uk91z5j0
:END: :END:
The module ~end-session~ provides functions for gracefully ending the My music is managed through MPD, and I often use ~mpc~ commands in order
user session, powering off, restarting, and suspending the computer. to interact with it without any GUI application. So, we’ll see a lot
It also provides a function that interactively asks what the user of its usage here.
whishes to do.
#+name: end-session-keymap First, let’s declare an interactive keymap in order to easily change
several times in a row either the current song playing or the volume
of MPD.
#+name: inter-mpc
#+caption: Interactive keybinds for ~mpc~
| Keychord | Function |
|----------+--------------------|
| ~c~ | ~exec mpc prev~ |
| ~t~ | ~exec mpc volume -2~ |
| ~s~ | ~exec mpc volume +2~ |
| ~r~ | ~exec mpc next~ |
Cela donne le code suivant:
#+begin_src lisp
<<interactive-gen(name="mpc-interactive", keys=inter-mpc)>>
#+end_src
Another one will be defined for the general audio of my computer. And
I know it isn’t technically media keybinds, but I’ll add in keybinds
for my screen’s backlight.
#+name: inter-media
#+caption: Interactive keybinds for general media interaction
| Keys | Function |
|------+--------------------------------------|
| ~c~ | ~exec xbacklight -dec 2~ |
| ~t~ | ~exec amixer -q set Master 2%- unmute~ |
| ~s~ | ~exec amixer -q set Master 2%+ unmute~ |
| ~r~ | ~exec xbacklight -inc 2~ |
| ~m~ | ~exec amixer -q set Master 1+ toggle~ |
#+begin_src lisp
<<interactive-gen(name="media-interactive", keys=inter-media)>>
#+end_src
Then, let’s declare a keymap for our media controls.
#+name: media-management
#+caption: ~*my-media-keymap*~
| Keychord | Function | | Keychord | Function |
|----------+-------------------| |----------+-------------------|
| ~q~ | ~end-session~ | | ~.~ | ~media-interactive~ |
| ~l~ | ~logout~ | | ~m~ | ~mpc-interactive~ |
| ~s~ | ~suspend-computer~ | | ~p~ | ~exec mpc prev~ |
| ~S~ | ~shutdown-computer~ | | ~n~ | ~exec mpc next~ |
| ~r~ | ~restart-computer~ | | ~t~ | ~exec mpc toggle~ |
| ~s~ | ~exec mpc stop~ |
This translates to: Let’s translate this table in CommonLisp:
#+begin_src lisp #+begin_src lisp
(defvar *my-end-session-keymap* (defvar *my-buffers-management-keymap*
(let ((m (make-sparse-keymap))) (let ((m (make-sparse-keymap)))
<<keybinds-gen(map="m", keybinds=end-session-keymap)>> <<keybinds-gen(map="m", keybinds=media-management)>>
m)) m))
(define-key *root-map* (kbd "m") '*my-media-keymap*)
#+end_src #+end_src
Which is bound in the root map to ~q~: I will also define on ~*top-map*~ some basic volume management keybinds
so that they are immediately accessible. Again, this isn’t technically
media-related, but I’ll add keybinds for my screen’s backlight.
#+name: media-top-level
#+caption: Top-level media keys
| Keychord | Function |
|-----------------------+--------------------------------------|
| ~XF86AudioRaiseVolume~ | ~exec amixer -q set Master 2%+ unmute~ |
| ~XF86AudioLowerVolume~ | ~exec amixer -q set Master 2%- unmute~ |
| ~XF86AudioMute~ | ~exec amixer -q set Master 1+ toggle~ |
| ~XF86MonBrightnessDown~ | ~exec xbacklight -dec 2~ |
| ~XF86MonBrightnessUp~ | ~exec xbacklight -inc 2~ |
#+begin_src lisp #+begin_src lisp
(define-key *root-map* (kbd "q") '*my-end-session-keymap*) <<keybinds-gen(map="*top-map*", keybinds=media-top-level)>>
#+end_src #+end_src
** Misc ** Misc
@@ -964,3 +1115,57 @@ anywhere else:
#+begin_src lisp #+begin_src lisp
<<keybinds-gen(map="*root-map*", keybinds=misc-root-map)>> <<keybinds-gen(map="*root-map*", keybinds=misc-root-map)>>
#+end_src #+end_src
* org functions :noexport:
:PROPERTIES:
:CUSTOM_ID: org-functions-syqgzgg0m6j0
:END:
#+name: keybinds-gen
#+headers: :tangle no :exports none :cache yes :noweb yes
#+begin_src emacs-lisp :var map="m" keybinds=frames-float
(mapconcat (lambda (keybind)
(format "%s" (let ((key (let ((s (car keybind)))
(substring-no-properties s 1 (1- (length s)))))
(function (let ((s (cadr keybind)))
(substring-no-properties s 1 (1- (length s))))))
`(define-key ,map
(kbd ,(format "\"%s\"" key))
,(if (string-prefix-p "'" function t)
function
(format "\"%s\"" function))))))
keybinds
"\n")
#+end_src
#+name: interactive-gen
#+headers: :tangle no :exports none :noweb yes
#+begin_src emacs-lisp :var name="inter" keys=inter-mpc
(format "%s"
`(define-interactive-keymap ,name ()
"\n "
,(mapconcat (lambda (keybind)
(format "%s"
(let ((key (let ((s (car keybind)))
(substring-no-properties s
1
(1- (length s)))))
(command (let ((s (cadr keybind)))
(substring-no-properties s
1
(1- (length s))))))
`((kbd ,(format "\"%s\"" key)) ,(format "\"%s\"" command)))))
keys
"\n ")))
#+end_src
#+name: num-to-char
#+headers: :tangle no :exports none :noweb yes
#+begin_src emacs-lisp :var table=number-to-char-table num=0
(replace-regexp-in-string (regexp-quote "~")
""
(cadr (assoc num table)))
#+end_src
#+RESULTS: num-to-char
: *