Skip to content


Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?

Latest commit


Git stats


Failed to load latest commit information.
Latest commit message
Commit time


These are my dotfiles. If you are interested in keyboard-based programs (tui, cli, vim-inspired programs, emacs, etc.), keyboard ergonomics, Colemak, etc., this repo may be of some use. Most newer config files are consistently formatted (org-style headings/outline) and well-commented. However, the state of this repository is generally not up-to-date with my actual configuration, older config files may be a mess, and my actual configuration may have bugs, organization issues, or only work with a specific version of the relevant program (e.g. I’ve had alter my bspwm configuration for most updates), so I’d advise against copying anything without first testing it. I move any scripts that become significant/generally useful from my dotfiles into their own repos (e.g. general.el and tdrop). That said, if you have any comments, questions, or suggestions regarding this repo, feel free to make an issue.

Other Notes

I have some notes on software related to aesthetics (e.g. picom and conky) here. Here are some notes on browser-related software (e.g. pentadactyl and vimperator). I’ll eventually add my notes on vim, emacs, and text editing here and my notes on keyboards, keyboard layouts, and keybindings/remappings here.

Also see my blog if you’re interested.

Some resources from others:

Table of Contents



See aesthetics/ for more info on theming, panels, etc.



Workflow Summary

The goals for my workflow are to achieve speed and efficiency, cut wasted time and movement, and eliminate hand, pinky, and wrist pain.

My philosophy when choosing software is to pick customizable, keyboard-friendly programs that are configured in plain text. Setup should be automated. Human-editable configuration files prevent the need to ever configure programs with a mouse/GUI, and keeping these files in a central location allows for better organization and easier backups (which should be performed regularly as well as automatic snapshots).

The most frequently used programs should be opened automatically and bound to a key instead of opened with a launcher. Sessions should be automatically saved and set up. Navigation of any sort (window, file, etc.) should be quick and not get in the way of the task at hand. Time shouldn’t be wasted switching to and using the mouse. Symbols (e.g. parentheses, brackets, and programming operators) and keys like backspace and enter should be remapped or put on a layer based on their frequency of use. Similarly, modifier keys should be re-arranged and put into the most comfortable locations.

Modal editing should be preferred any time non-text-insertion commands/actions are taken consecutively and repeatedly as it saves keypresses and allows for differentiating between different modes or types of actions. Prefix keys, letter chords (e.g. vim-arpeggio and key-chord or dual-role keys), and thumb modifiers (best method when possible) should be preferred for one-off commands/actions (e.g. window management, basic line navigation, pasting at the cursor, deleting the previous word after mistyping a word, etc.). I don’t follow these rules perfectly. I use modifiers for the most frequently used one-off commands but generally use modal prefix keys over modified prefix keys (i.e. when prefix keys become necessary because there are not enough <modifier>+<key> combinations available for some type of action, I prefer modal prefix keys). For example, I use modal keybindings for file/buffer/window/workgroup management keybindings in emacs even though these are one-off actions. Although ESC SPC f is longer than C-SPC f (e.g. for a find-file equivalent), this doesn’t matter too much in practice since I am always in normal state If I am not typing, making the ESC unnecessary. Some may prefer to use modal editing only for consecutive, contextual, and/or composable editing commands and to instead consistently use modifiers regardless of mode/state when prefix keys become necessary to group one-off actions.

The fewest number of keys possible should be used to perform all actions (e.g. more than 2 keys for one-off actions is undesirable), and the most comfortable keys should be used for the most frequently used actions. That said, I think personalization is more important with regards to key sequence length than with to key position. For example, the philosophy of xah-fly-keys is to put the most frequently used commands on the most comfortable key positions. For me this is overkill not because I think this system requires too much memorization but because I think that it is hard to determine which commands should get the best positions (my command frequency has changed drastically over the years). I don’t consider the difference in effort required to press most keys (excluding the worst keys like z and b) to be significant enough to justify this extra work. As a simpler method of choosing keybindings, I prefer using mnemonics so that commands are tied to related letters as opposed to keyboard positions. I do use some positional keybindings but they are all directional (e.g. QWERTY mjkl for directional keys) as opposed to being related to effort.

On the other hand, the positions of letters themselves can be more objectively optimized since there is a limited set of letters and letter/digraph frequency by language (and other statistics) can be more reasonably analyzed (e.g. see some of the reasoning behind Colemak and Colemak Mod-DH). The keyboard and keyboard layout used should ideally limit movement away from the home row (and horizontal movement that requires hand repositioning), eliminate the need for pinky modifiers, and keep wrists straight. This can be achieved by using an ergonomic keyboard and ergonomic keyboard layout with a wide mod (i.e. right hand moved over one or two keys) if necessary. Ideally, a keyboard should be split, vertically staggered, adjustably tented, support hardware remapping (e.g. see qmk and kaleidoscpoe), and have a well positioned thumbcluster. The Keyboardio Model 01 is the only keyboard at the time of writing that meets these requirements well enough for me personally (e.g. the thumbcluster on the ergodox does not look like it would be comfortable to me). In the absence of an ergonomic keyboard, a wide mod can help to keep wrists straight and is also useful for making RAlt more accessible to the thumb. An ISO layout can allow for a wider wide mod. Using the TrackPoint buttons as modifiers on a ThinkPad allows for more thumb modifiers. As for the specific keyboard layout, I don’t think it matters that much as long as it isn’t QWERTY (but please be cautioned about switching keyboard layout). I personally prefer rolls to finger alternation and am not a huge fan of Dvorak, but look at the reasoning behind any layout you are interested in and decide for yourself what you prefer. A long term goal of mine is to learn stenography, but the barrier of entry is high.

On Rodent Extermination (Why the Keyboard? Why Vim?)

I prefer software created with keyboard usage in mind because it is generally more efficient and can help reduce wrist pain (which I used to have problems with). Some general things I look for are as follows:

  • Can be operated entirely with the keyboard
  • Has modality (à la vim)
  • Allows for sequence/multi-key keybindings (à la vim)
  • Has some level of scriptability and the ability to call shell commands

