diff --git a/org/config/stumpwm.org b/org/config/stumpwm.org index 7812bf6..33bc49c 100644 --- a/org/config/stumpwm.org +++ b/org/config/stumpwm.org @@ -865,314 +865,6 @@ Finally, let’s enable our gaps: (swm-gaps:toggle-gaps)) #+end_src -* Utilities -:PROPERTIES: -:CUSTOM_ID: Utilities-vrggajs0z9j0 -:header-args:lisp: :mkdirp yes :tangle ~/.stumpwm.d/utilities.lisp :noweb yes -:END: -Part of my configuration is not really related to StumpWM itself, or -rather it adds new behavior StumpWM doesn’t have. ~utilities.lisp~ -stores all this code in one place. - -** Binwarp -:PROPERTIES: -:CUSTOM_ID: Utilities-Binwarp-0wrbg1v0z9j0 -:END: -Binwarp allows the user to control their mouse from the keyboard, -basically eliminating the need for a physical mouse in daily usage of -the workstation (though a physical mouse stays useful for games and -such). -#+begin_src lisp -(load-module "binwarp") -#+end_src - -Next, I’ll define my keybinds for when using Binwarp for emulating -mouse clicks as well as bépo-compatible mouse movements. This new -Binwarp mode is now available from the keybind ~s-m~ at top level. -#+begin_src lisp -(binwarp:define-binwarp-mode my-binwarp-mode "s-m" (:map *top-map*) - ((my/kbd "SPC") "ratclick 1") - ((my/kbd "RET") "ratclick 3") - ((my/kbd "c") "binwarp left") - ((my/kbd "t") "binwarp down") - ((my/kbd "s") "binwarp up") - ((my/kbd "r") "binwarp right") - ((my/kbd "i") "init-binwarp") - ((my/kbd "q") "exit-binwarp")) -#+end_src - -** Bluetooth -:PROPERTIES: -:CUSTOM_ID: Utilities-Bluetooth-rns0nr902aj0 -:header-args:lisp: :mkdirp yes :tangle ~/.stumpwm.d/bluetooth.lisp :noweb yes -:END: -Although there is a bluetooth module for the modeline, this is about -the extent to which StumpWM can interact with the system’s bluetooth. -However, I wish for some more interecactivity, like powering on and -off bluetooth, connecting to devices and so on. - -First, out code relies on ~cl-ppcre~, so let’s quickload it. -#+begin_src lisp -(ql:quickload :cl-ppcre) -#+end_src - -Let’s indicate which command we’ll be using. -#+begin_src lisp -(defvar *bluetooth-command* "bluetoothctl" - "Base command for interacting with bluetooth.") -#+end_src - -*** Utilities -:PROPERTIES: -:CUSTOM_ID: Utilities-Bluetooth-Utilities-3zicf7k03aj0 -:END: -We’ll need a couple of functions that will take care of stuff for us -so we don’t have to repeat ourselves. The first one is a way for us to -share a message. The function ~bluetooth-message~ will first display -~Bluetooth:~ in green, then it will display the message we want it to -display. -#+begin_src lisp -(defun bluetooth-message (&rest message) - (message (format nil - "^2Bluetooth:^7 ~{~A~^ ~}" - message))) -#+end_src - -This function is a builder function which will create our commands. -For instance, src_lisp[:exports code]{(bluetooth-make-command "power" -"on")} will return ~"bluetoothctl power on"~ with ~*bluetooth-ctl*~ set as -~"bluetoothctl"~ --- simply put, it joins ~*bluetooth-command*~ with ~args~ -with a space as their separator. -#+begin_src lisp -(defun bluetooth-make-command (&rest args) - (format nil - "~a ~{~A~^ ~}" - ,*bluetooth-command* - args)) -#+end_src - -Now we can put ~bluetooth-make-command~ to use with ~bluetooth-command~ -which will actually run the result of the former. As you can see, it -also collects the output so we can display it later in another -function. -#+begin_src lisp -(defmacro bluetooth-command (&rest args) - `(run-shell-command (bluetooth-make-command ,@args) t)) -#+end_src - -Finally, ~bluetooth-message-command~ is the function that both executes -and also displays the result of the bluetooth command we wanted to see -executed. Each argument of the command is a separate string. For -instance, if we want to power on the bluetooth on our device, we can -call src_lisp[:exports code]{(bluetooth-message-command "power" -"on")}. -#+begin_src lisp -(defmacro bluetooth-message-command (&rest args) - `(bluetooth-message (bluetooth-command ,@args))) -#+end_src - -*** Toggle Bluetooth On and Off -:PROPERTIES: -:CUSTOM_ID: Utilities-Bluetooth-Toggle-Bluetooth-On-and-Off-9pyfbtd02aj0 -:END: -This part is easy. Now that we can call our bluetooth commands easily, -we can easily define how to turn on bluetooth. -#+begin_src lisp -(defcommand bluetooth-turn-on () () - "Turn on bluetooth." - (bluetooth-message-command "power" "on")) -#+end_src - -And how to power it off. -#+begin_src lisp -(defcommand bluetooth-turn-off () () - "Turn off bluetooth." - (bluetooth-message-command "power" "off")) -#+end_src - -*** Bluetooth Devices -:PROPERTIES: -:CUSTOM_ID: Utilities-Bluetooth-Bluetooth-Devices-196gbtd02aj0 -:END: -In order to manipulate bluetooth device, which we can represent as a -MAC address and a name, we can create a structure that will make use -of a constructor for simpler use. The constructor -~make-bluetooth-device-from-command~ expects an entry such as ~Device -00:00:00:00:00:00 Home Speaker~. The constructor discards the term -~Device~ and stores the MAC address separately from the rest of the -string which is assumed to be the full name of the device. -#+begin_src lisp -(defstruct (bluetooth-device - (:constructor - make-bluetooth-device (&key (address "") - (name nil))) - (:constructor - make-bluetooth-device-from-command - (&key (raw-name "") - &aux (address (cadr (cl-ppcre:split " " raw-name))) - (full-name (format nil "~{~A~^ ~}" (cddr (cl-ppcre:split " " raw-name))))))) - address - (full-name (progn - (format nil "~{~A~^ ~}" name)))) -#+end_src - -We can now collect our devices easily. -#+begin_src lisp -(defun bluetooth-get-devices () - (let ((literal-devices (bluetooth-command "devices"))) - (mapcar (lambda (device) - (make-bluetooth-device-from-command :raw-name device)) - (cl-ppcre:split "\\n" literal-devices)))) -#+end_src - -*** Connect to a device -:PROPERTIES: -:CUSTOM_ID: Utilities-Bluetooth-Connect-to-a-device-tjqcf7k03aj0 -:END: -When we want to connect to a bluetooth device, we always need -bluetooth turned on, so ~bluetooth-turn-on~ will always be called. Then -the function will attempt to connect to the device specified by the -~device~ argument, whether the argument is a bluetooth structure as -defined above or a plain MAC address. -#+begin_src lisp -(defun bluetooth-connect-device (device) - (progn - (bluetooth-turn-on) - (cond ((bluetooth-device-p device) ;; it is a bluetooth-device structure - (bluetooth-message-command "connect" - (bluetooth-device-address device))) - ((stringp device) ;; assume it is a MAC address - (bluetooth-message-command "connect" device)) - (t (message (format nil "Cannot work with device ~a" device)))))) -#+end_src - -The command to connect to a device displays a choice between the -collected bluetooth device and the user only has to select it. It will -then attempt to connect to it. -#+begin_src lisp -(defcommand bluetooth-connect () () - (let* ((devices (bluetooth-get-devices)) - (choice (cdr (stumpwm:select-from-menu - (stumpwm:current-screen) - (mapcar (lambda (device) - `(,(bluetooth-device-full-name device) . ,device)) - devices))))) - (bluetooth-connect-device choice))) -#+end_src - -*** Keybinds -:PROPERTIES: -:CUSTOM_ID: Utilities-Bluetooth-Keybinds-gxjaagl05aj0 -:END: -It’s all nice and all, but typing manually the commands with ~s-SPC ;~ -is a bit tiring, so let’s define our bluetooth keymap which we will -bind to ~s-SPC B~. -#+name: bluetooth-keymap -| Keychord | Command | -|----------+--------------------| -| ~c~ | ~bluetooth-connect~ | -| ~o~ | ~bluetooth-turn-on~ | -| ~O~ | ~bluetooth-turn-off~ | - -#+begin_src lisp -(defvar *my-bluetooth-keymap* - (let ((m (make-sparse-keymap))) - <> - m)) - -(define-key *root-map* (my/kbd "B") '*my-bluetooth-keymap*) -#+end_src - -** NetworkManager integration -:PROPERTIES: -:CUSTOM_ID: Utilities-NetworkManager-integration-nm7jxbt0z9j0 -:END: -It is possible to have some kind of integration between StumpWM and -NetworkManager. To do so, we have to load the related module, then -create the two keybinds described in [[nm-keybinds]]. -#+name: nm-keybinds -#+caption: ~*my-nm-keybinds*~ -| Keychord | Command | -|----------+---------------------------| -| ~W~ | ~nm-list-wireless-networks~ | - -A call to src_lisp[:exports code]{(ql:quickload :dbus)} is necessary -for this module. Installing the ~dbus~ module in turn requires the -library ~libfixposix~ installed on the user’s machine. On Arch, you can -install it like so using ~paru~: -#+begin_src fish -paru -S libfixposix --noconfirm -#+end_src - -#+begin_src lisp -(ql:quickload :dbus) - -(load-module "stump-nm") - -<> -#+end_src - -** Pinentry -:PROPERTIES: -:CUSTOM_ID: Utilities-Pinentry-o6v95fu0z9j0 -:END: -Out with GTK2’s pinentry program! Let’s use StumpWM’s! At least that’s -what I’d like to say, but unfortunately there is a bug in the text -reading devices of StumpWM that prevent the user from using modifiers -when entering a password such as AltGr, so I can’t use it : / -#+begin_src lisp -;; (load-module "pinentry") -#+end_src - -** Sly -:PROPERTIES: -:CUSTOM_ID: Utilities-Sly-kkok6oi0yaj0 -:END: -[[https://github.com/joaotavora/sly][Sly]] is a fork of SLIME with which I can connect StumpWM and Emacs -together. Technically this is already done to some level with -~stumpwm-mode~, but the latter doesn’t provide auto-completion or stuff -like that. - -The first thing to do is load ~slynk~, SLY’s server: -#+begin_src lisp -(ql:quickload :slynk) -#+end_src - -Now we can define a command to launch the server. I don’t want it to -run all the time, just when I need it. -#+begin_src lisp -(stumpwm:defcommand sly-start-server () () - "Start a slynk server for sly." - (slynk:create-server :dont-close t)) - -(stumpwm:defcommand sly-stop-server () () - "Stop current slynk server for sly." - (slynk:stop-server 4005)) -#+end_src - -** ~swm-ssh~ -:PROPERTIES: -:CUSTOM_ID: Utilities-swm-ssh-s14ahrs0z9j0 -:END: -This module from the contrib repository scans the user’s ssh -configuration file and offers them a quick way of connecting to their -remote hosts. -#+begin_src lisp -(load-module "swm-ssh") -#+end_src - -The default terminal needs to be set, otherwise the module will try to -call ~urxvtc~ which is not installed on my system. -#+begin_src lisp -(setq swm-ssh:*swm-ssh-default-term* "kitty") -#+end_src - -Now, to call the main command of this module we can define the -following keybind. -#+begin_src lisp -(define-key *root-map* (my/kbd "s") "swm-ssh-menu") -#+end_src - * Keybinds :PROPERTIES: :CUSTOM_ID: Keybinds-c6wgf961v5j0 @@ -1280,7 +972,9 @@ the right column. : (("«" . "guillemotleft") ("»" . "guillemotright")) To convert these characters, I have my own macro which is a wrapper -around the function ~kbd~: +around the function ~kbd~. + +#+name: my-kbd-defun #+begin_src lisp :noweb yes (defun my/kbd (keys) "Prepares KEYS for function `stumpwm:kbd'. @@ -1293,6 +987,16 @@ such as « or » and have them replaced with their actual name when (setf keys (cl-ppcre:regex-replace-all (car row) keys (cdr row))))))) #+end_src +#+header: :exports none +#+begin_src lisp :noweb yes :tangle ~/.stumpwm.d/bluetooth.lisp +<> +#+end_src + +#+header: :exports none +#+begin_src lisp :noweb yes :tangle ~/.stumpwm.d/utilities.lisp +<> +#+end_src + ** Applications :PROPERTIES: :CUSTOM_ID: Keybinds-Applications-2t512k00w5j0 @@ -1842,6 +1546,314 @@ games and the bépo layout most of the time. I’ll use the command (define-key *root-map* (my/kbd "k") '*my-keyboard-layout-keymap*) #+end_src +* Utilities +:PROPERTIES: +:CUSTOM_ID: Utilities-vrggajs0z9j0 +:header-args:lisp: :mkdirp yes :tangle ~/.stumpwm.d/utilities.lisp :noweb yes +:END: +Part of my configuration is not really related to StumpWM itself, or +rather it adds new behavior StumpWM doesn’t have. ~utilities.lisp~ +stores all this code in one place. + +** Binwarp +:PROPERTIES: +:CUSTOM_ID: Utilities-Binwarp-0wrbg1v0z9j0 +:END: +Binwarp allows the user to control their mouse from the keyboard, +basically eliminating the need for a physical mouse in daily usage of +the workstation (though a physical mouse stays useful for games and +such). +#+begin_src lisp +(load-module "binwarp") +#+end_src + +Next, I’ll define my keybinds for when using Binwarp for emulating +mouse clicks as well as bépo-compatible mouse movements. This new +Binwarp mode is now available from the keybind ~s-m~ at top level. +#+begin_src lisp +(binwarp:define-binwarp-mode my-binwarp-mode "s-m" (:map *top-map*) + ((my/kbd "SPC") "ratclick 1") + ((my/kbd "RET") "ratclick 3") + ((my/kbd "c") "binwarp left") + ((my/kbd "t") "binwarp down") + ((my/kbd "s") "binwarp up") + ((my/kbd "r") "binwarp right") + ((my/kbd "i") "init-binwarp") + ((my/kbd "q") "exit-binwarp")) +#+end_src + +** Bluetooth +:PROPERTIES: +:CUSTOM_ID: Utilities-Bluetooth-rns0nr902aj0 +:header-args:lisp: :mkdirp yes :tangle ~/.stumpwm.d/bluetooth.lisp :noweb yes +:END: +Although there is a bluetooth module for the modeline, this is about +the extent to which StumpWM can interact with the system’s bluetooth. +However, I wish for some more interecactivity, like powering on and +off bluetooth, connecting to devices and so on. + +First, out code relies on ~cl-ppcre~, so let’s quickload it. +#+begin_src lisp +(ql:quickload :cl-ppcre) +#+end_src + +Let’s indicate which command we’ll be using. +#+begin_src lisp +(defvar *bluetooth-command* "bluetoothctl" + "Base command for interacting with bluetooth.") +#+end_src + +*** Utilities +:PROPERTIES: +:CUSTOM_ID: Utilities-Bluetooth-Utilities-3zicf7k03aj0 +:END: +We’ll need a couple of functions that will take care of stuff for us +so we don’t have to repeat ourselves. The first one is a way for us to +share a message. The function ~bluetooth-message~ will first display +~Bluetooth:~ in green, then it will display the message we want it to +display. +#+begin_src lisp +(defun bluetooth-message (&rest message) + (message (format nil + "^2Bluetooth:^7 ~{~A~^ ~}" + message))) +#+end_src + +This function is a builder function which will create our commands. +For instance, src_lisp[:exports code]{(bluetooth-make-command "power" +"on")} will return ~"bluetoothctl power on"~ with ~*bluetooth-ctl*~ set as +~"bluetoothctl"~ --- simply put, it joins ~*bluetooth-command*~ with ~args~ +with a space as their separator. +#+begin_src lisp +(defun bluetooth-make-command (&rest args) + (format nil + "~a ~{~A~^ ~}" + ,*bluetooth-command* + args)) +#+end_src + +Now we can put ~bluetooth-make-command~ to use with ~bluetooth-command~ +which will actually run the result of the former. As you can see, it +also collects the output so we can display it later in another +function. +#+begin_src lisp +(defmacro bluetooth-command (&rest args) + `(run-shell-command (bluetooth-make-command ,@args) t)) +#+end_src + +Finally, ~bluetooth-message-command~ is the function that both executes +and also displays the result of the bluetooth command we wanted to see +executed. Each argument of the command is a separate string. For +instance, if we want to power on the bluetooth on our device, we can +call src_lisp[:exports code]{(bluetooth-message-command "power" +"on")}. +#+begin_src lisp +(defmacro bluetooth-message-command (&rest args) + `(bluetooth-message (bluetooth-command ,@args))) +#+end_src + +*** Toggle Bluetooth On and Off +:PROPERTIES: +:CUSTOM_ID: Utilities-Bluetooth-Toggle-Bluetooth-On-and-Off-9pyfbtd02aj0 +:END: +This part is easy. Now that we can call our bluetooth commands easily, +we can easily define how to turn on bluetooth. +#+begin_src lisp +(defcommand bluetooth-turn-on () () + "Turn on bluetooth." + (bluetooth-message-command "power" "on")) +#+end_src + +And how to power it off. +#+begin_src lisp +(defcommand bluetooth-turn-off () () + "Turn off bluetooth." + (bluetooth-message-command "power" "off")) +#+end_src + +*** Bluetooth Devices +:PROPERTIES: +:CUSTOM_ID: Utilities-Bluetooth-Bluetooth-Devices-196gbtd02aj0 +:END: +In order to manipulate bluetooth device, which we can represent as a +MAC address and a name, we can create a structure that will make use +of a constructor for simpler use. The constructor +~make-bluetooth-device-from-command~ expects an entry such as ~Device +00:00:00:00:00:00 Home Speaker~. The constructor discards the term +~Device~ and stores the MAC address separately from the rest of the +string which is assumed to be the full name of the device. +#+begin_src lisp +(defstruct (bluetooth-device + (:constructor + make-bluetooth-device (&key (address "") + (name nil))) + (:constructor + make-bluetooth-device-from-command + (&key (raw-name "") + &aux (address (cadr (cl-ppcre:split " " raw-name))) + (full-name (format nil "~{~A~^ ~}" (cddr (cl-ppcre:split " " raw-name))))))) + address + (full-name (progn + (format nil "~{~A~^ ~}" name)))) +#+end_src + +We can now collect our devices easily. +#+begin_src lisp +(defun bluetooth-get-devices () + (let ((literal-devices (bluetooth-command "devices"))) + (mapcar (lambda (device) + (make-bluetooth-device-from-command :raw-name device)) + (cl-ppcre:split "\\n" literal-devices)))) +#+end_src + +*** Connect to a device +:PROPERTIES: +:CUSTOM_ID: Utilities-Bluetooth-Connect-to-a-device-tjqcf7k03aj0 +:END: +When we want to connect to a bluetooth device, we always need +bluetooth turned on, so ~bluetooth-turn-on~ will always be called. Then +the function will attempt to connect to the device specified by the +~device~ argument, whether the argument is a bluetooth structure as +defined above or a plain MAC address. +#+begin_src lisp +(defun bluetooth-connect-device (device) + (progn + (bluetooth-turn-on) + (cond ((bluetooth-device-p device) ;; it is a bluetooth-device structure + (bluetooth-message-command "connect" + (bluetooth-device-address device))) + ((stringp device) ;; assume it is a MAC address + (bluetooth-message-command "connect" device)) + (t (message (format nil "Cannot work with device ~a" device)))))) +#+end_src + +The command to connect to a device displays a choice between the +collected bluetooth device and the user only has to select it. It will +then attempt to connect to it. +#+begin_src lisp +(defcommand bluetooth-connect () () + (let* ((devices (bluetooth-get-devices)) + (choice (cdr (stumpwm:select-from-menu + (stumpwm:current-screen) + (mapcar (lambda (device) + `(,(bluetooth-device-full-name device) . ,device)) + devices))))) + (bluetooth-connect-device choice))) +#+end_src + +*** Keybinds +:PROPERTIES: +:CUSTOM_ID: Utilities-Bluetooth-Keybinds-gxjaagl05aj0 +:END: +It’s all nice and all, but typing manually the commands with ~s-SPC ;~ +is a bit tiring, so let’s define our bluetooth keymap which we will +bind to ~s-SPC B~. +#+name: bluetooth-keymap +| Keychord | Command | +|----------+--------------------| +| ~c~ | ~bluetooth-connect~ | +| ~o~ | ~bluetooth-turn-on~ | +| ~O~ | ~bluetooth-turn-off~ | + +#+begin_src lisp +(defvar *my-bluetooth-keymap* + (let ((m (make-sparse-keymap))) + <> + m)) + +(define-key *root-map* (my/kbd "B") '*my-bluetooth-keymap*) +#+end_src + +** NetworkManager integration +:PROPERTIES: +:CUSTOM_ID: Utilities-NetworkManager-integration-nm7jxbt0z9j0 +:END: +It is possible to have some kind of integration between StumpWM and +NetworkManager. To do so, we have to load the related module, then +create the two keybinds described in [[nm-keybinds]]. +#+name: nm-keybinds +#+caption: ~*my-nm-keybinds*~ +| Keychord | Command | +|----------+---------------------------| +| ~W~ | ~nm-list-wireless-networks~ | + +A call to src_lisp[:exports code]{(ql:quickload :dbus)} is necessary +for this module. Installing the ~dbus~ module in turn requires the +library ~libfixposix~ installed on the user’s machine. On Arch, you can +install it like so using ~paru~: +#+begin_src fish +paru -S libfixposix --noconfirm +#+end_src + +#+begin_src lisp +(ql:quickload :dbus) + +(load-module "stump-nm") + +<> +#+end_src + +** Pinentry +:PROPERTIES: +:CUSTOM_ID: Utilities-Pinentry-o6v95fu0z9j0 +:END: +Out with GTK2’s pinentry program! Let’s use StumpWM’s! At least that’s +what I’d like to say, but unfortunately there is a bug in the text +reading devices of StumpWM that prevent the user from using modifiers +when entering a password such as AltGr, so I can’t use it : / +#+begin_src lisp +;; (load-module "pinentry") +#+end_src + +** Sly +:PROPERTIES: +:CUSTOM_ID: Utilities-Sly-kkok6oi0yaj0 +:END: +[[https://github.com/joaotavora/sly][Sly]] is a fork of SLIME with which I can connect StumpWM and Emacs +together. Technically this is already done to some level with +~stumpwm-mode~, but the latter doesn’t provide auto-completion or stuff +like that. + +The first thing to do is load ~slynk~, SLY’s server: +#+begin_src lisp +(ql:quickload :slynk) +#+end_src + +Now we can define a command to launch the server. I don’t want it to +run all the time, just when I need it. +#+begin_src lisp +(stumpwm:defcommand sly-start-server () () + "Start a slynk server for sly." + (slynk:create-server :dont-close t)) + +(stumpwm:defcommand sly-stop-server () () + "Stop current slynk server for sly." + (slynk:stop-server 4005)) +#+end_src + +** ~swm-ssh~ +:PROPERTIES: +:CUSTOM_ID: Utilities-swm-ssh-s14ahrs0z9j0 +:END: +This module from the contrib repository scans the user’s ssh +configuration file and offers them a quick way of connecting to their +remote hosts. +#+begin_src lisp +(load-module "swm-ssh") +#+end_src + +The default terminal needs to be set, otherwise the module will try to +call ~urxvtc~ which is not installed on my system. +#+begin_src lisp +(setq swm-ssh:*swm-ssh-default-term* "kitty") +#+end_src + +Now, to call the main command of this module we can define the +following keybind. +#+begin_src lisp +(define-key *root-map* (my/kbd "s") "swm-ssh-menu") +#+end_src + * org functions :noexport: :PROPERTIES: :CUSTOM_ID: org-functions-syqgzgg0m6j0