Linux/WSL config to optimize ergonomics, security, and productivity: vim/neovim, zsh, tmux, i3, emacs, vscode, ipython, jupyter, ranger, fzf, kitty, xkb, selfquant, firejail, systemd, etc

infokiller infokiller Last update: Sep 23, 2022

Public config repo

This repo contains config files (commonly called dotfiles) targeting Linux andWSL. It is my humble attempt to optimize ergonomics, security, and productivity.No doubt that I spent too much time micro-optimizing them, and I still have apsychotic urge to keep improving them. Hopefully, I'll be able to recover oneday.

Feel free to steal anything that seems useful to you. That said, you shouldn'tblindly copy stuff because:

  • I only test this repo on my machines so some things may be catastrophicallybroken for you
  • Some config/scripts rely on git repos I haven't published publicly yet
  • Some bits of my setup is highly optimized for my own taste and you willprobably hate it

In addition, I provide absolutely no backward compatibility guarantees, and Isometimes fully reset the git history and start from scratch (though that willhopefully stop once this repo is more stable).

Specific configs that may be more interesting for you: vim, tmux, zsh, vscode,ipython, ranger, i3, bash, and probably others I forgot.

Coding guidelines


  • Don't split large files just for the sake of organization: it's usually betterto do the organization within the file (using functions, etc). Good reasonsfor splitting files include:
    • There are use cases that require only using part of the file. For example,my shell configuration has separate files for defining functions and aliases( and for terminal settings (, since I have ause case where only the former is needed (parsing shell aliases fromIPython). In this case, using the same file for both would add cognitiveburden when working on the IPython config and make the code uglier withconditionals.
    • Modularization and controlling internal dependencies. For example, if alarge part of a file contains one public function that's used by otherparts, and many private utility functions that are used only forimplementing this public function, separating this public function and allits dependencies into a separate file can clarify the dependencies andreduce cognitive load.
    • Editors start crawling. As of 2020-05-06, I ran into issues with my vimconfig in files that have more than 1000 lines. It seems that vim pluginauthors don't test or care about performance in these files much, and thesituation may be similar in other editors.
  • Lazy load and/or async load as much as possible to make startup time fast.
  • Try to use native configuration facilities (conditionals, etc) for settingsthat differ between hosts. Resort to separate files only if necessary.
  • Prefer Python over Bash for complex scripts (general rule of thumb: more than100 LOC).
  • Don't use Python for tools that should launch fast (less than 100ms). PreferGo in this case. For example,i3-workspace-groups waswritten in Python, which causes some operations to have noticeable latency.
  • Code copied from an external source should have a comment with a URL to thesource.
  • Directories that may contain python code should be named with underscores andnot dashes, because python can't import from directories with underscores.
  • Executable files should be named using dashes to separate words, notunderscores, i.e. my-tool and not my_tool. They should also have no fileextension.
  • Importable files (Python or bash libraries, for example) should be named usingunderscores and have a file extension (.sh for shell scripts, .py forPython, etc.).


I roughly followGoogle's style guidewith the following additions:

  1. "Constants" should be named LIKE_THIS ("constants" is quoted because therearen't enforced constants in vim, this is only a convention).
  2. There's no need to define a addon-info.json for plugins since it's rarelyused by plugins.
  3. There's no need to put commands, mappings, and autocommands in separatefiles, since I don't see any benefit in doing so.

Shell: Bash and Zsh

Many scripts in this repo are written in bash and zsh. In order to make the codeeasier to manage, I try to follow theGoogle Style Guide alongwith the following additions:

  1. Bash scripts start with a #!/usr/bin/env bash shebang.

  2. Functions that are private to the script and are not intended to be exportedshould have a leading underscore, for example _my_func. Functions that areexported from a script should never have a leading underscore, (i.e.my_func, not _my_func).

  3. printf '%s\n' "${var}" is preferred over echo "${var}" because the lattercan interpret escape sequences (such as \b). However, printing stringliterals with not special chars is fine and shorter (echo 'message').

  4. All scripts should pass shellcheck with no warnings or errors.

  5. Single quotes are preferred over double quotes when substitution is not used.

  6. Functions should not use the function keyword and should generally useunderscores to separate words, unless they're interactive shell functionsthat are expected to be extracted to their own executable, in which case theycan use dashes.

  7. "Library scripts" (intended to be sourced from other scripts) should alwaysuse underscores in the filenames and end with a .sh filename extension,while "executable scripts" should always use dashes and without a filenameextension.

  8. Files are structured as following:

    1. Shebang line (if the script is executable)
    2. Script documentation, separated from the shebang with an empty line
    3. Setting error handling options
    4. Setting ${REPO_ROOT} and other constants
    5. Sourcing other scripts
    6. Defining functions
    7. Defining a main function
    8. Calling main


    #!/usr/bin/env bash## This script does XYZ. Usage:#   my_script <arg> [opt_arg]# See -o errexit -o errtrace -o nounset -o pipefail# shellcheck disable=SC2155readonly REPO_ROOT="$([[ ${CONFIG_GET_ROOT:-0} == 1 ]] && config-repo-root "${BASH_SOURCE[0]}" || echo "${HOME}")"readonly OTHER_CONST=3# shellcheck source=../../.my_scripts/lib/base.shsource -- "${REPO_ROOT}/.my_scripts/lib/"_private_func() {  echo 'This is a private function'}main() {  printf 'Called main with args: %s\n' "$*"}main "$@"

Note that old scripts may not conform to this style yet.

Subscribe to our newsletter