None are these are absolute requirements of course. I’m happy to use a mouse with GIMP or games. However, the keyboard is usually faster for any action that doesn’t involve precise movement or interaction with specific pixels. This is mainly because the keyboard allows for lot more possible actions (through single, combined, and/or sequential keypresses) and because there is no need for precision. Certainly, mice can have a huge number of potential actions if you consider small parts of the screen as separate actions, but a system designed in this way would require inhuman precision and would be unintuitive. The upside of the mouse in the first place is that it allows for a more intuitive user interface. GUIs designed with the mouse in mind use nested menus to prevent taking up too much screen space. Using keys instead of navigating through menus may require some memorization (though software like which-key eliminates the need for that), but it is ultimately far more efficient and can free up screen space as a bonus.

I’ve found the keyboard to be more efficient for pretty much everything, including navigating to an arbitrary character in some text. People seem often to bring this up as case where the mouse is quicker. I’ve tested myself using vim-sneak and evil-snipe and the mouse and found 2-char searching to be significantly faster for me. Furthermore, I don’t generally want to move to a random character, and the keyboard is far more elegant when you want to move by an actual unit like a sentence or paragraph or when you want to do something like jump to a typo or error.

Standard keyboards may generally be poorly designed (QWERTY, horizontal stagger, lack of thumb keys, and poorly placed modifiers), but the mouse is inefficient by design without possibility for improvement (except for making it more like the keyboard by adding more buttons). That’s not to say it’s completely useless or that learning keybindings is always best. Again, I’m fine with using the mouse for lesser-used programs (e.g. GParted) or typing out commands on the command line instead of using keybindings when it makes sense. However, I’ve found that for most simple applications, learning keybindings takes a few minutes (especially if the keybindings are based off vim’s and you already know vim), and for more complicated ones (e.g. the editor), some investment pays off a lot (with regards to both efficiency and possibly wrist pain).

When it comes to modality, I’m not a complete purist either. Modality doesn’t make sense for actions taken in isolation (like deleting one word backwards or moving to the end of the line before continuing to type), and it is not the answer to “Emacs pinky,” RSI, etc. (a better keyboard and/or layout is). Improved ergonomics can be a major benefit if you are using a standard keyboard, but it’s not the main one. Of course, modality doesn’t preclude the use of modifier keybindings, so I use them when it makes sense. That said, I find modality (or just letter keybindings if there is no text entry) makes sense almost everywhere. Modality saves keypresses in any situation where you start executing multiple actions in a row. The downside is the key(s) required for mode switching, but for every new action, you save the need to press a modifier you would have had to press otherwise. This means that when an extra key is required to switch modes, it is quickly made up for. Furthermore, the vim style of having operators, motions, and text objects makes for great composability. Finally, different modes allow for contextual key reuse (e.g. i can be used for text objects in the visual and operator pending modes).

The main exception where I dislike modality is with window managers. You can have modal keybindings with quite a few window managers, and howm even embraces this style by default and provides operators and motions. Since I personally don’t usually take more than one or two window management related actions at a time, I find modality to be extremely inefficient here and stick to thumb-modifier keybindings.

It’s also worth noting that modality isn’t exclusive to vim. Even emacs users who have little interest in vim make use of hydra (the equivalent of sub modes/user created modes in vim) to save keypresses. Org speedkeys (or worf) and lispy could also be seen as “contextually” modal.

As for sequence keybindings, they are vital for programs where any significant number of actions need to be bound. It is unfortunate that many commandline programs do not support them (e.g. every cli feed reader I’ve tried at the time of writing).

Finally, scriptability is almost always nice. I especially love software that is configured in an actual language or in commands that would be valid for that program’s “command line” (e.g. vim, emacs, vimus, and pentadactyl). It’s not even necessary for the program itself to provide the scripting language. For example, bspwm, lemonbar, polybar, etc. can be scripted in essentially any language. In some cases a simple config file will do for me though, especially when keys can be bound to external programs.

On the Unix Philosophy (Why Emacs?)

I have no attachment to the Unix philosophy. I care mainly about practicality and reusability. If you consider emacs as a single, monolithic program, then it completely violates the Unix philospohy. On the other hand, if you consider it to be an ecosystem, there are many individual packages written for it that do one thing well, and they can generally be combined to work well with each other (e.g. ivy, which-key, etc.).

It turns out that, for me, emacs is the best interface for anything text-related from a user and developer standpoint. Standalone programs that aim to be vim-like have to re-implement a modal keybinding system, vim motions, etc., and it’s unlikely that they’ll have advanced functionality like fuzzy searching or text objects or be easily programmable. Every application for emacs gets vim functionality for free with evil. Motions, text objects, and operators are always available for navigating and copying text, and modal keybindings can be used for anything. Even for those who dislike modality, emacs offers programmability and many other useful packages. With ivy (or helm), you can (fuzzy) search the text of any buffer with immediate, visible results. This, of course, applies even if the buffer is not a file on the disk (e.g. an irc buffer or shell/terminal buffer). You can use abbreviations, snippets, autocompletion, etc. anywhere you can type text if you so desire. You can use a package like link-hint to copy or open links, buttons, file paths, etc. using the home row. Packages like avy, hydra, ivy, and evil can be useful even when you’re not editing text but instead reading your mail or communicating on irc or jabber. If you choose to have emacs be your mail client, irc client, mpd client, feed reader, man page viewer, etc., you have a whole ecosystem of functionality that would not otherwise be available.

So the main reason that I use emacs is that, to me, it has the most generally useful text-manipulation libraries (e.g. evil, avy, ivy, etc.) as well as the most and best text-based applications (e.g. mu4e/notmuch/gnus, dired, erc/circe, nov.el, etc.) out of any program in existence. I think it unlikely that any program will catch up to emacs even with regards to just editing (ignoring vim itself, although I prefer emacs’ packages and evil). The other reason I prefer emacs is because of its extensibility and basic design. While emacs lisp is lacking compared to other lisps, there is no existing editor configuration language that I would prefer to emacs lisp, and there is no primary configuration language that I dislike more than vimscript. There are also various design decisions in emacs that I prefer (e.g. emacs’ hierarchical lookup for various keymaps vs. having to use buffer-local keybindings for everything). While there are a lot of design principles from other editors I wish emacs had like “Incredibly high performance” and reliability (see Xi), none of these editors come close in terms of functionality, and functionality is king.

