diff options
Diffstat (limited to 'config')
-rw-r--r-- | config/doom.org | 174 | ||||
-rw-r--r-- | config/elfeed.org | 20 | ||||
-rw-r--r-- | config/fish.org | 55 | ||||
-rw-r--r-- | config/index.org | 27 | ||||
-rw-r--r-- | config/kmonad.org | 720 | ||||
-rw-r--r-- | config/qtile.org | 286 | ||||
-rw-r--r-- | config/qutebrowser.org | 99 |
7 files changed, 1381 insertions, 0 deletions
diff --git a/config/doom.org b/config/doom.org new file mode 100644 index 0000000..b3fce4b --- /dev/null +++ b/config/doom.org @@ -0,0 +1,174 @@ +#+title: Doom Literate Config +#+author: Preston Pan +#+date: <2023-06-09 Fri> +#+description: My doom emacs configuration +#+html_head: <link rel="stylesheet" type="text/css" href="../style.css" /> + +* Configuration +** Basic Information +My name, and the org mode directory on my computer, as well as basic editor configuration options. +Below is the old documentation. +#+begin_src emacs-lisp :tangle yes +(setq user-full-name "Preston Pan" + user-mail-address "prseton@nullring.xyz") + +(setq display-line-numbers-type t) + +(setq org-directory "~/org/") +#+end_src +- `load!' for loading external *.el files relative to this one +- `add-load-path!' for adding directories to the `load-path', relative to + this file. Emacs searches the `load-path' when you load packages with + `require' or `use-package'. +** Font +Now we configure fonts: +#+begin_src emacs-lisp :tangle yes +(setq doom-font (font-spec :family "FiraCode Nerd Font" :size 14 :weight 'semi-light) + doom-variable-pitch-font (font-spec :family "Fira Sans" :size 14) + doom-unicode-font (font-spec :family "Symbola" :size 14) + doom-serif-font (font-spec :family "Fira Sans" :size 14) + doom-big-font (font-spec :family "FiraCode Nerd Font" :size 28)) +#+end_src +** Color Scheme +I'm using the catppuccin theme, which is available on github. +#+begin_src emacs-lisp :tangle yes +(setq doom-theme 'catppuccin) +(setq catppuccin-flavor 'mocha) +#+end_src +** Doom Module and Programs Configuration +*** IRC +Set up circe to connect to my bouncer: +#+begin_src emacs-lisp :tangle yes +(after! circe + (set-irc-server! "nullring.xyz" + `(:tls t + :port 4095 + :nick "LiCoO2/AndreiNet" + :user "LiCoO2/AndreiNet" + :pass ,(+pass-get-secret "ZNC")))) +#+end_src +*** Email +In order to use this configuration, you must install and configure mu and mbsync. +#+begin_src emacs-lisp :tangle yes +(setq mu4e-get-mail-command "mbsync --config ~/.config/doom/mbsyncrc prestonpan") + +(setq send-mail-function 'smtpmail-send-it) +(setq smtpmail-smtp-server "mail.nullring.xyz") +(setq smtpmail-smtp-service 465) +(setq smtpmail-stream-type 'ssl) + +(setq mu4e-drafts-folder "/Drafts") +(setq mu4e-sent-folder "/Sent") +(setq mu4e-trash-folder "/Trash") + +(setq mu4e-html2text-command "w3m -T text/html" + mu4e-update-interval 300 + mu4e-headers-auto-update t + mu4e-view-show-images t + mu4e-compose-signature-auto-include nil + mu4e-use-fancy-chars t) +(setq mu4e-compose-reply-ignore-address '("no-?reply" "preston@nullring.xyz")) +#+end_src +*** RSS +We need to set up elfeed with a list of rss feeds. +#+begin_src emacs-lisp :tangle yes +(after! elfeed + (setq elfeed-search-filter "@1-month-ago +unread")) +(add-hook! 'elfeed-search-mode-hook #'elfeed-update) +(setq rmh-elfeed-org-files '("~/org/elfeed.org")) +#+end_src +*** Music +In order to use this configuration, you must have mpd configured to use the same directory. +We automatically connect to mpd. +#+begin_src emacs-lisp :tangle yes +(setq emms-player-mpd-music-directory "~/music/") +(setq emms-player-list '(emms-player-mpd)) +(emms-player-mpd-connect) +#+end_src +*** Journal +First we set the journal to be in the website directory: +#+begin_src emacs-lisp :tangle yes + +(setq org-journal-dir "~/org/website/journal/") +(setq org-journal-date-format "%A, %d %B %Y") +#+end_src +And then we add the headers needed to export the journal automatically: +#+begin_src emacs-lisp :tangle yes +(defun org-journal-file-header-func (time) + "Custom function to create journal header." + (concat + (pcase org-journal-file-type + (`daily "#+TITLE: Daily Journal\n#+STARTUP: showeverything\n#+DESCRIPTION: My daily journal entry\n#+AUTHOR: Preston Pan\n#+HTML_HEAD: <link rel=\"stylesheet\" type=\"text/css\" href=\"../style.css\" />\n#+html_head: <script src=\"https://polyfill.io/v3/polyfill.min.js?features=es6\"></script>\n#+html_head: <script id=\"MathJax-script\" async src=\"https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js\"></script>") + (`weekly "#+TITLE: Weekly Journal\n#+STARTUP: folded") + (`monthly "#+TITLE: Monthly Journal\n#+STARTUP: folded") + (`yearly "#+TITLE: Yearly Journal\n#+STARTUP: folded")))) + +(setq org-journal-file-header 'org-journal-file-header-func) +(setq org-journal-file-format "%Y%m%d.org") +#+end_src +*** Brain +#+begin_src emacs-lisp :tangle yes +(setq org-brain-path "~/org/website/brain/") +#+end_src +*** Roam +#+begin_src emacs-lisp :tangle yes +(setq org-roam-directory (file-truename "~/org/website/mindmap")) +(setq org-roam-capture-templates '(("d" "default" plain "%?" + :target (file+head "${title}.org" + "#+title: ${title}\n#+author: Preston Pan\n#+html_head: <link rel=\"stylesheet\" type=\"text/css\" href=\"../style.css\" />\n#+html_head: <script src=\"https://polyfill.io/v3/polyfill.min.js?features=es6\"></script>\n#+html_head: <script id=\"MathJax-script\" async src=\"https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js\"></script>") + :unnarrowed t))) +#+end_src +*** Publishing +#+begin_src emacs-lisp :tangle yes +(require 'ox-publish) +(setq org-publish-project-alist + '(("website-org" + :base-directory "~/org/website" + :base-extension "org" + :publishing-directory "~/website_html" + :recursive t + :publishing-function org-html-publish-to-html + :headline-levels 4 + :auto-preamble t) + ("website-static" + :base-directory "~/org/website" + :base-extension "css\\|js\\|png\\|jpg\\|gif\\|pdf\\|mp3\\|ogg\\|swf" + :publishing-directory "~/website_html/" + :recursive t + :publishing-function org-publish-attachment) + ("website" :components ("website-org" "website-static")))) + + +#+end_src +** Keybindings +Now we set up our keybindings for our applications: +#+begin_src emacs-lisp :tangle yes +(map! :leader + :desc "Open irc" + "i c" #'circe) +(map! :leader + :desc "Open audio manager" + "m m" #'emms) +(map! :leader + :desc "Open RSS feed reader" + "r s" #'elfeed) +(map! :leader + :desc "Open password manager" + "p w" #'ivy-pass) +#+end_src +** External Packages +we want to include some packages that don't come with doom emacs. +*** KBD-Mode +kbd-mode allows us to edit kmonad kbd files with syntax highlighting: +#+begin_src emacs-lisp :tangle yes +(use-package! kbd-mode) +#+end_src +*** Pinentry +We now set up pinentry for the pass program. We need to set the mode to loopback +in order to enable emacs to start itself as a pinentry program, and we need to allow +loopbacks in gpg-agent.conf. +#+begin_src emacs-lisp :tangle yes +(use-package! pinentry + :init (setq epa-pinentry-mode `loopback) + (pinentry-start)) +#+end_src diff --git a/config/elfeed.org b/config/elfeed.org new file mode 100644 index 0000000..bd71ffd --- /dev/null +++ b/config/elfeed.org @@ -0,0 +1,20 @@ +#+title: Elfeed Feed +#+author: Preston Pan +#+date: <2023-06-09 Fri> +#+description: My list of blogs, news sites, and channels. + +#+html_head: <link rel="stylesheet" type="text/css" href="../style.css" /> +* Feed +** Blogs :blog: +Here are some interesting blogs, many of which are from substack. +*** https://astralcodexten.substack.com/feed +*** https://graymirror.substack.com/feed +*** https://lukesmith.xyz/index.xml :lukesmith: +** News :news: +*** https://rss.nytimes.com/services/xml/rss/nyt/Technology.xml +*** https://rss.nytimes.com/services/xml/rss/nyt/World.xml +*** https://rss.nytimes.com/services/xml/rss/nyt/Science.xml +*** https://rss.nytimes.com/services/xml/rss/nyt/AsiaPacific.xml +** Podcasts :podcast: +*** https://notrelated.xyz/rss :lukesmith: +** Misc. diff --git a/config/fish.org b/config/fish.org new file mode 100644 index 0000000..cb6e0af --- /dev/null +++ b/config/fish.org @@ -0,0 +1,55 @@ +#+title: Fish RC File +#+author: Preston Pan +#+date: <2023-06-09 Fri> +#+description: My fish shell configuration. + +#+html_head: <link rel="stylesheet" type="text/css" href="../style.css" /> + +* Configuration +** Environment Variables +We define our path and also some environment variables. Since +I use guix as one of my package managers, I set GUIX_LOCPATH. +Also, I have a ~/.local/bin directory where I keep my scripts. +#+begin_src fish :tangle config.fish +fish_add_path -m ~/.local/bin +fish_add_path -m ~/gems/bin +fish_add_path -m ~/.local/share/gem/ruby/3.0.0/bin +set -x GUIX_LOCPATH $HOME/.guix-profile/lib/locale +set -x GEM_HOME "~/gems" +#+end_src +** Aliases +Now we define some aliases: +*** Git +We want to define aliases only if we call fish as an interactive shell. +We also define some common aliases for git commands: +#+begin_src fish :tangle config.fish +if status is-interactive + alias gcl="git clone" + alias gp="git push" + alias gpu="git pull" + alias gcm="git commit" +#+end_src +*** Pacman +Now we define aliases for commonly used pacman commands in the form +of the paru aur helper: +#+begin_src fish :tangle config.fish + alias p="paru -S" + alias pq="paru -sS" + alias pd="paru -Rncs" + alias syncweb="rsync -uvrP --delete-after website_html/ root@nullring.xyz:/var/www/ret2pop/" +#+end_src +*** Misc. +These are generally useful commands. Since I use mbsync, I wrote an alias +for it. +#+begin_src fish :tangle config.fish + alias c="clear" + alias l="ls -a" + alias mkdir="mkdir -pv" + alias syncmail="mbsync -c ~/.config/doom/mbsyncrc prestonpan" +#+end_src +** Vi Mode +Now we want to use vi mode because it is better. +#+begin_src fish :tangle config.fish + fish_vi_key_bindings +end +#+end_src diff --git a/config/index.org b/config/index.org new file mode 100644 index 0000000..1932468 --- /dev/null +++ b/config/index.org @@ -0,0 +1,27 @@ +#+title: Configurations +#+author: Preston Pan +#+date: <2023-06-10 Sat> +#+language: en +#+html_head: <link rel="stylesheet" type="text/css" href="../style.css" /> +#+OPTIONS: broken-links:t +* What is this magic? +They're configurations for extremely obscure programs I use. Yeah, I know, I'm somewhat of a hipster myself. +** Configurations +Here is a list of my configurations for various programs: +#+begin_src shell :results output raw :exports both +for f in *; +do + if [[ "$f" == "index.org" ]]; then + continue + fi + printf -- "- [[file:$f][$f]]\n" +done +#+end_src + +#+RESULTS: +- [[file:doom.org][doom.org]] +- [[file:elfeed.org][elfeed.org]] +- [[file:fish.org][fish.org]] +- [[file:kmonad.org][kmonad.org]] +- [[file:qtile.org][qtile.org]] +- [[file:qutebrowser.org][qutebrowser.org]] diff --git a/config/kmonad.org b/config/kmonad.org new file mode 100644 index 0000000..4f38a86 --- /dev/null +++ b/config/kmonad.org @@ -0,0 +1,720 @@ +#+title: KMonad Configuration +#+author: Preston Pan +#+description: My Literate KMonad Configuration +#+html_head: <link rel="stylesheet" type="text/css" href="../style.css" /> + +* Goals +** It should be the most efficient keyboard layout possible. +*** Ergonomic key positions and more frequent keys closer to home row. +*** Optimize the layers in such a way where we do not need to change layer frequently +however, layers are still needed because it is sometimes more economical to switch layers rather than to reach. + +* Configuration +** Initial Values +We must set our initial values for the configuration: +#+begin_src kbd :tangle config.kbd +(defcfg + input (device-file "/dev/input/by-path/platform-i8042-serio-0-event-kbd") + output (uinput-sink "My KMonad output" + "/usr/bin/sleep 1 && /usr/bin/setxkbmap -option compose:ralt") + cmp-seq ralt ;; Set the compose key to `RightAlt' + cmp-seq-delay 5 ;; 5ms delay between each compose-key sequence press + fallthrough true + allow-cmd true +) +#+end_src +you need to set your input device according to your hardware. +** defsrc +The defsrc block specifies the default layout that our keyboard uses. Note that when you are, +for example, using a 40% keyboard, some of these keys will not be present. +However, it is still syntactically valid and you will be able to use this +configuration. +#+begin_src kbd :tangle config.kbd +(defsrc + grv 1 2 3 4 5 6 7 8 9 0 - = bspc + tab q w e r t y u i o p [ ] \ + caps a s d f g h j k l ; ' ret + lsft z x c v b n m , . / rsft + lctl lmet lalt spc ralt rmet cmp rctl +) +#+end_src +Also note that the defsrc block is not used for custom key configuration. It +is used only to describe the shape of the current keyboard. +** defalias +defalias defines aliases for buttons. Buttons are used in deflayer blocks +in order to remap the keys. +#+begin_src kbd :tangle config.kbd +(defalias + num (layer-toggle numbers) + kil C-A-del +) +#+end_src +** deflayer +#+begin_src kbd :tangle config.kbd +#| -------------------------------------------------------------------------- + Necessary: at least 1 `deflayer` block + + It is also important to mention that the 'keymap' in KMonad is modelled as a + stack of layers (just like in QMK). When an event is registered we look in the + top-most layer for a handler. If we don't find one we try the next layer, and + then the next. + + Exactly what 'evaluates-to-a-button' will be expanded on in more detail below. + There are very many different specialist buttons in KMonad that we will touch + upon. However, for now, these 4 are a good place to begin: + + 1. Any keycode evaluates to a button that, on press, emits the press of that + keycode, and on release, emits the release of that keycode. Just a 'normal' + button. The exception is '\', which gets used as an escape character. Use + '\\' instead. Other characters that need to be escaped to match the literal + character are '(', ')', and '_'. + + 2. An @-prefixed name evaluates to an alias lookup. We named two buttons in + the `defalias` block above, we could now refer to these buttons using + `@num` and `@kil`. This is also why we only use alias-names no longer than + 3 characters in this tutorial. Also, note that we are already referencing + some aliases that have not yet been defined, this is not an issue. + + 3. The '_' character evaluates to transparent. I.e. no handler for that + key-event in this layer, causing this event to be handed down the layer + stack to perhaps be handled by the next layer. + + 4. The 'XX' character evaluates to blocked. I.e. no action bound to that + key-event in this layer, but do actually catch event, preventing any + underlying layer from handling it. + + Finally, it is important to note that the *first* `deflayer` statement in a + KMonad config will be the layer that is active when KMonad starts up. + + -------------------------------------------------------------------------- |# + + +(deflayer qwerty + grv 1 2 3 4 5 6 7 8 9 0 - = bspc + tab q w e r t y u i o p [ ] \ + esc a s d f g h j k l ; ' ret + lsft z x c v b n m , . / rsft + lctl lmet lalt spc @num rmet @sym rctl +) + +(deflayer numbers + _ _ _ _ _ _ _ _ _ _ _ _ _ _ + _ _ _ _ _ XX / 7 8 9 - _ _ _ + _ _ _ _ _ XX * 4 5 6 + _ _ + _ _ \( \) . XX 0 1 2 3 _ _ + _ _ _ _ _ _ _ _ +) + +#+end_src + +#+begin_src kbd :tangle config.kbd +#| -------------------------------------------------------------------------- + Optional: modded buttons + + Let's start by exploring the various special buttons that are supported by + KMonad by looking at 'modded' buttons, that is to say, buttons that activate + some kind of 'mod', then perform some button, and finally release that 'mod' + again. + + We have already seen an example of this style of button, our `kil` button is + one such button. Let's look at it in more detail: + C-A-del + + This looks like a simple declarative statement, but it's helpful to realize + that is simply syntactic sugar around 2 function calls. This statement is + equivalent to: + (around ctl (around alt del)) + + This highlights a core design principle in KMonad: we try to provide very + simple buttons, and then we provide rules and functions for combining them + into new buttons. Although note: still very much a work in progress. + + So, looking at this statement: + (around foo bar) + + Here, `around` is a function that takes two buttons and creates a new button. + This new button will, on a press, first press foo, then press bar, and on a + release first release bar, and then foo. Once created, this new button can be + passed to anything in KMonad that expects a button. + + We have already seen other examples of modded buttons, \(, \), *, and +. There + are no Keycodes for these buttons in KMonad, but they are buttons. They simply + evaluate to `(around lsft x)`. All shifted numbers have their corresponding + characters, the same is true for all capitals, and < > : ~ " | { } \_ + and ?. + + To wrap up 'modded-buttons', let's look back at C-A-del. We have 8 variants: + C- : (around lctl X) + A- : (around lalt X) + M- : (around lmet X) + S- : (around lsft X) + + Then RC-, RA-, RM-, and RS- behave exactly the same, except using the + right-modifier. + + These can be combined however you please: + C-A-M-S-x ;; Perfectly valid + C-% ;; Perfectly valid: same as C-S-5 + C-RC-RA-A-M-S-RS-m ;; Sure, but why would you? + + Also, note that although we provide special syntax for certain modifiers, + these buttons are in no way 'special' in KMonad. There is no concept of 'modifier'. + (around a (around b c)) ;; Perfectly valid + + -------------------------------------------------------------------------- |# + +(defalias + + ;; Something useful + cpy C-c + pst C-v + cut C-x + + ;; Something silly + md1 (around a (around b c)) ;; abc + md2 (around a (around lsft b)) ;; aB + md3 C-A-M-S-l + md4 (around % b) ;; BEWARE: %B, not %b, do you see why? +) + +#| -------------------------------------------------------------------------- + Optional: sticky keys + + KMonad also support so called "sticky keys". These are keys that will + behave as if they were pressed after just tapping them. This behaviour + wears off after the next button is pressed, which makes them ideal for + things like a quick control or shift. For example, tapping a sticky and + then pressing `abc' will result in `Abc'. + + You can create these keys with the `sticky-key' keyword: + + (defalias + slc (sticky-key 500 lctl)) + + The number after `sticky-key' is the timeout you want, in milliseconds. If + a key is tapped and that time has passed, it won't act like it's pressed + down when we receive the next keypress. + + It is also possible to combine sticky keys. For example, to + get a sticky shift+control you can do + + (defalias + ssc (around + (sticky-key 500 lsft) + (sticky-key 500 lctl))) + + -------------------------------------------------------------------------- |# + +;; Let's make both shift keys sticky +(defalias + sl (sticky-key 300 lsft) + sr (sticky-key 300 rsft)) + + +;; Now we define the 'tst' button as opening and closing a bunch of layers at +;; the same time. If you understand why this works, you're starting to grok +;; KMonad. +;; +;; Explanation: we define a bunch of testing-layers with buttons to illustrate +;; the various options in KMonad. Each of these layers makes sure to have its +;; buttons not overlap with the buttons from the other layers, and specifies all +;; its other buttons as transparent. When we use the nested `around` statement, +;; whenever we push the button linked to '@tst' (check `qwerty` layer, we bind +;; it to `rctl`), any button we press when holding `rctl` will be pressed in the +;; context of those 4 layers overlayed on the stack. When we release `rctl`, all +;; these layers will be popped again. +(defalias tst (around (layer-toggle macro-test) + (around (layer-toggle layer-test) + (around (layer-toggle around-next-test) + (around (layer-toggle command-test) + (layer-toggle modded-test)))))) + +(deflayer modded-test + _ _ _ _ _ _ _ _ _ _ _ _ _ _ + _ _ @md4 _ _ _ _ _ _ _ _ _ _ _ + _ _ @md1 @md2 @md3 _ _ _ _ _ _ _ _ + _ _ @cut @cpy @pst _ _ _ _ _ _ _ + _ _ _ _ _ _ _ _ +) + +#| -------------------------------------------------------------------------- + Optional: tap-macros + + Let's look at a button we haven't seen yet, tap-macros. + + `tap-macro` is a function that takes an arbitrary number of buttons and + returns a new button. When this new button is pressed it rapidly taps all its + stored buttons in quick succesion except for its last button, which it only + presses. This last button gets released when the `tap-macro` gets released. + + There are two ways to define a `tap-macro`, using the `tap-macro` function + directly, or through the #() syntactic sugar. Both evaluate to exactly the + same button. + + (tap-macro K M o n a d) + #(K M o n a d) + + If you are going to use a `tap-macro` to perform a sequence of actions inside + some program you probably want to include short pauses between inputs to give + the program time to register all the key-presses. Therefore we also provide + the 'pause' function, which simply pauses processing for a certain amount of + milliseconds. Pauses can be created like this: + + (pause 20) + P20 + + You can also pause between each key stroke by specifying the `:delay' keyword, + as well as a time in ms, at the end of a `tap-macro': + + (tap-macro K M o n a d :delay 5) + #(K M o n a d :delay 5) + + The above would be equivalent to e.g. + + (tap-macro K P5 M P5 o P5 n P5 a P5 d) + + The `tap-macro-release` is like `tap-macro`, except that it + waits to press the last button when the `tap-macro-release` + gets released. It might be useful when combined with a + footswitch that sends keyboard scan codes. + + (tap-macro-release i K M o n a d esc) + + WARNING: DO NOT STORE YOUR PASSWORDS IN PLAIN TEXT OR IN YOUR KEYBOARD + + I know it might be tempting to store your password as a macro, but there are 2 + huge risks: + 1. You accidentally leak your config and expose your password + 2. Anyone who knows about the button can get clear-text representation of your + password with any text editor, shell, or text-input field. + + Support for triggering shell commands directly from KMonad is described in the + command buttons section below. + + This concludes this public service announcement. + + -------------------------------------------------------------------------- |# + +(defalias + mc1 #(K M o n a d) + mc2 #(C-c P50 A-tab P50 C-v) ;; Careful, this might do something + mc3 #(P200 h P150 4 P100 > < P50 > < P20 0 r z 1 ! 1 ! !) + mc4 (tap-macro a (pause 50) @md2 (pause 50) c) + mc5 (tap-macro-release esc esc esc) + mc6 #(@mc3 spc @mc3 spc @mc3) +) + +(deflayer macro-test + _ @mc1 @mc2 @mc3 @mc4 @mc5 @mc6 _ _ _ _ _ _ _ + _ _ _ _ _ _ _ _ _ _ _ _ _ _ + _ _ _ _ _ _ _ _ _ _ _ _ _ + _ _ _ _ _ _ _ _ _ _ _ _ + _ _ _ _ _ _ _ _ +) + + +#| -------------------------------------------------------------------------- + Optional: layer manipulation + + You have already seen the basics of layer-manipulation. The `layer-toggle` + button. This button adds a layer to the top of KMonad's layer stack when + pressed, and removes it again when released. There are a number of other ways + to manipulate the layer stack, some safer than others. Let's go through all of + them from safest to least safe: + + `layer-toggle` works as described before, 2 things to note: + 1. If you are confused or worried about pressing a key, changing layers, and + then releasing a key and this causing issues: don't be. KMonad handles + presses and releases in very different ways. Presses get passed directly to + the stacked keymap as previously described. When a KMonad button has its + press-action triggered, it then registers a callback that will catch its + own release before we ever touch the keymap. This guarantees that the + button triggered by the press of X *will be* the button whose release is + triggered by the release of X (the release of X might trigger other things + as well, but that is besides the point.) + 2. If `layer-toggle` can only ever add and then necessarily remove 1 layer + from the stack, then it will never cause a permanent change, and is + perfectly safe. + + `layer-delay`, once pressed, temporarily switches to some layer for some + milliseconds. Just like `layer-toggle` this will never permanently mess-up the + layer stack. This button was initially implemented to provide some + 'leader-key' style behavior. Although I think in the future better solutions + will be available. For now this will temporarily add a layer to the top of the + stack: + (layer-delay 500 my-layer) + + `layer-next`, once pressed, primes KMonad to handle the next press from some + arbitrary layer. This aims to fill the same usecase as `layer-delay`: the + beginnings of 'leader-key' style behavior. I think this whole button will get + deleted soon, because the more general `around-next` now exists (see below) + and this is nothing more than: + (around-next (layer-toggle layer-name)) + Until then though, use `layer-next` like this: + (layer-next layer-name) + + `layer-switch`: change the base-layer of KMonad. As described at the top of + this document, the first `deflayer` statement is the layer that is active when + KMonad starts. Since `layer-toggle` can only ever add on and remove from the + top of that, it can never change the base-layer. The following button will + unregister the bottom-most layer of the keymap, and replace it with another + layer. + (layer-switch my-layer) + + This is where things start getting potentially dangerous (i.e. get KMonad into + an unusuable state until a restart has occured). It is perfectly possible to + switch into a layer that you can never get out of. Or worse, you could + theoretically have a layer full of only `XX`s and switch into that, rendering + your keyboard unuseable until you somehow manage to kill KMonad (without using + your keyboard). + + However, when handled well, `layer-switch` is very useful, letting you switch + between 'modes' for your keyboard. I have a tiny keyboard with a weird keymap, + but I switch into a simple 'qwerty' keymap shifted 1 button to the right for + gaming. Just make sure that any 'mode' you switch into has a button that + allows you to switch back out of the 'mode' (or content yourself restarting + KMonad somehow). + + `layer-add` and `layer-rem`. This is where you can very quickly cause yourself + a big headache. Originally I didn't expose these operations, but someone + wanted to use them, and I am not one to deny someone else a chainsaw. As the + names might give away: + (layer-add name) ;; Add a layer to the top of the stack + (layer-rem name) ;; Remove a layer by name (noop if no such layer) + + To use `layer-add` and `layer-rem` well, you should take a moment to think + about how to create a layout that will prevent you from getting into + situations where you enter a key-configuration you cannot get out of again. + These two operations together, however, are very useful for activating a + permanent overlay for a while. This technique is illustrated in the tap-hold + overlay a bit further down. + + + -------------------------------------------------------------------------- |# + +(defalias + + yah (layer-toggle asking-for-trouble) ;; Completely safe + nah (layer-add asking-for-trouble) ;; Completely unsafe + + ld1 (layer-delay 500 numbers) ;; One way to get a leader-key + ld2 (layer-next numbers) ;; Another way to get a leader key + + ;; NOTE, this is safe because both `qwerty` and `colemak` contain the `@tst` + ;; button which will get us to the `layer-test` layer, which itself contains + ;; both `@qwe` and `@col`. + qwe (layer-switch qwerty) ;; Set qwerty as the base layer + col (layer-switch colemak) ;; Set colemak as the base layer +) +(deflayer layer-test + @qwe _ _ _ _ _ _ _ _ _ _ @add _ @nah + @col _ _ _ _ _ _ _ _ _ _ _ _ @yah + _ _ _ _ _ _ _ _ _ _ _ _ _ + _ _ _ _ _ _ _ _ _ @ld1 @ld2 _ + _ _ _ _ _ _ _ _ +) + +;; Exactly like qwerty, but with the letters switched around +(deflayer colemak + grv 1 2 3 4 5 6 7 8 9 0 - = bspc + tab q w f p g j l u y ; [ ] \ + @xcp a r s t d h n e i o ' ret + @sl z x c v b k m , . / @sr + lctl @num lalt spc ralt rmet @sym @tst +) + +(defalias lol #(: - D)) + +;; Contrived example +(deflayer asking-for-trouble + @lol @lol @lol @lol @lol @lol @lol @lol @lol @lol @lol @lol @lol @lol + @lol @lol @lol @lol @lol @lol @lol @lol @lol @lol @lol @lol @lol @lol + @lol @lol @lol @lol @lol @lol @lol @lol @lol @lol @lol @lol @lol + @lol @lol @lol @lol @lol @lol @lol @lol @lol @lol @lol @lol + @lol @lol @lol @lol @lol @lol @lol @lol +) + +;; One way to safely use layer-add and layer-rem: the button bound to layer-add +;; is the same button bound to layer-rem in the layer that `add` adds to the +;; stack. I.e., it becomes impossible to add or remove multiple copies of a +;; layer. +(defalias + add (layer-add multi-overlay) ;; multi-overlay is defined in the next + rem (layer-rem multi-overlay) ;; section below this + ) + +#| -------------------------------------------------------------------------- + Optional: Multi-use buttons + + Perhaps one of the most useful features of KMonad, where a lot of work has + gone into, but also an area with many buttons that are ever so slightly + different. The naming and structuring of these buttons might change sometime + soon, but for now, this is what there is. + + For the next section being able to talk about examples is going to be handy, + so consider the following scenario and mini-language that will be the same + between scenarios. + - We have some button `foo` that will be different between scenarios + - `foo` is bound to 'Esc' on the input keyboard + - the letters a s d f are bound to themselves + - Px signifies the press of button x on the keyboard + - Rx signifies the release of said button + - Tx signifies the sequential and near instantaneous press and release of x + - 100 signifies 100ms pass + + So for example: + Tesc Ta: + tap of 'Esc' (triggering `foo`), tap of 'a' triggering `a` + Pesc 100 Ta Tb Resc: + press of 'Esc', 100ms pause, tap of 'a', tap of 'b', release of 'Esc' + + The `tap-next` button takes 2 buttons, one for tapping, one for holding, and + combines them into a single button. When pressed, if the next event is its own + release, we tap the 'tapping' button. In all other cases we first press the + 'holding' button then we handle the event. Then when the `tap-next` gets + released, we release the 'holding' button. + + So, using our mini-language, we set foo to: + (tap-next x lsft) + Then: + Tesc -> x + Tesc Ta -> xa + Pesc Ta Resc -> A + Pesc Ta Tr Resc -> AR + + The `tap-hold` button is very similar to `tap-next` (a theme, trust me). The + difference lies in how the decision is made whether to tap or hold. A + `tap-hold` waits for a particular timeout, if the `tap-hold` is released + anywhere before that moment we execute a tap immediately. If the timeout + occurs and the `tap-hold` is still held, we switch to holding mode. + + The additional feature of a `tap-hold` is that it pauses event-processing + until it makes its decision and then rolls back processing when the decision + has been made. + + So, again with the mini-language, we set foo to: + (tap-hold 200 x lsft) ;; Like tap-next, but with a 200ms timeout + Then: + Tesc -> x + Tesc Ta -> xa + Pesc 300 a -> A (the moment you press a) + Pesc a 300 -> A (after 200 ms) + Pesc a 100 Resc -> xa (both happening immediately on Resc) + + The `tap-hold-next` button is a combination of the previous 2. Essentially, + think of it as a `tap-next` button, but it also switches to held after a + period of time. This is useful, because if you have a (tap-next ret ctl) for + example, and you press it thinking you want to press C-v, but then you change + your mind, you now cannot release the button without triggering a 'ret', that + you then have to backspace. With the `tap-hold-next` button, you simply + outwait the delay, and you're good. I see no benefit of `tap-next` over + `tap-hold-next` with a decent timeout value. + + You can use the `:timeout-button` keyword to specify a button other than the + hold button which should be held when the timeout expires. For example, we + can construct a button which types one x when tapped, multiple x's when held, + and yet still acts as shift when another button is pressed before the timeout + expires. So, using the minilanguage and foo as: + (tap-hold-next 200 x lsft :timeout-button x) + Then: + Tesc -> Tx + Pesc 100 a -> A (the moment you press a) + Pesc 5000 Resc -> xxxxxxx (some number of auto-repeated x's) + + Note that KMonad does not itself auto-repeat the key. In this last example, + KMonad emits 200 Px 4800 Rx, and the operating system's auto-repeat feature, + if any, emits multiple x's because it sees that the x key is held for 4800 ms. + + The `tap-next-release` is like `tap-next`, except it decides whether to tap or + hold based on the next release of a key that was *not* pressed before us. This + also performs rollback like `tap-hold`. So, using the minilanguage and foo as: + (tap-next-release x lsft) + Then: + Tesc Ta -> xa + Pa Pesc Ra Resc -> ax (because 'a' was already pressed when we started, so + foo decides it is tapping) + Pesc Pa Resc Ra -> xa (because the first release we encounter is of esc) + Pesc Ta Resc -> A (because a was pressed *and* released after we started, + so foo decides it is holding) + + `tap-next-press` is also a lot like `tap-next`, but decides whether to tap or + hold based on whether another key is pressed before this one is released. + Using the minilanguage: + (tap-next-press x lsft) + Then: + Tesc Ta -> xa + Pa Pesc Ra Resc -> ax (because esc is released before another key is pressed) + Pesc Pa Resc Ra -> A (because a is pressed before esc is released) + Pesc Ta Resc -> A (a is pressed before esc is released here as well) + + These increasingly stranger buttons are, I think, coming from the stubborn + drive of some of my more eccentric (and I mean that in the most positive way) + users to make typing with modifiers on the home-row more comfortable. + Especially layouts that encourage a lot of rolling motions are nicer to use + with the `release` style buttons. + + The `tap-hold-next-release` (notice a trend?) is just like `tap-next-release`, + but it comes with an additional timeout that, just like `tap-hold-next` will + jump into holding-mode after a timeout. + + I honestly think that `tap-hold-next-release`, although it seems the most + complicated, probably is the most comfortable to use. But I've put all of them + in a testing layer down below, so give them a go and see what is nice. + + -------------------------------------------------------------------------- |# + + +(defalias + xtn (tap-next x lsft) ;; Shift that does 'x' on tap + xth (tap-hold 400 x lsft) ;; Long delay for easier testing + thn (tap-hold-next 400 x lsft) + tnr (tap-next-release x lsft) + tnp (tap-next-press x lsft) + tnh (tap-hold-next-release 2000 x lsft) + + ;; Used it the colemak layer + xcp (tap-hold-next 400 esc ctl) +) + +;; Some of the buttons used here are defined in the next section +(deflayer multi-overlay + @mt _ _ _ _ _ _ _ _ _ _ _ @rem _ + _ _ _ _ _ _ _ _ _ _ _ _ _ _ + @thn _ _ _ _ _ _ _ _ _ _ _ _ + @xtn _ _ _ _ _ _ _ _ _ _ @xth + @tnr @tnp _ _ _ _ _ @tnh +) + + +#| -------------------------------------------------------------------------- + Optional: Multi-tap + + Besides the tap-hold style buttons there is another multi-use button (with. + only 1 variant, at the moment). The `multi-tap`. + + A `multi-tap` codes for different buttons depending on how often it is tapped. + It is defined by a series of delay |