From 22bbd61ed194e3f883af3025e417c2444c401f1e Mon Sep 17 00:00:00 2001 From: Lucien Cartier-Tilet Date: Wed, 1 Sep 2021 21:22:16 +0200 Subject: [PATCH] [StumpWM] Reorganize some code, better keybinds and modeline MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- org/config/stumpwm.org | 661 +++++++++++++++++++++++++++-------------- 1 file changed, 433 insertions(+), 228 deletions(-) diff --git a/org/config/stumpwm.org b/org/config/stumpwm.org index 063b8d2..adfa986 100644 --- a/org/config/stumpwm.org +++ b/org/config/stumpwm.org @@ -3,7 +3,8 @@ #+OPTIONS: auto-id:t #+HTML_HEAD_EXTRA: #+HTML_HEAD_EXTRA: -#+HTML_HEAD_EXTRA: +#+HTML_HEAD_EXTRA: +#+property: header-args:emacs-lisp :tangle no :exports results :cache yes :noweb yes * Introduction :PROPERTIES: @@ -140,7 +141,7 @@ Now, we’ll load a couple of my custom files that will be described below: | modeline.lisp | #+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 (mapconcat (lambda (file) (format "(load \"~/.stumpwm.d/%s\")" (car file))) @@ -175,23 +176,20 @@ windows. #+end_src Next, some modules will be loaded from the ~stumpwm-contrib~ package -(which is included in ~stumpwm-git~). Here is a short list including a -short description of what they are for: +(which is included in ~stumpwm-git~ in the AUR). Here is a short list +including a short description of what they are for: #+name: loaded-modules -| Module Name | Why It Is Loaded | -|------------------+------------------------------------------------------------| -| 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 | -| cpu | Get the CPU usage of the computer | -| end-session | Gracefully end programs when ending user session | -| globalwindows | Navigate between windows from all workspaces | -| mem | Get the memory usage of the computer | -| stump-backlight | Native management of backlight in StumpWM | -| urgentwindows | Get urgent windows | +| Module Name | Why It Is Loaded | +|-----------------+------------------------------------------------------------| +| alert-me | Creates notifications, can also create timed notifications | +| beckon | Bring the mouse cursor to the current window | +| end-session | Gracefully end programs when ending user session | +| globalwindows | Navigate between windows from all workspaces | +| stump-backlight | Native management of backlight in StumpWM | +| urgentwindows | Get urgent windows | #+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 (mapconcat (lambda (module) (format "(load-module \"%s\")" (car module))) @@ -199,15 +197,12 @@ short description of what they are for: "\n") #+end_src -#+RESULTS[1978f17a99db4ca68780c378e5e5d9d58f9e08bc]: gen-load-modules +#+RESULTS[508e36f9747f1da901bbee63582416a8a6ba2c2f]: gen-load-modules #+begin_src lisp (load-module "alert-me") -(load-module "battery-portable") (load-module "beckon") -(load-module "cpu") (load-module "end-session") (load-module "globalwindows") -(load-module "mem") (load-module "stump-backlight") (load-module "urgentwindows") #+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 :header-args:lisp: :mkdirp :tangle ~/.stumpwm.d/commands.lisp :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 -it if it already exists, and for Emacs to invoke the Emacs client or a -new Emacs instance if the server isn’t running. This is done like so: + +The first command I declare in this file is a command that will avoid +me invoking too many Firefox instances. Either Firefox is not already +running and an instance is launched, or one already is and we are +brought to it. This is done like so: #+begin_src lisp (defcommand firefox () () "Run or raise Firefox." (run-or-raise "firefox" '(:class "Firefox") t nil)) #+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 :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 code looks like so: #+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 (mapconcat (lambda (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. #+begin_src lisp - (setf *group-format* " %t ") + (setf *group-format* "%t") #+end_src 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") #+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 ~^>~ 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 @@ -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 ~%B~ will display the battery level of the laptop. #+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 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 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. # #+begin_src lisp # (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 is the list of groups I will be using: #+name: list-groups -| Groups | -|----------| -| term | -| emacs | -| www | -| files | -| media | -| graphics | -| VMs | -| games | -| private | -| discord | +| Groups | Number | Windows | +|---------+--------+----------------------------| +| [SYS] | 1 | | +| [DEV] | 2 | Emacs, Virt-manager | +| [WWW] | 3 | Firefox | +| [FILES] | 4 | Nemo | +| [MEDIA] | 5 | Gimp | +| [SOC] | 6 | Signal, discord, lightcord | +| [PRIV] | 7 | | #+name: gen-groups #+headers: :tangle no :exports none :cache yes #+begin_src emacs-lisp :var groups=list-groups - (string-join `(,(format "(grename \"%s\")" (car (car groups))) - ,@(mapcar (lambda (group) - (format "(gnewbg \"%s\")" (car group))) - (cdr groups))) - "\n") + (string-trim (string-join `(,(format "(grename \"%s\")" (car (car groups))) + ,@(mapcar (lambda (group) + (format "(gnewbg \"%s\")" (car group))) + (cdr groups))) + "\n") + "[[:space:]]*" + "[[:space:]]*") #+end_src -#+RESULTS[ed2b45d9a542233061373da32e830bd27a68d61b]: gen-groups -#+begin_example -(grename "term") -(gnewbg "emacs") -(gnewbg "www") -(gnewbg "files") -(gnewbg "media") -(gnewbg "graphics") -(gnewbg "VMs") -(gnewbg "games") -(gnewbg "private") -(gnewbg "discord") -#+end_example +#+RESULTS[caa45af7c6ee092f88acb86d974cf0c9c93b2a3e]: gen-groups +: (grename "[SYS]") +: (gnewbg "[DEV]") +: (gnewbg "[WWW]") +: (gnewbg "[FILES]") +: (gnewbg "[MEDIA]") +: (gnewbg "[SOC]") +: (gnewbg "[PRIV]") Groups are specified this way: #+begin_src lisp @@ -430,51 +476,46 @@ this will avoid unexpected and hard-to-debug behavior. (clear-window-placement-rules) #+end_src -Now we can define our window placement preferences. For now, all rely -on the window’s class, so it will be pretty straightforward to write. -#+name: frame-preferences -| Window Class | Group | -|--------------+---------| -| Emacs | emacs | -| Firefox | browser | -| Nemo | files | -| Gimp | media | -| Signal | private | -| lightcord | discord | -| Steam | games | -| Virt-manager | VMs | - +As you can see in the table [[list-groups]] above, I also indicated my +window placement preferences. For now, they all rely on the window’s +class, so it will be pretty straightforward to the corresponding code. #+name: gen-rules #+headers: :tangle no :exports results :cache yes :wrap src lisp -#+begin_src emacs-lisp :var rules=frame-preferences - (mapconcat (lambda (rule) - (let ((class (car rule)) - (group (cadr rule))) - (format "(define-frame-preference \"%s\" - (nil t t :class \"%s\"))" group class))) - rules - "\n") +#+begin_src emacs-lisp :var rules=list-groups + (require 'seq) + (let ((output "") + (rules (seq-filter (lambda (rule) rule) + (mapcar (lambda (line) + (let ((classes (caddr line))) + (unless (string= "" classes) + (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 This can be written this way: -#+RESULTS[b493d3cb9cae1fc97cdb4eb5dc56c9440fde0b2b]: gen-rules +#+RESULTS[1c9490c15e3cc7d2c8ed1c508cab844567232afc]: gen-rules #+begin_src lisp -(define-frame-preference "emacs" - (nil t t :class "Emacs")) -(define-frame-preference "browser" - (nil t t :class "Firefox")) -(define-frame-preference "files" - (nil t t :class "Nemo")) -(define-frame-preference "media" - (nil t t :class "Gimp")) -(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")) +(define-frame-preference "[SOC]" (nil t t :class "lightcord")) +(define-frame-preference "[SOC]" (nil t t :class "discord")) +(define-frame-preference "[SOC]" (nil t t :class "Signal")) +(define-frame-preference "[MEDIA]" (nil t t :class "Gimp")) +(define-frame-preference "[FILES]" (nil t t :class "Nemo")) +(define-frame-preference "[WWW]" (nil t t :class "Firefox")) +(define-frame-preference "[DEV]" (nil t t :class "Virt-manager")) +(define-frame-preference "[DEV]" (nil t t :class "Emacs")) #+end_src * 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). 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 (ql:quickload :clx-truetype) (load-module "ttf-fonts") #+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 -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 -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 -have in my windows’ title, such as CJK characters, emojis and all! -Here is my list of fonts I want loaded: +# 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 +# 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 +# great, since my main font does not support some characters I regularly +# have in my windows’ title, such as CJK characters, emojis and all! +# Here is my list of fonts I want loaded: #+name: list-fonts -| Family | Subfamily | Size | -|-------------+-----------+------| -| DejaVu Sans | Book | 9 | -| IPAMincho | Regular | 11 | +| Family | Subfamily | Size | +|------------------+-----------+------| +| DejaVu Sans Mono | Book | 8 | +# | IPAMincho | Regular | 11 | #+name: gen-fonts #+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 The code equivalent of this table can be seen below: -#+RESULTS[054585246a49cd88836d4c5ea1aad66c1bc97f8a]: gen-fonts +#+RESULTS[ca1ca106ad10eea84a34362acfc543eba559260c]: gen-fonts #+begin_src lisp -(set-font `(,(make-instance 'xft:font :family "DejaVu Sans" :subfamily "Book" :size 11 :antialias t) - ,(make-instance 'xft:font :family "IPAMincho" :subfamily "Regular" :size 11 :antialias t))) +(set-font `(,(make-instance 'xft:font :family "DejaVu Sans Mono" :subfamily "Book" :size 8 :antialias t))) #+end_src *** TODO Font error in modeline with Japanese :noexport: @@ -691,26 +736,143 @@ Also, let’s enable ~which-key~: (which-key-mode) #+end_src -#+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 (string-replace "~" "" (car keybind))) - (function (string-replace "~" "" (cadr keybind)))) - `(define-key ,map - (kbd ,(format "\"%s\"" key)) - ,(if (string-prefix-p "'" function t) - function - (format "\"%s\"" function)))))) - keybinds - "\n") +Lastly, before we get more into details, keep in mind that I use the +[[https://bepo.fr][bépo]] layout, as I often say in my different documents. This means the +characters found in the numbers’ row when pressing shift are actually +the numbers themselves. Below are the following characters: +#+name: number-to-char-table +| Number | Character | +|--------+-----------| +| 1 | ~"~ | +| 2 | ~«~ | +| 3 | ~»~ | +| 4 | ~(~ | +| 5 | ~)~ | +| 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))) + <> + m)) #+end_src -#+RESULTS[5938b2a6efd9c8b565416f9a687bc0d6a4a5f77e]: keybinds-gen -: (define-key m (kbd "f") "float-this") -: (define-key m (kbd "F") "unfloat-this") -: (define-key m (kbd "u") "unfloat-this") -: (define-key m (kbd "C-f") "flatten-floats") +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))) + <> + 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))) + <> + 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))) + <> + 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 :PROPERTIES: @@ -748,10 +910,8 @@ We can now pass onto ~*my-frames-management-keymap*~. My keybinds are organized | ~C-t~ | ~exchange-direction down~ | | ~C-s~ | ~exchange-direction up~ | | ~C-r~ | ~exchange-direction right~ | -| ~n~ | ~next~ | -| ~p~ | ~prev~ | -| ~/~ | ~hsplit~ | -| ~-~ | ~vsplit~ | +| ~/~ | ~hsplit-and-focus~ | +| ~-~ | ~vsplit-and-focus~ | | ~h~ | ~hsplit~ | | ~v~ | ~vsplit~ | | ~H~ | ~hsplit-equally~ | @@ -765,9 +925,6 @@ We can now pass onto ~*my-frames-management-keymap*~. My keybinds are organized | ~i~ | ~info~ | | ~I~ | ~show-window-properties~ | | ~m~ | ~meta~ | -| ~o~ | ~other-window~ | -| ~q~ | ~delete-window~ | -| ~Q~ | ~kill-window~ | | ~s~ | ~sibling~ | | ~u~ | ~next-urgent~ | | ~U~ | ~unmaximize~ | @@ -833,119 +990,113 @@ redefine it: ((kbd "r") "resize-direction right")) #+end_src -** Applications +** Windows management :PROPERTIES: -:CUSTOM_ID: Keybinds-Applications-2t512k00w5j0 +:CUSTOM_ID: Keybinds-Windows-management-ylf903j0x5j0 :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. +When it comes to windows management, I will treat them a bit like I do +with Emacs’ buffers. -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))) - <> - 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))) - <> - m)) -#+end_src - -We can now define our applications keymap which will reference both -the above keymaps. -#+name: application-keymap -#+caption: ~*my-applications-keymap*~ +#+name: window-management +#+caption: ~*my-buffers-management-keymap*~ | Keychord | Function | |----------+-------------------------| -| ~b~ | ~firefox~ | -| ~d~ | ~exec lightcord~ | -| ~e~ | ~emacs~ | -| ~g~ | ~exec gimp~ | -| ~n~ | ~exec nemo~ | -| ~r~ | ~'*my-rofi-keymap*~ | -| ~s~ | ~'*my-screenshot-keymap*~ | +| ~b~ | ~windowlist~ | +| ~d~ | ~delete-window~ | +| ~D~ | ~window-window-and-frame~ | +| ~k~ | ~kill-window~ | +| ~n~ | ~next~ | +| ~o~ | ~other-window~ | +| ~p~ | ~prev~ | -This translates to: #+begin_src lisp - (defvar *my-applications-keymap* + (defvar *my-buffers-management-keymap* (let ((m (make-sparse-keymap))) - <> + <> m)) + + (define-key *root-map* (kbd "b") '*my-buffers-management-keymap*) #+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 +** Media and Media Control :PROPERTIES: -:CUSTOM_ID: Keybinds-End-of-Session-Powering-Off-and-the-Likes-mgz02z40w5j0 +:CUSTOM_ID: Keybinds-Media-and-Media-Control-hbv5uk91z5j0 :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 +My music is managed through MPD, and I often use ~mpc~ commands in order +to interact with it without any GUI application. So, we’ll see a lot +of its usage here. + +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 + <> +#+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 + <> +#+end_src + +Then, let’s declare a keymap for our media controls. +#+name: media-management +#+caption: ~*my-media-keymap*~ | Keychord | Function | |----------+-------------------| -| ~q~ | ~end-session~ | -| ~l~ | ~logout~ | -| ~s~ | ~suspend-computer~ | -| ~S~ | ~shutdown-computer~ | -| ~r~ | ~restart-computer~ | +| ~.~ | ~media-interactive~ | +| ~m~ | ~mpc-interactive~ | +| ~p~ | ~exec mpc prev~ | +| ~n~ | ~exec mpc next~ | +| ~t~ | ~exec mpc toggle~ | +| ~s~ | ~exec mpc stop~ | -This translates to: +Let’s translate this table in CommonLisp: #+begin_src lisp - (defvar *my-end-session-keymap* + (defvar *my-buffers-management-keymap* (let ((m (make-sparse-keymap))) - <> + <> m)) + + (define-key *root-map* (kbd "m") '*my-media-keymap*) #+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 - (define-key *root-map* (kbd "q") '*my-end-session-keymap*) + <> #+end_src ** Misc @@ -964,3 +1115,57 @@ anywhere else: #+begin_src lisp <> #+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 +: *