Some people scoff at the idea of running a terminal in a text editor, but terminals’ text editing capabilities are pitiful, and using emacs or vim to, for example, edit the current input requires extra keypresses. Certainly, there are some general ways to get some of the useful functionality I mentioned without re-implementing it across programs. Terminal programs are often keyboard friendly. Consider the vim navigation mode for scrollback and copying provided by some terminals. Tmux’s copy mode allows for using vim keys for navigation regardless of the terminal. There are plenty of ways to do “link-hinting” for terminal programs. Zsh has text objects builtin now. You can integrate fasd and fzf with a lot of terminal applications (like ranger). Still, none of this comes close to the functionality available in emacs. How may tui applications provide customizable keys for navigation and copying on par with vim? There are no non-editor programs that do. Tmux’s copy mode is not all that efficient, especially when compared to navigating text with more advanced vim motions and avy (compare to sneak or easymotion). Many tui applications don’t even support sequence keybindings. Link-hinting in terminals is often error prone (e.g. for urls split across lines) and lacks customizability (e.g. one must use numbers for termite’s link opening functionality). For this reason, I’m actually using emacs to do this even when opening urls outside of emacs. Integration with fzf is usually limited to actions on files or directories. On the other hand, many applications in emacs have good integration with helm and ivy. For example, you can use helm to search your emails, add to your mpd playlist, or to switch to an irc channel you have open.

Also consider that emacs has an advantage over most tui programs in that it can nicely display formatted text and images. This isn’t to say that I think emacs is always the best for any type of application. I’d never use it as my primary image viewer or browser (unfortunately emacs is far from the perfect ecosystem for everything), but there are some things it does unexpectedly well. Using eww can be great for reading html, and though I was skeptical at first, I’ve found myself liking pdf-tools and nov.el more than zathura in some cases. Being able to use bookmarks or helm/ivy to get to recently viewed pdfs is great. Unfortunately, pdfs in emacs aren’t text, so you don’t get all the features you would get otherwise. There are useful commands like pdf-occur though, and the outline menu can help with navigation. While you can’t use vim keys to copy text directly, you can open a buffer with the text from the current page iserted and use evil to copy what you want there. In zathura and apvlv, there currently isn’t any way at all to use the keyboard to copy text.

The only slight disadvantage I’ve found of using emacs for these types of applications is that things may not look as good. For example, while I think emacs’ irc clients look pretty good, I doubt they’ll ever look anywhere as good as a riced weechat or irssi. Mingus looks ugly compared to ncmpcpp. Mu4e doesn’t look as good as mutt in my opinion. The same goes for elfeed when compared to newsbeuter or canto. For most of these, emacs version’s UI is more minimal too, which some may prefer. I care more about functionality, so this doesn’t really bother me.

What Exactly Can Emacs Replace?

Emacs has applications for almost everything, and they are often better than cli equivalents (even ignoring the fact that you get vim selection/search and the functionality from dozens of other packages such as ivy/helm, avy, and various evil extension packages automatically in every single application). Here are some examples for popular types software (the vast majority of which will work in terminal emacs):

emailmu4e or notmuch.el or gnus (or wanderlust, etc.) with isync and msmtp
file managementdired (possibly with ranger.el) and wdired
pdf viewerpdf-tools
epub viewernove.el
feed readerelfeed
musicemms, bongo, or mpd with mingus, simple-mpc, mpdel, etc.
browsereww or emacs-w3m
irc/chatjabber and erc or circe or rcirc
todo managementorg possibly with something like org-journal
bookmarksorg possibly with something like org-board
calenderorg and calfw (google calender integration possible)
password managementemacs integration comes with pass/password-store; there are other packages
(emacs) notificationssauron
search/fuzzy finderivy/counsel, helm, or ido and flx
terminal/shellansi-term or emacs-libvterm or eshell
replsemacs has direct repl integration (e.g. generally using comint)

You can find a lot more if you have more specific needs. There are also mixers, support for emms (or externally with mpd), an application for transmission, one for browsing stack overflow, at least one for twitter, one for reddit, applications for package management with the aur, nix, and guix, etc. While not relevant to commandline usage, emacs supports viewing images.

These applications are generally better than cli, tui, and gui equivalents in terms of functionality and keyboard efficiency. That said, I still prefer ranger and use transmission from the commandline with just a few simple aliases for the moment. I will continue to use rofi, dunst, etc., and will probably end up using buku for bookmarks. I still use zathura for now, and will probably never use emacs as an dedicated image viewer or web browser. That said, for anything primarily text based (with some images thrown in here and there), emacs is generally the way to go in my opinion.


Here I’ve organized my thoughts from trying from trying out and choosing various programs. Arrows indicate switching primary program.

