[StumpWM] Fix issue with undeclared my/kbd
`my/kbd` appeared as undefined in `bluetooth.lisp` and `utilities.lisp`. This commit fixes this error.
This commit is contained in:
parent
3e476e67a9
commit
bb1dfc15fc
@ -865,314 +865,6 @@ Finally, let’s enable our gaps:
|
|||||||
(swm-gaps:toggle-gaps))
|
(swm-gaps:toggle-gaps))
|
||||||
#+end_src
|
#+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)))
|
|
||||||
<<keybinds-gen(map="m", keybinds=bluetooth-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")
|
|
||||||
|
|
||||||
<<keybinds-gen(map="*root-map*", keybinds=nm-keybinds)>>
|
|
||||||
#+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
|
* Keybinds
|
||||||
:PROPERTIES:
|
:PROPERTIES:
|
||||||
:CUSTOM_ID: Keybinds-c6wgf961v5j0
|
:CUSTOM_ID: Keybinds-c6wgf961v5j0
|
||||||
@ -1280,7 +972,9 @@ the right column.
|
|||||||
: (("«" . "guillemotleft") ("»" . "guillemotright"))
|
: (("«" . "guillemotleft") ("»" . "guillemotright"))
|
||||||
|
|
||||||
To convert these characters, I have my own macro which is a wrapper
|
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
|
#+begin_src lisp :noweb yes
|
||||||
(defun my/kbd (keys)
|
(defun my/kbd (keys)
|
||||||
"Prepares KEYS for function `stumpwm:kbd'.
|
"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)))))))
|
(setf keys (cl-ppcre:regex-replace-all (car row) keys (cdr row)))))))
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
|
#+header: :exports none
|
||||||
|
#+begin_src lisp :noweb yes :tangle ~/.stumpwm.d/bluetooth.lisp
|
||||||
|
<<my-kbd-defun>>
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
#+header: :exports none
|
||||||
|
#+begin_src lisp :noweb yes :tangle ~/.stumpwm.d/utilities.lisp
|
||||||
|
<<my-kbd-defun>>
|
||||||
|
#+end_src
|
||||||
|
|
||||||
** Applications
|
** Applications
|
||||||
:PROPERTIES:
|
:PROPERTIES:
|
||||||
:CUSTOM_ID: Keybinds-Applications-2t512k00w5j0
|
: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*)
|
(define-key *root-map* (my/kbd "k") '*my-keyboard-layout-keymap*)
|
||||||
#+end_src
|
#+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)))
|
||||||
|
<<keybinds-gen(map="m", keybinds=bluetooth-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")
|
||||||
|
|
||||||
|
<<keybinds-gen(map="*root-map*", keybinds=nm-keybinds)>>
|
||||||
|
#+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:
|
* org functions :noexport:
|
||||||
:PROPERTIES:
|
:PROPERTIES:
|
||||||
:CUSTOM_ID: org-functions-syqgzgg0m6j0
|
:CUSTOM_ID: org-functions-syqgzgg0m6j0
|
||||||
|
Loading…
Reference in New Issue
Block a user