distroUbuntu->Mint->Arch (have tried NixOS but no plans to switch)
config management/setupbash+SaltStack+stow->bash+stow
arch package managerpacman+(pacnanny -> –newsonupgrade)+(yaourt->pacaur->trizen->yay->paru)
universal package managernix
Emacs package managerpackage.el->straight.el
vim plugin managerneobundle->dein->minpac->packages.nvim->lazy.nvim
shell plugin managerantigen->antigen-hs->zgen->zplug->zinit (formerly “zplugin”)
tmux plugin managertpm
boot loaderGRUB->rEFInd
display managernone
window managereverything(incl. awesome and xmonad)->bspwm->herbstluftwm
hotkey daemonsxhkd and xchainkeys
old remappingxmodmap->klfc (to generate mainly XKB configs); kmonad as backup and on other OS
remapping-> kanata
screen lockerslimlock->i3lock-color+multilockscreen(now betterlockscreen)
text editornotepad++->gedit->sublime->vim->Emacs (tried all vim alts)
shellbash->zsh (fish is fine too; eshell occasionally, e.g. with TRAMP)
network manageriwctl+connman
old terminal emulatorsgnome-terminal->xfce4-terminal->guake->URxvt->termite
terminal emulator->xst->kitty+tdrop+tmux->tdrop+wezterm and Emacs vterm
terminal multiplexortmux->wezterm
launcherdmenu->bemenu->rofi (just to launch rarely used gui programs)
wallpaper settereverything->setroot
file managerranger and Emacs+dired/dirvish (very little ranger now, dirvish is amazing)
mass renamingranger’s :bulkrename and wdired
browserchromium->firefox+pentadactyl->qutebrowser->firefox+tridactyl (nyxt next decade?)
password managerpass->?->pass+pass.el
image viewereverything (mainly feh and sxiv)->pqiv->mpv
media playervlc/mplayer->mpv
mail sendingmsmtp
mail fetchingofflineimap->isync
mail clientmutt+abook+notmuch->Emacs+mu4e->phone->phone+mu4e
news readercanto->Emacs+elfeed->nothing->gnus (for large volumes of mail/news)
irc clientweechat->Emacs+circe->nothing (don’t really use irc anymore)
matrix clientelement and ement.el
pdf viewerapvlv->Emacs+pdf-tools and zathura
musicclementine/a lot->mpd+(ncmpcpp->vimus->mingus)->spotify->spotify and mopidy+Emacs
cd rippingabcde
music taggingbeets
backuprsync->borg->borg and restic for larger backups
Emacs searching/filteringhelm->ivy+flx->selectrum/prescient/orderless/embark/consult/marginalia and ivy
Emacs searching/filtering->vertico (instead of selectrum/prescient)
Terminal searching/filteringfzf
Vim searching/filteringunite->denite->telescope
pagervimpager->nvimpager (used infrequently); woman in Emacs for reading manpages
torrent clienttransmission
video recordingffmpeg+slop
audio/video conversionffmpeg
torrent clienttransmission
taggingtmsu (don’t really use)
download manageraria2c (haven’t tried saldl)
calendarEmacs+org+calfw (don’t really use)
language inputscim->ibus->fcitx
typesettinghave only tried LaTeX (and groff I guess)
fontsMainly Delugia, sometimes Office Code Pro, uushi, siji, one billion others
nvidia GPU managementbumblebee->nvidia-xrun->optimus-manager->nvidia-xrun->optimus-manager
process manager/viewerhtop->Emacs+proced

OS and Package Managers

I started out using debian-based distros but quickly switched to Arch mainly for the minimal base installation, pacman, the aur, the wiki, and the rolling-release system. I love that essentially all the software I use is available in the aur (though I like that a good portion of my aur-only packages are in the official nix repos better). On the other hand, I hate having to recompile all my aur packages to ensure nothing breaks after a system update. This isn’t always technically necessary if major packages (like gpg) haven’t been updated, but it’s risky not to. This makes me wish that more programs were in the official repos. As for aur helpers, I don’t really have a strong preference. I’m mainly using trizen since pacaur development died; I really like that it asks to retry instead of quitting (e.g. if I leave it alone for a while after it’s done/wrong password). Bauerbill and aura are also interesting. I like that pacaur can be used for both the aur and official repos at once, and I like that aura is run as root from the start like pacman, but I don’t really use any of their advanced functionality.

As for my actual kernel, I’m using linux-ck for bfq and bfs. I’ve found bfq to help to prevent my laptop from freezing as badly during large file transfers. This is less of an issue on my current laptop, but it’s easy enough to CK that I haven’t considered switching back to the default kernel.

I’ve been using nix more and more, and it solves most of the annoyances I have with pacman. Nix is great because it’s a distro-independent package manager that takes a “functional” approach to package management. I really love being able to have multiple versions of packages (and of their dependencies) installed at once. This makes it easy for me to test my emacs packages with multiple versions of emacs (edit: evm does this better). It also means updating something like ncurses or gtk won’t break an older version of a program (different programs can use different versions of a dependency). Having everything under /nix means that nix can be used on any distro without conflicting with any packages installed by another package manager. Nix also gives you a good level of customizability by allowing packages to be compiled with or without certain features, but it also provides binaries if you don’t need to customize a package.

I’ve ended up liking most things about nix a lot more than other package managers, and despite its non-traditional approach, it still makes writing packages fairly simple. To be honest, for the few simple packages I’ve written, it was even more straightforward than writing a PKGBUILD. That said, nix isn’t as polished as pacman. By default, searching for packages is extremely slow (though nox fixes this), and while installing packages isn’t slow, it’s definitely not as fast as using pacman and powerpill. It is also missing some of the packages I use, but that is changing quickly, and anyone can make a pull request to add a package.

I doubt I’ll switch away from Arch for primarily practical reasons (popularity and good support), but I am interested in trying out other distros like CRUX and gentoo. For me the, the most important features of a distro are the package manager, size of the community, level of maturity, and how easily the installation can be scripted (including a minimal installation so uninstalling defaults insn’t necessary). NixOS is exceptional for automated installation. It provides a single central configuration file that replaces the fstab and pretty much all root config files. You can use it to do things like create your user, set your hostname, set your timezone, and install all the packages you use. Changes are saved, so you can rollback to a previous configuration in the bootloader if you break something. This means that NixOS has builtin support for a declarative installation without the need to do almost any manual setup. My first install in virtualbox took about ten minutes using the basic template configuration. You configure your system once and then forget about it; this is how things should be. It’s not too hard to achieve this with scripts on Arch, but the way NixOS does things is much simpler and cleaner.

On the other hand, the way NixOS works makes it harder (or impossible) to manually install software. You can’t just make && make install. Nix doesn’t put programs under /usr/bin or /bin; they go under /nix and are symlinked into ~/.nix-profile/bin. There are a few programs that I need to update frequently (some bug has been fixed or feature added), and while the process to do this on NixOS can be mostly automated, it’s not nearly as simple as updating a package from the aur. This isn’t a big deal, but it could pose a problem for me in the case that I needed to quickly install a package that wasn’t already in the repos. Some other reasons I’m hesitant to switch are the lack of a lot of packages I use, the lack of startx, and the lack of support/popularity (e.g. the documentation/wiki is lacking). The package situation is constantly improving though, and nix has a lot of packages that aren’t even in the official Arch repos. For now, I’m happy to be able to use both nix and pacman.

As for guix, I see it as a less popular (less packages), more restricted (only libre packages are allowed) version of nix. My laptop won’t even work properly with linux-libre, so GuixSD isn’t really an option for me. I might prefer to use scheme over the nix DSL, but the nix DSL is pretty simple and good enough for the task I think (especially considering that a lot of package managers just use bash). I’m not sure what major benefits guix has to the end user. The command names for guix seem more reasonable to me, and it has a nice emacs package. On the other hand, it’s worth noting that nix is on github, whereas the primary way to interact with the guix community is the mailing list. For these reasons, I have to doubt that guix will ever be useful to more than a small niche of people. I still hope to play around with guix and Sheperd (previously dmd) more in the future and would still recommend looking into guix.

Configuration Management/ Installation Automation

Installing Arch manually every time is needlessly tedious. Automation of this process isn’t nearly as nice as on NixOS or GuixSD, but it’s not too hard to write a script to automate installation. The post-installation setup is also a lot more tedious on Arch, especially if you don’t remember what packages you installed and what setup you performed. This is why I prefer declarative configuration. I’m using bash scripts and SaltStack to do every step of the installation and post-installation setup apart from things that have to be manual like partitioning, wifi setup, and creating the user and setting the user password. See ./root/system-install and ./root/post-install for more information. As an alternative, you can generally just copy your entire filesystem instead of doing a new installation (with a few extra steps), but I prefer using scripts so all setup/configuration is explicit.

I use SaltStack for syncing my root configuration files and stow for symlinking configuration files in my home directory. I prefer to keep all my dotfiles under ~/dotfiles since it is less cluttered and means I don’t have to make my home directory a git repository. Stow also allows categorizing dotfiles into directories (e.g. music). I’ve looked at the countless “dotfile managers,” and most of them just make things more complicated (e.g. by requiring every managed config file have an entry) or don’t allow for categorizing dotfiles into different directories. Stow is simple and does everything I need, so I have no intention of switching to something else.

Window Manager

This is probably my most selective pick, considering just how many window managers there are (I’ve tried dozens, many when testing tdrop). After finding out about tiling window managers, I used awesome and xmonad with a DE for a while before switching to using just bspwm. I tried herbstluftwm and i3 as well and like them for mostly the same reasons I like bspwm, but bspwm is by far my favorite. The reason is that while it is extremely simple, it is also extremely scriptable and has a lot of advanced functionality if you need it.

When I was using xmonad and awesome, I knew very little about haskell or lua and had config files full of snippets I didn’t understand just to have basic the functionality I wanted. In contrast, bspwm has a simple, straightforward configuration file and has everything I want out of the box (e.g. highly customizable keybindings). I like that the hotkey daemon is separate (unlike with most window managers) and that all interaction with bspwm is done through a command line program: bspc. This basically makes bspwm scriptable in pretty much any language (though I’ve never needed to use anything other than bash). I don’t use a lot of bspwm’s more advanced functionality (see the man page; it’s capable of a ton), but I do use its query, subscribe, and rule commands a lot. They make doing a lot of things trivial (e.g. automatically taking actions when certain events occur).

I’ve tried exwm, but it is not really for me (see this relevant discussion). I don’t need my WM to do a lot. Bspwm offers more functionality than I need already, and switching to exwm would be entirely downsides for me. Exwm has seen significant improvements, but I’d be more likely to switch to something like stumpwm/paulownia if I really wanted a lisp WM. Key simulation is a not a feature unique to exwm; it’s just built in. I don’t need ivy/helm for window switching; I use very few windows. Given how often I’ve seen various packages slow/crash emacs, I’m pretty hesitant to use it as a window manager even with a minimal configuration. Many people use it without issues, so this concern is probably unwarranted if exwm is configured sanely.

Hotkey Daemon

Here’s one area where I prefer adherence to the Unix philosophy. I find it kind of annoying that there are so many window managers that implement keybinding functionality independently. I also happen to like sxhkd better than every WM-specific keybinding method I’ve tried. Compared to xbindkeys, it has saner syntax in my opinion and has a lot more functionality. It allows for prefix, modal, and modifier keybindings. That said, deeply nested keybindings were buggy last time I tried them, so I’d recommend xchainkeys as a potential alternative.


See the ./browsing/ README.

Image Viewer

My image manager of choice is pqiv. I was previously using sxiv but never found it to be very convenient/hospitable. Pqiv is a keyboard-focused image viewer like sxiv, but it fixes pretty much everything I disliked about sxiv. Unlike sxiv, it has an actual config file that’s read at runtime. You can bind shell commands to any key directly in the config file, whereas in sxiv you can only have one external key-handler used with a prefix key. For this reason, I’d previously been using a fork of sxiv with ugly, duplicated code to add more key-handlers. Pqiv is also the only image viewer I’m aware of that has vim-like sequence key bindings. It allows for binding keys to multiple commands and even allows for cycling the behavior of keys. This means you can implement something like a 4-corner cycle for reading comics directly in the config file. Speaking of comics, it supports viewing images in archives (e.g. cbz). It’s even scriptable, and you can send commands to a running instance or have it watch a directory and automatically update its image list. It also allows viewing the output of running commands on an image (e.g. imagemagick). Pqiv even supports viewing video and webms if you want to.

Given all this, I think it’s a crime pqiv isn’t more popular. I’d definitely recommend trying it out.

Wallpaper Setter

See the ./aesthetics/ README.

File Manager

Dired can be a good file manager, and I’m using it more, but ranger is far more polished out of the box. I especially love rifle and how well ranger does previews. The only thing that bothers me about it is how slow it can be to load when starting or entering certain directories.

As for mass renaming, there are a ton of solutions (e.g. vidir, wdired, vim-renamer, and tmfan), but they all basically end up involving editing the directory structure in a file. I use ranger’s :bulkrename and emacs’ wdired since they are both builtin and work well.

Pdf Viewer

I mentioned my reasons for liking pdf-tools above. Zathura is also a nice vim-like pdf viewer, but I dislike the lack of tab support (which apvlv does support), especially when I have related pdfs open. Using suckless’ tabbed is awful; it’s not aware of the context of programs and just compare pressing a single key to creating a new tab with some global key like alt+shift+t.

Terminal Emulator

I don’t need much functionality from a terminal emulator. Editors will always do navigation, searching, and selection of text better than terminal emulators, and tmux does it better or just as well than most terminal emulators. Tmux also does splits/tabs better or just as well as most terminal emulators (see here for an alternate opinion on multiplexors from the author of kitty).

Emacs libvterm is good for project work for me. My primary use for a dedicated terminal emulator right now is ranger and just running commands (see my zshrc and scripts). The main thing I want from a terminal emulator is image capability (for ranger image previews), correct/out-of-the-box handling of fonts/icons (unicode support), and correct handling of input (my keyboard layout is supported, copy/paste are builtin, etc.).

Previously, termite and xst were my favorite terminals that meet these requirements, but I’ve since switched to kitty. It has what seems to me the best method for image display among any terminal emulator. Speed, truecolor support, ligature support, and extensibility are all nice bonuses.

That all said, I’d still be mostly fine using another terminal emulator. Kitty ranger image preview doesn’t work in tmux. I’ve been using ueberzug, which works a lot better for me than w3mimgdisplay.

The input issues have been mostly fixed. If you want to use an IME in the terminal, kitty only supports ibus at the time of writing though.

Working On

Major TODO items:

  • Clean up all config files and add them here
  • Clean up and add emacs init file
  • Clean up/remove older bash scripts
  • Fix dual role on keyboardio

Interesting Workflow Excerpts

Make Any Terminal Emulator Dropdown Regardless of WM

I’ve tried to create a much more generalized version of my dropdown script that works well with more window managers and has extra functionality that other dropdowns don’t have. For example, it can automatically resize a dropdown when changing monitors and supports turning any window into a dropdown.

See tdrop and feel free to make an issue if there isn’t already floating support for your wm.

Empty Desktop Keybindings

Why use modifier keys to start a program if there is no active window? I’m using bspc’s subscribe command to monitor for when a desktop becomes empty and then switch to a different sxhkd config. This way, I can start my programs with the home row on empty desktops.

It would also be possible to use a single config file and check for every single key whether the desktop is empty, but this would be uglier, so I haven’t bothered trying it. The approach I’m using doesn’t usually cause problems, and I’ve mostly (completely I think) prevented rapid changes between an empty and non-empty desktop (e.g. dropdown toggling) from resulting in the wrong sxhkd config being loaded. The only annoyance with this is that sxhkd configs can’t source other configs, so I have all the normal keybindings replicated in the new sxhkd config.

See my bspwmrc and the corresponding script.

Use Ranger/Dired Instead of Default GUI Popup for File Saving

Pentadactyl already has :w and ;s, which allow for typing out file paths with tab completion. This is cumbersome especially for deeply nested directories. I used to just use an alias to open ranger in my downloads folder and save there automatically. I found even then that I didn’t always get around to moving stuff, so now I have an autocommand to send the file name on download to a script which will open a floating terminal with ranger running and pass the file location to ranger’s –selectfile and cut it (see dl_move). The script also works with dired which when used with emacsclient can potentially start a lot faster than ranger. Qutebrowser doesn’t currently have a way to replicate this autocommand, but you can use a script to open the most recent download.

See this post for more detailed information and other possibilities.

I’ve found that pentadactyl’s upload file: prompt that appears when you hint an upload link to be nice but not a universal solution for uploads (i.e. this doesn’t work for every website). Right now, I do image uploads and mail attachment from the commandline/ranger (see ranger_functions). When I have to use the upload gui I often paste in file locations after copying them in ranger.

Block Layout in Emacs/Vim and Examples of Context-dependent Keybindings

Using tabs is only useless if you’re trying to use one buffer per tab (in an editor that supports buffers/a bufferline). I use tabs (or workgroups/perspectives/whatever in emacs) as workspaces. I set them up with names so I can see which tab corresponds to which subject and can easily jump to them with <space><home row>. I also use a script that sets up custom keybindings for different tab/workspace names. For example, I use =,= as a prefix key to jump to specific files depending on tab name. I have a general set of these “quickmarks” and specific ones that either correspond to files by frequency of use (=,f=, =,s=, and =,t= for first, second, and third) or by name (e.g. =, r= for readme, =, t= for todo file, etc.).

This drastically reduces the time it takes to get to a specific file as well as the complexity of the keybindings. This is the order of preference for me when it comes to file navigation:

  1. navigate to open buffer or quickmarks (2-4 keys; 2 for right tab/workgroup, maybe 2 for getting correct pane or using a quickmark)
  2. interactive search of open buffers, mru files, current dir, and current project (unite in vim; helm, ivy, projectile, etc. in emacs)
  3. switch from above to search with locate (or maybe ag if searching for by contents) (unite in vim; helm or ivy in emacs)
  4. file manager with quickmarked dirs as last resort (ranger if in terminal; otherwise dired or vimfiler)

On the commandline, I find fasd to usually be the fastest way to get to a specific directory. Previously I was using deer, blscd, or just ranger with bookmarks and f to get places. Enhancd is also worth noting, and fzf is what I would use if I did’t already have a directory in my fasd history. That said, I’m using the commandline a lot less especially for directory-dependent work, so I haven’t needed fzf in a while.

Quickmarks for files are fast, but the less you use a keybinding, the more forgettable it is. I find workspaces that are automatically set up with my most frequently used files and the “f s t” keybindings I previously described to be a nice way to keep both keystrokes and memorization to a minimum. Which-key can also serve as a useful reminder, but even without quickmarks, helm/unite/etc. can be used to very quickly get to pretty much anywhere. I have one key bound to open ivy for open buffers and mru files, and key to switch to searching with locate for the current search. If I’m working in a repo, I use fuzzy searching with ivy and projectile, which is lightning fast.

In vim/emacs, I am using m as a prefix key for whatever major mode/filetype I’m currently in (with M instead used for marks). In org mode, m<keys> performs org mode navigation, clocking, todo, etc. In code files, I use m<keys> to compile or run the current file as well as for repl interaction, error navigation, etc.

As for other, non-vim/emacs examples, I have context bindings for empty vs. non-empty workspaces/desktops. On empty desktops, I have sxhkd automatically restarted with a custom config where single keys are mapped to open programs and switch desktops. Why use more keys than necessary? The transition time to get used to the difference was insignificant, so I don’t think consistency is of any benefit here.

In firefox, I also use the space bar as a prefix key for tab navigation. I bind <space><home row> to a command that will go to tab 1-10 in the curent tab range (e.g. <space>a on tab 24 will go to tab 21). I also have keybindings to switch to specific tab groups and set up a few custom key bindings depending on tab group. I haven’t done much with this though since TabGroupie works very inconsistently (with pentadactyl but not vimperator), and qutebrowser doesn’t have an equivalent of tab broups.

Pentadactyl’s groups (not related to tab groups) are probably the best example for taking advantage of different contexts. I use them to set up site-specific keybindings. For example, on reddit, I pass through keys for use with RES (and userscripts that make keybindings for other websites) and also add custom goto bindings with the prefix g for going to specific subreddits. I use this to set up more convenient zoom bindings on image urls. This also allows setting up custom key bindings for sites that have non-configurable key bindings (e.g. gmail).

The best example I’ve seen of key-reuse is lispy. Org speed keys and worf are also good examples.


Stream Any Video in MPV

Existing solutions for playing videos in the player of your choice (e.g. mplayer or vlc) are limited in what they work with. There are quite a few programs that allow this for a few sites such as youtube and daily motion. Consider youtube-viewer, quvi, and youtube-dl (used by mpv by default), which now supports a large number of popular websites. Still, youtube-dl doesn’t work on a lot of sites I use, and I’m not particularly fond of the mozplugger/viewtube approach either where your player is basically embedded in the browser (even if this worked with all sites).

This is a relatively simple thing to do in actuality. The reason existing solutions are site specific is because they operate based on the site url. Mpv will have no problem playing pretty much any video if you pass it the direct link, so all you need to do is write a script to fetch the link of playing media.

There’s certainly a much better way to do this, but I only know how to get this link manually: you open the browser inspector and go to the network/media tab. When you play the video, the direct link will show up. You can also use the media sniffer firefox plugin (which is short and could probably easily be turned into a pentdactyl plugin). Previously I scripted clicks to automatically start the inspector and open this link, but it became to much of a hassle to use, so I just manually use the inspector at the moment.

Make Gifs/Webms in MPV

I thought it would be efficient to set up bindings within mpv to create gifs. Now that mpv has a-b looping (issue #1241), I’ve gone back to using a script (ffcut) that first cuts part of a video out and then optionally makes a gif from that part. I’ve also fixed ffcut to accurately cut videos by default. The alternative, directly copying sections of the video, is faster but requires starting from a key frame, making the timing inaccurate. These two mpv plugins may be better ways to cut/crop/convert a video, but I personally like ffcut.

The makegif script is just a wrapper for ffmpeg, imagemagick, and optionally gifsicle that takes a video, makes frames from it, and then creates an optimized 600 width 10 fps gif. It has much improved (though it may be annoying as-is to users other than myself due to the default output directory). For example, if the output gif is not satisfactory, one can simply use the frames already created and try different options:

makegif <path/to/video>
# notice that there are some extra frames at the end
# go to the location of the frames and delete a few at the end
makegif -u
# use max optimization with gifsicle and increase fuzz percent
makegif -u -O 3 -z 1.8
# changing fps or width values requires remaking the frames
# (unless you want something sped up/slowed down):
makegif -w 800 -O 3 -f 15 -o mygif.gif <path/to/video>

I also have a makewebm script that behaves similarly.

An example gif with default settings (made within mpv): ./example.gif


Consolidate Bspwm Resizing Keybindings

I never really liked the default way of resizing in bspwm. I prefer to have keybindings do something else in cases where the normal command would fail. I’ve been using the style where the directions “act on the split.” Consider an example where there are only two windows (left and right). If the left window was selected, super + alt + h would shrink the left window on the right and grow the right window on the left (moving the split between them to the left). It would act the same if the right window was selected instead.

I find this behavior more consistent, and it consolidates two sets of keybindings (the default super + alt + {h,j,k,l} and super + alt + shift {h,k,j,l}). Now that bspwm’s resizing command works on both tiled and floating windows, all three types of the resizing keybindings can be combined into one. Using the following script, super + alt + {h,j,k,l} can both have the behavior described above on tiled windows and resize in a direction for floating windows. It might be more useful to actually move a floating window, but I don’t use floating windows that often, so I don’t have a strong opinion here. That would require an extra check to see if the window was floating.

Unfortunately, the resize commands don’t have a non-zero exit status if they don’t do anything, so unlike with the tiled-only solution (see the commented out commands), the width and height need to be explicitly checked to see if they have changed. I’m getting the dimensions from xwininfo, but they could also be gotten from bspc’s query command.

wid=$(xdotool getactivewindow)
wininfo=$(xwininfo -id "$wid")
width=$(echo "$wininfo" | awk '/Width/ {print $2}')
height=$(echo "$wininfo" | awk '/Height/ {print $2}')
case $1 in
		# bspc node @east -r -40 || bspc node @west -r -40
		bspc node -z left -40 0
		if [[ $width == "$(xwininfo -id "$wid" | \
				awk '/Width/ {print $2}')" ]]; then
			bspc node -z right -40 0
		# bspc node @south -r +35 || bspc node @north -r +35
		bspc node -z bottom 0 +35
		if [[ $height == "$(xwininfo -id "$wid" | \
				awk '/Height/ {print $2}')" ]]; then
			bspc node -z top 0 +35
		# bspc node @north -r -35 || bspc node @south -r -35
		bspc node -z top 0 -35
		if [[ $height == "$(xwininfo -id "$wid" | \
				awk '/Height/ {print $2}')" ]]; then
			bspc node -z bottom 0 -35
		# bspc node @west -r +40 || bspc node @east -r +40
		bspc node -z right +40 0
		if [[ $width == "$(xwininfo -id "$wid" | \
				awk '/Width/ {print $2}')" ]]; then
			bspc node -z left +40 0

You can see ./scripts/bin/wm_action for my current version of the script with support for resizing based on a percentage of the screen. Neeasade has also rewriten my script to additionally support resizing window groups

Home Row Window Mangement (Outdated)

Note: This started as something I did for fun, but I’ve actually found it pretty useful, especially for switching desktops. Now I’ve abandoned this method and I see it as a horrible but interesting workaround for a lack of thumbkeys.

For me, window management is pretty much split between tmux and bspwm. Bspwm takes care of all my gui windows (and occasionally a terminal window), and tmux takes care of all my terminal sessions, windows, splits, etc. There is also tab/split management within programs, but that already doesn’t require the use of modifier keys.

The idea of modal window management has interested me, but modal window management isn’t really efficient when most of the time you only execute one wm command (it just requires an extra key for escaping as opposed to using a prefix key). It introduces other problems as well. Escape can’t be used to enter this “window management mode” (with sxhkd this would make escape lose functionality everywhere else). Unlike in vim, “normal mode” would be infrequently entered and immediately exited. Although I am a fan of modality, I do not think having modes within modes does anything other than overcomplicate things. Instead of trying to mirror this functionality, I’ve found it most efficient to eliminate window management as a separate entity and build it in to all my programs just as I would set up the same (or similar) bindings for split navigation for different programs.

My most used gui programs (emacs, gvim, firefox, mpv, apvlv/zathura, and pqiv) all allow for bindings to terminal commands as well as sequence key bindings (thanks to wm4 for implementing this in mpv!) which makes this possible. This probably won’t be as useful for anyone who uses a lot of gui programs, without doing something particularly convulted like using sxhkd as a wrapper for modal keybindings (see below). The difference between pressing super+5 and rd (qwerty “sg”) may not seem to be a big deal, but it’s been quite noticeable to me. As for delay/lag, it should be noted that -ex and not -builtin should be used for pentadactyl keybindings (builtin is much slower and will cause a noticeable delay).

I’ve also made tmux keybindings in all of tui my programs (vim, zsh, less, weechat, ranger, emacs, mutt, tig, w3m, and vimus). The only downside of this is that zsh keybindings obviously won’t work if you have something running (not a problem if you’re running zsh in emacs or vim though!). On the other hand, this isn’t that big of a deal because tmux allows use of a prefix key on a layer (e.g. mine is grave/backquote, which is mode_switch+f for me). Repls can also be run in emacs or vim to keep modal keybindings

Previously I was repurposing r and s as these prefix keys. I’ve switched to just using r, since I didn’t feel that this functionality warranted taking up two home row keys. I’ve started using the wm_action script as a wrapper for my window management keybindings. This is kind of ugly, but it has already allowed me to get rid of some old scripts I was using. For example, I’ve set it up to determine whether mpv is being run in a terminal or not so that bspc or tmux key bindings are used accordingly. I’ve also started binding keys in sxhkd to it instead of directly to bspc, so that I don’t have to use a different sxhkd config for different window managers (I check the window manager in the script). Lastly, I’m using wm_action so that I can change the actions for r in one place instead of 10 and have them work in whatever window manager I’m working with (as long as it supports interaction through the command line like i3, herbstluftwm, and stumpwm do).

I’d also like to try window management with chording or dual-roled keys at some point (pressing qwerty s + {h,j,k,l} simultaneously will do window switching). This gets pretty messy without a universal way of doing chording, and it may just be better/cleaner to do window management with well-placed thumbkeys instead.


Create a Modal Interface for Programs That Don’t Support Rebinding

I’ve pretty much abandoned software that doesn’t support modality and prefix bindings, but this may be a useful hack for users of such software.

There are many programs that have extensive keyboard shortcuts that could potentially be useful if their default bindings weren’t oriented towards masochists. For some programs, the few available shortcuts can still be massively useful when implemented in vim-like modes (e.g. Libre Office). One way to do his is to rebind keys to fake existing keyboad shortcuts. It is worth noting that this isn’t that great of an approach. For example, a better solution exists at least for Libre Office (see vibreoffice). Hopefully embedded vim/neovim will further prevent the need for solutions like this. An alternate possibility is to implement modality for all text boxes on an OS (I think OSX has something like this?).

As an example, I’ve done this with Libre Writer to emulate a normal and visual mode with keys for moving by words, characters, and lines.

Video Demonstration With Libre Writer


This solution is restricted to X currently (though something similar could probably done with AHK). It makes use of xchainkeys for the modal keybindings and xdotool and xsendkey to fake the necessary keyboard input. A potentially “software independent” solution would be to use tmk firmware to make layers with macros and keys for “mode” (layer) switching. I have not been able to test this.

See xchainkeys.examplevimlayer.conf for the example configuration for Libre Writer. Since I’ve started using LaTeX or simple markup instead for the most part, I haven’t done anything else with this, but I think that it would be more desirable to have the modal interface automatically started (setting up and deconstructing keybindings on window change) for the program it is being used for (using bspc –subscribe and awk to run a bash script on window change that checks if the current window is, for example, Libre Office).


Anything I’ve swiped for my config files has a url.

Some general stuff:

Credit to vaskozl for his thread on not using the mouse, which is one of the main reasons I ever took interest in any of this. Credit to DreymaR and lalop for inspiration on layout stuff after I switched to colemak and to bunnfly for the colemak vim config (all from the colemak forum).

Thanks to baskerville/bloom for bspwm and sxhkd. Thanks to kana, Shougo, tpope, junegunn, dhruvasagar, rhysd, etc. for all their awesome vim plugins. Thanks to abo-abo for his awesome emacs packages. Thanks to tuhdo for his great guide on emacs and helm. Thanks to codestation for qcma. Thanks to sol, haasn, etc. for vimus. Thanks to ttzhou for setroot, which solved the problems I’d had with every other wallpaper setter. Thanks to phillipberndt for pqiv, which is a hidden gem and a joy to use/configure (especially compared to sxiv). Thanks to 39aldo39 for klfc which provides a flexible, universal, and understandable format for specifying keyboard layouts; now I never have to use xmodmap (which is annoyingly buggy) again.


Mouseless Workflow (WIP)






No releases published


No packages published