dotfiles
A collection of literate programming dotfiles created and maintained in Emacs with Org mode. The source is available at index.org.1
Table of Contents
- Build Configuration Files
- Bootstrap
- Bash
- Homebrew
- Secrets
- Functions
- 1Password
asdf
- AWS CLI
- bat
- Emacs
- eza
- Gemini CLI
- Ghostty
- Git
- Go
- Google Cloud SDK
kubectl
,k
,kctx
,kns
,krew
- Jujutsu
- nvm
- OCaml
- Playdate
- PostgreSQL
- Python
- Rancher
ripgrep
- Rust
- ShellCheck
- skim
- SSH
- Starship
- terminal-notifier
- Terraform
- Television
- WezTerm
yamllint
~/.inputrc
Build Configuration Files
Open this Org document in Emacs and tangle it (C-c C-v t
). Configuration files, e.g., ~/.bashrc
, will be generated.
Bootstrap
- Install Homebrew
- Install Homebrew Bundle:
brew bundle
Change Default Shell
I prefer bash
over zsh
.
This should be the Homebrew installed bash
not the system bash
path:
eval "$(/opt/homebrew/bin/brew shellenv)" && \ export SHELL="${HOMEBREW_PREFIX}/bin/bash" && \ sudo dscl . -create ${HOME} UserShell ${SHELL} && \ dscl . -read ${HOME} UserShell
Set HOSTNAME
export HOSTNAME='TODO' && \ sudo scutil --set HostName ${HOSTNAME}
Accessibility
defaults write com.apple.Accessibility ReduceMotionEnabled -bool true
Bash
~./bash_profile
header-args: :mkdirp yes :tangle ~/.bash_profile
# shellcheck source=/dev/null source "${HOME}/.bashrc"
~/.bashrc
header-args: :mkdirp yes :tangle ~/.bashrc
Load all configuration:
export K20E_BASHRC_DIR="${HOME}/.bashrc.d" for f in "${K20E_BASHRC_DIR}/"*.bash; do # shellcheck source=/dev/null source "${f}" done unset -v config
Configuration
header-args: :mkdirp yes :tangle ~/.bashrc.d/000-bash.bash
Environment variables:
export LANG=en_US.UTF-8 export HISTSIZE=100000 export HISTCONTROL=ignoredups:erasedups export HISTTIMEFORMAT='%F %T ' export TERM=xterm-256color
Shell options:
shopt -s \ autocd \ cdspell \ checkjobs \ checkwinsize \ dirspell \ histappend \ no_empty_cmd_completion
Base variables that I use to organize the file system:
export K20E_CODE_HOME=${HOME}/code export GOOGLE="${HOME}/Google Drive/My Drive"
CDPATH
:
The
CDPATH
variable sets the search path for the cd command. If you do not specify.
somewhere in the path, it is assumed to be the first component.
export CDPATH="${K20E_CODE_HOME}:${GOOGLE}"
PATH
:
pathmunge () { case ":${PATH}:" in *:"$1":*) ;; *) if [ "$2" = "after" ] ; then PATH=$PATH:$1 else PATH=$1:$PATH fi esac }
pathmunge /usr/local/sbin pathmunge /usr/local/bin pathmunge "${HOME}/.local/bin" pathmunge "${HOME}/bin"
TODO
If these modify PATH
, etc., I should figure out a way to pre/post them with the rest of this setup. For
instance, asdf
tries to shim PATH
here but then gets overwritten later by pathmunge
.
Aliases:
alias ..="cd ../" alias ...="cd ../../" alias ....="cd ../../.." alias dirs="dirs -v" alias r='[ "$(pwd)" != "$(git rev-parse --show-toplevel)" ] && cd "$(git rev-parse --show-toplevel)"' alias tree="tree -C" alias top="top -ocpu -Orsize"
Homebrew
header-args: :mkdirp yes :tangle ~/.bashrc.d/010-brew.bash
if [ -e /opt/homebrew/bin/brew ]; then eval "$(/opt/homebrew/bin/brew shellenv)" export HOMEBREW_CASK_HOME="${HOMEBREW_PREFIX}/Caskroom" export HOMEBREW_CASK_OPTS=--require-sha export HOMEBREW_INSTALL_CLEANUP=1 export HOMEBREW_NO_ANALYTICS=1 export HOMEBREW_NO_ENV_HINTS=1 export HOMEBREW_NO_INSECURE_REDIRECT=1 command -v "${HOMEBREW_PREFIX}/bin/bash" >/dev/null 2>&1 && export SHELL="${HOMEBREW_PREFIX}/bin/bash" fi
Completion:
# shellcheck source=/dev/null [ -e "${HOMEBREW_PREFIX}/etc/profile.d/bash_completion.sh" ] && source "${HOMEBREW_PREFIX}/etc/profile.d/bash_completion.sh"
Homebrew Bundle
Install: brew bundle
if command -v "${HOMEBREW_PREFIX}/bin/bundle" >/dev/null 2>&1; then export HOMEBREW_BREWFILE="${HOME}/.Brewfile" alias k20e_brew_bundle_dump='brew bundle dump --force --global --verbose && pbcopy < $HOMEBREW_BREWFILE' alias k20e_brew_bundle_install="brew bundle --global" fi
~/.Brewfile
header-args: :mkdirp yes :tangle ~/.Brewfile
tap "buo/cask-upgrade" tap "d12frosted/emacs-plus" tap "homebrew/autoupdate" tap "homebrew/command-not-found" tap "homebrew/test-bot" tap "tidbyt/tidbyt" brew "git" brew "asdf" brew "aspell" brew "automake" brew "bash" brew "bash-completion@2" brew "oniguruma" brew "bat" brew "bison" brew "chafa" brew "cmake" brew "dasel" brew "diff-so-fancy" brew "difftastic" brew "dive" brew "eza" brew "fd" brew "libssh" brew "xvid" brew "ffmpeg" brew "flex" brew "flyctl" brew "gawk" brew "gcc" brew "gd" brew "gflags" brew "gh" brew "gnupg" brew "go" brew "gprof2dot" brew "hunspell" brew "shared-mime-info" brew "imagemagick" brew "innoextract" brew "ispell" brew "jj" brew "jq" brew "just" brew "kubernetes-cli" brew "kubectx" brew "less" brew "libdvdcss" brew "libyaml" brew "makedepend" brew "node" brew "opam" brew "parallel" brew "perl" brew "pkgconf" brew "pre-commit" brew "pstree" brew "pv" brew "repo" brew "ripgrep" brew "rocksdb" brew "ruby", link: true brew "rust" brew "scons" brew "sevenzip" brew "shellcheck" brew "sk" brew "starship" brew "subversion" brew "television" brew "terminal-notifier" brew "texi2html" brew "tree" brew "uv" brew "watch" brew "wget" brew "yamllint" brew "yasm" brew "yq" brew "yt-dlp" brew "d12frosted/emacs-plus/emacs-plus@30" brew "tidbyt/tidbyt/pixlet" cask "1password" cask "1password-cli" cask "alfred" cask "alt-tab" cask "betterdisplay" cask "firefox" cask "font-symbols-only-nerd-font" cask "ghostty" cask "google-chrome" cask "google-drive" cask "gzdoom" cask "heroic" cask "istat-menus" cask "lm-studio" cask "mactex-no-gui" cask "orion" cask "qlmarkdown" cask "rancher" cask "rectangle" cask "signal" cask "slack" cask "tomatobar" cask "vanilla" cask "vlc" cask "wezterm" cask "whisky" cask "zed" cask "zoom"
Secrets
header-args: :mkdirp yes :tangle ~/.bashrc.d/011-secrets.bash
Define a directory to keep secret information in. Make sure that it exists in .gitignore-global
.
export K20E_SECRET_HOME="${K20E_BASHRC_DIR}/secret" mkdir -p "${K20E_SECRET_HOME}"
Setup environment, create & source secrets for aliases, functions, PATH
and environment variables:
export K20E_SECRET_ALIASES="${K20E_SECRET_HOME}/aliases.sh" && touch -a "${K20E_SECRET_ALIASES}" # shellcheck source=/dev/null source "${K20E_SECRET_ALIASES}" export K20E_SECRET_FUNCTIONS="${K20E_SECRET_HOME}/functions.sh" && touch -a "${K20E_SECRET_FUNCTIONS}" # shellcheck source=/dev/null source "${K20E_SECRET_FUNCTIONS}" export K20E_SECRET_PATH="${K20E_SECRET_HOME}/path.sh" && touch -a "${K20E_SECRET_PATH}" # shellcheck source=/dev/null source "${K20E_SECRET_PATH}" export K20E_SECRET_VARIABLES="${K20E_SECRET_HOME}/variables.sh" && touch -a "${K20E_SECRET_VARIABLES}" # shellcheck source=/dev/null source "${K20E_SECRET_VARIABLES}"
Adjust permissions.
chmod 0700 "${K20E_SECRET_HOME}" chmod -Rf 0600 "${K20E_SECRET_HOME}"/*
Functions
header-args: :mkdirp yes :tangle ~/.bashrc.d/800-functions.bash
Random functions.
Strip exif information out of images like geoloc data:
function k20e_exif_strip() { local path="$1" if [ ! -e "${path}" ]; then echo "Image at path \"${path}\" does not exist" return fi echo "Before:" echo identify -verbose "${path}" | rg exif mogrify -strip "${path}" echo echo "After:" echo identify -verbose "${path}" | rg exif }
Use jq
to reformat messy JSON files:
function k20e_jqf() { local path="$1" local tmpPath if [ ! -e "${path}" ]; then echo "File at path \"${path}\" does not exist" return fi tmpPath=$(mktemp) cp "${path}" "${tmpPath}" jq . "${tmpPath}" > "${path}" rm "${tmpPath}" }
1Password
header-args: :mkdirp yes :tangle ~/.bashrc.d/501-1password.bash
Generate completion script:
op completion bash > /opt/homebrew/etc/bash_completion.d/op
# shellcheck source=/dev/null [ -e "${HOMEBREW_PREFIX}/etc/bash_completion.d/op" ] && source "${HOMEBREW_PREFIX}/etc/bash_completion.d/op"
asdf
header-args: :mkdirp yes :tangle ~/.bashrc.d/110-asdf.bash
Need to add completion for my silly Dvorak alias. Lookup existing completion function: complete -p asdf
, then add
it below.
alias aoeu='asdf' # shellcheck source=/dev/null [ -e "${HOMEBREW_PREFIX}/opt/asdf/libexec/asdf.sh" ] && source "${HOMEBREW_PREFIX}/opt/asdf/libexec/asdf.sh" && complete -o default -F _asdf aoeu
AWS CLI
header-args: :mkdirp yes :tangle ~/.bashrc.d/440-awscli.bash
export AWS_SDK_LOAD_CONFIG=1 export AWS_VAULT_KEYCHAIN_NAME=login [ -e "${HOMEBREW_PREFIX}/bin/aws_completer" ] && complete -C "${HOMEBREW_PREFIX}/bin/aws_completer" aws [ -e '/usr/bin/aws_completer' ] && complete -C '/usr/bin/aws_completer' aws
bat
header-args: :mkdirp yes :tangle ~/.bashrc.d/108-bat.bash
[ -x "${HOMEBREW_PREFIX}/bin/bat" ] && alias cat='bat --theme auto:system --theme-dark default --theme-light GitHub'
~/.config/bat
header-args: :mkdirp yes :tangle ~/.config/bat/config
# This is `bat`s configuration file. Each line either contains a comment or # a command-line option that you want to pass to `bat` by default. You can # run `bat --help` to get a list of all possible configuration options. # Specify desired highlighting theme (e.g. "TwoDark"). Run `bat --list-themes` # for a list of all available themes #--theme="TwoDark" # Enable this to use italic text on the terminal. This is not supported on all # terminal emulators (like tmux, by default): #--italic-text=always # Uncomment the following line to disable automatic paging: #--paging=never # Uncomment the following line if you are using less version >= 551 and want to # enable mouse scrolling support in `bat` when running inside tmux. This might # disable text selection, unless you press shift. #--pager="less --RAW-CONTROL-CHARS --quit-if-one-screen --mouse" # Syntax mappings: map a certain filename pattern to a language. # Example 1: use the C++ syntax for Arduino .ino files # Example 2: Use ".gitignore"-style highlighting for ".ignore" files #--map-syntax "*.ino:C++" #--map-syntax ".ignore:Git Ignore"
Emacs
header-args: :mkdirp yes :tangle ~/.bashrc.d/107-emacs.bash
[ -x "${HOMEBREW_PREFIX}/bin/emacs" ] && alias emacs='$HOMEBREW_PREFIX/bin/emacs --no-window-system' [ -x "${HOMEBREW_PREFIX}/bin/emacsclient" ] && alias emacsclient='$HOMEBREW_PREFIX/bin/emacsclient --no-wait' export EDITOR=emacsclient
This is a clever emacsclient
hack to support opening files at a line number with the :linum
suffix that I stumbled
across at https://stuff-things.net/2019/07/31/opening-files-with-line-numbers-in-emacs.
function k20e_ec () { if [[ $1 =~ (.*):([0-9]+):(.*)$ ]]; then emacsclient "+${BASH_REMATCH[2]}" "${BASH_REMATCH[1]}" else emacsclient "$@" fi } alias ec=k20e_ec
eza
header-args: :mkdirp yes :tangle ~/.bashrc.d/130-eza.bash
if command -v eza >/dev/null 2>&1; then # Workaround for https://github.com/orgs/eza-community/discussions/209#discussioncomment-10801021 which is apparently still not resolved export EXA_COLORS="xx=''" export EZA_CONFIG_DIR="${HOME}/.config/eza" export EZA_ICON_SPACING=2 export EZA_ICONS_AUTO=1 alias l="eza --classify --git --git-repos --grid" alias ls="eza --classify --git --git-repos --grid" alias ll="eza --classify --git --git-repos --long --header --smart-group" alias lt="eza --classify --git --git-repos --tree" alias ltl="eza --classify --git --git-repos --tree --long --header --smart-group" fi
Theme
header-args: :mkdirp yes :tangle ~/.config/eza/theme.yml
See https://github.com/eza-community/eza-themes
---
Gemini CLI
header-args: :mkdirp yes :tangle ~/.gemini/settings.json
{ "checkpointing": { "enabled": true }, "selectedAuthType": "gemini-api-key", "theme": "GitHub Light" }
Ghostty
header-args: :mkdirp yes :tangle ~/.config/ghostty/config
[X]
https://ghostty.org/docs/config/keybind/reference#jump_to_prompt[X]
https://ghostty.org/docs/config/keybind/reference#toggle_quick_terminal
# See https://github.com/ghostty-org/ghostty/discussions/3501#discussioncomment-12102205 font-codepoint-map = U+E000-U+E00A,U+E0A0-U+E0A3,U+E0B0-U+E0C8,U+E0CA,U+E0CC-U+E0D7,U+E200-U+E2A9,U+E300-U+E3E3,U+E5FA-U+E6B7,U+E700-U+E8EF,U+EA60-U+EC1E,U+ED00-U+F2FF,U+EE00-U+EE0B,U+F300-U+F381,U+F400-U+F533,U+F0001-U+F1AF0=Symbols Nerd Font alpha-blending = native background-opacity = 0.75 background-blur-radius = 20 # See also shell-integration-features cursor-style = block cursor-style-blink = true font-family = "" font-family = PragmataPro Mono Liga font-size = 20 # Font features for PragmataPro # Contextual alternate ligatures font-feature = calt # Ligatures font-feature = liga # Git tree font-feature = ss13 # Serif # font-feature = ss16 # BUG // TODO // HACK tags font-feature = ss18 # Backward erase word # This binds cmd+h to alt+backspace which will backward erase one word # Remember to go change the "Hide Ghostty" menu shortcut to something else, e.g., # https://apple.stackexchange.com/questions/101754/os-x-disable-cmd-h-or-hide-app-command keybind = cmd+h=text:\x1b\x7f # Forward erase word keybind = cmd+d=esc:d # Backward word keybind = cmd+b=esc:b # Forward word keybind = cmd+f=esc:f # Jump to prompt keybind = ctrl+up=jump_to_prompt:-1 keybind = ctrl+down=jump_to_prompt:1 # Quick terminal keybind = global:ctrl+alt+cmd+t=toggle_quick_terminal macos-option-as-alt = true macos-titlebar-style = native quit-after-last-window-closed = true resize-overlay = never shell-integration = bash # This fixed an issue w/ the initial Bash cursor showing as a bar instead of a block before a command was executed # (see cursor-style) shell-integration-features = no-cursor theme = light:GruvboxLight,dark:GruvboxDark window-height = 48 window-width = 110
Git
header-args: :mkdirp yes :tangle ~/.bashrc.d/105-git.bash
Add completion for my muscle memory alias of g
for git
:
alias g="git" __git_complete g __git_main
Diff highlighting (need to review if this is necessary now since I've configured difftastic below).
[ -e "$(brew --prefix git)/share/git-core/contrib/diff-highlight/" ] && pathmunge "$(brew --prefix git)/share/git-core/contrib/diff-highlight/"
~/.gitconfig
header-args: :mkdirp yes :tangle ~/.gitconfig
The includeIf
section below allows for sticking a .gitconfig
in a directory such that repositories cloned into that
directory will read that config for each repository there. This is useful for setting values like email, etc.,
that might be different than the global value without having to set it specifically in each repository's config.
Just clone the repository into this directory and make sure that the config is set. git config --list
is useful
when making sure that the config values are set properly.
[user] name = Kris Molendyke email = krismolendyke@users.noreply.github.com useconfigonly = true [color] ui = auto [core] excludesfile = ~/.gitignore-global whitespace = -trailing-space,-space-before-tab editor = emacsclient [apply] whitespace = nowarn [alias] diff = difftool stache = stash st = status -sb a = add -p l = log --color-moved --stat --no-merges --ext-diff lp = log --color-moved --patch --stat --no-merges --ext-diff wlp = log --color-moved --patch --stat --color-words --no-merges --ext-diff lo = log --color-moved --oneline --decorate --no-merges --ext-diff lf = log --color-moved --pretty=format: --name-only -z --max-count 1 --no-merges --ext-diff co = checkout br = branch -vv wdiff = diff --color-moved --color-words --ext-diff ds = diff --color-moved --staged --ext-diff g = log --oneline --graph --decorate --all [advice] statusHints = true [rebase] autosquash = true [diff] algorithm = histogram colorMoved = zebra compactionHeuristic = 1 external = difft --display=inline tool = difftastic [difftool] prompt = false [difftool "difftastic"] cmd = difft --display=inline "$LOCAL" "$REMOTE" [fetch] prune = true [help] autocorrect = 1 [pager] difftool = true [pull] rebase = false [push] autoSetupRemote = true [init] defaultBranch = main [credential] helper = cache --timeout=3600 [tag] sort = version:refname # Conditional include to set some work defaults, e.g., email, GHE interal url replacement, ssh signing # This file is stored in work 1Password Employee vault [includeIf "gitdir/i:~/code/work/"] path = ~/code/work/.gitconfig
~/.gitignore-global
header-args: :mkdirp yes :tangle ~/.gitignore-global custom_id: gitignore-global
# -*- mode: gitignore; -*- .jj/ ~/.bashrc.d/secret/ ########################################################################## # Below from: # # # # https://github.com/github/gitignore/blob/master/Global/Linux.gitignore # ########################################################################## *~ # temporary files which can be created if a process still has a handle open of a deleted file .fuse_hidden* # KDE directory preferences .directory # Linux trash folder which might appear on any partition or disk .Trash-* # .nfs files are created when an open file is removed but is still being accessed .nfs* ########################################################################## # Below from: # # # # https://github.com/github/gitignore/blob/master/Global/macOS.gitignore # ########################################################################## .DS_Store .AppleDouble .LSOverride # Icon must end with two \r Icon # Thumbnails ._* # Files that might appear in the root of a volume .DocumentRevisions-V100 .fseventsd .Spotlight-V100 .TemporaryItems .Trashes .VolumeIcon.icns # Directories potentially created on remote AFP share .AppleDB .AppleDesktop Network Trash Folder Temporary Items .apdisk ############################################################################## # Below from: # # # # https://github.com/github/gitignore/blob/master/Global/JetBrains.gitignore # ############################################################################## # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 # User-specific stuff .idea/**/workspace.xml .idea/**/tasks.xml .idea/**/usage.statistics.xml .idea/**/dictionaries .idea/**/shelf # Generated files .idea/**/contentModel.xml # Sensitive or high-churn files .idea/**/dataSources/ .idea/**/dataSources.ids .idea/**/dataSources.local.xml .idea/**/sqlDataSources.xml .idea/**/dynamic.xml .idea/**/uiDesigner.xml .idea/**/dbnavigator.xml # Gradle .idea/**/gradle.xml .idea/**/libraries # Gradle and Maven with auto-import # When using Gradle or Maven with auto-import, you should exclude module files, # since they will be recreated, and may cause churn. Uncomment if using # auto-import. .idea/modules.xml .idea/*.iml .idea/modules # CMake cmake-build-*/ # Mongo Explorer plugin .idea/**/mongoSettings.xml # File-based project format *.iws # IntelliJ out/ # mpeltonen/sbt-idea plugin .idea_modules/ # JIRA plugin atlassian-ide-plugin.xml # Cursive Clojure plugin .idea/replstate.xml # Crashlytics plugin (for Android Studio and IntelliJ) com_crashlytics_export_strings.xml crashlytics.properties crashlytics-build.properties fabric.properties # Editor-based Rest Client .idea/httpRequests # Android studio 3.1+ serialized cache file .idea/caches/build_file_checksums.ser
Go
header-args: :mkdirp yes :tangle ~/.bashrc.d/106-go.bash
[[ -x "${HOMEBREW_PREFIX}/bin/go" ]] && pathmunge "$("${HOMEBREW_PREFIX}/bin/go" env GOPATH)/bin"
Google Cloud SDK
header-args: :mkdirp yes :tangle ~/.bashrc.d/450-google-cloud-sdk.bash
Completion:
# shellcheck source=/dev/null [ -e "${HOMEBREW_CASK_HOME}/google-cloud-sdk/latest/google-cloud-sdk/path.bash.inc" ] && source "${HOMEBREW_CASK_HOME}/google-cloud-sdk/latest/google-cloud-sdk/path.bash.inc" # shellcheck source=/dev/null [ -e "${HOMEBREW_CASK_HOME}/google-cloud-sdk/latest/google-cloud-sdk/completion.bash.inc" ] && source "${HOMEBREW_CASK_HOME}/google-cloud-sdk/latest/google-cloud-sdk/completion.bash.inc"
kubectl
, k
, kctx
, kns
, krew
header-args: :mkdirp yes :tangle ~/.bashrc.d/104-kubectl.bash
Completion for my k
alias:
alias k="kubectl" # shellcheck source=/dev/null [ -e "${HOMEBREW_PREFIX}/etc/bash_completion.d/kubectl" ] && source "${HOMEBREW_PREFIX}/etc/bash_completion.d/kubectl" && complete -o default -F __start_kubectl k
kubectx for wrangling contexts and namespaces:
command -v kubectx >/dev/null 2>&1 && alias kctx="kubectx" command -v kubens >/dev/null 2>&1 && alias kns="kubens"
Change currently selected color:
KUBECTX_CURRENT_FGCOLOR=$(tput setaf 2) export KUBECTX_CURRENT_FGCOLOR
TODO krew
Install and configure krew.
Jujutsu
header-args: :mkdirp yes :tangle ~/.bashrc.d/102-jujutsu.bash
jj
isn't all that bad to type but I'm conditioned to type g
for git
after all these years. So j
for jj
it is.
alias j="jj" && complete -F _clap_complete_jj -o nosort -o bashdefault -o default j
~.config/
header-args: :mkdirp yes :tangle ~/.config/jj/config.toml
"$schema" = "https://jj-vcs.github.io/jj/latest/config-schema.json" [signing] backend = "ssh" backends.ssh.program = "/Applications/1Password.app/Contents/MacOS/op-ssh-sign" behavior = "own" key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPFEgqTPapPtOUOAsoSH2o4VJbp1JFzvXaiuEpdS0KuK" [user] email = "krismolendyke@users.noreply.github.com" name = "Kris Molendyke" [ui] default-command = ["log"] diff-formatter = ["difft", "--color=always", "$left", "$right"] [template-aliases] 'format_short_id(id)' = 'id.shortest()'
nvm
header-args: :mkdirp yes :tangle ~/.bashrc.d/590-nvm.bash
if [ -e "$(brew --prefix nvm)/nvm.sh" ]; then export NVM_DIR="$HOME/.nvm" # shellcheck source=/dev/null source "$(brew --prefix nvm)/nvm.sh" fi
OCaml
header-args: :mkdirp yes :tangle ~/.bashrc.d/500-opam.bash
Modified output of opam init
:
# shellcheck source=/dev/null [ -e "${HOME}/.opam/opam-init/init.sh" ] && source "${HOME}/.opam/opam-init/init.sh"
Playdate
header-args: :mkdirp yes :tangle ~/.bashrc.d/511-playdate.bash
[ -e "${HOME}/Developer/PlaydateSDK" ] && export PLAYDATE_SDK_PATH="${HOME}/Developer/PlaydateSDK" && pathmunge "${PLAYDATE_SDK_PATH}/bin"
PostgreSQL
header-args: :mkdirp yes :tangle ~/.bashrc.d/515-postgresql.bash
[ -d "$(brew --prefix postgresql@16)" ] && pathmunge "$(brew --prefix postgresql@16)/bin"
Python
https://docs.astral.sh/uv/ FTW I'll remove this section soon.
Rancher
header-args: :mkdirp yes :tangle ~/.bashrc.d/560-rancher.bash
[ -d "${HOME}/.rd/bin" ] && pathmunge "${HOME}/.rd/bin"
ripgrep
header-args: :mkdirp yes :tangle ~/.bashrc.d/510-ripgrep.bash
export RIPGREP_CONFIG_PATH=${HOME}/.ripgreprc
~/.ripgreprc
header-args: :mkdirp yes :tangle ~/.ripgreprc
See RIPGREP_CONFIG_PATH
above and https://github.com/BurntSushi/ripgrep/blob/master/GUIDE.md#configuration-file
--sort-files
Rust
header-args: :mkdirp yes :tangle ~/.bashrc.d/550-rust.bash
See https://github.com/rust-lang-nursery/rustfmt#tips.
if [ -d "${HOME}/.cargo" ]; then export CARGO_HOME=${HOME}/.cargo pathmunge "${CARGO_HOME}/bin" fi if [[ -x ${HOMEBREW_PREFIX}/bin/rustc ]]; then DYLD_LIBRARY_PATH=$("${HOMEBREW_PREFIX}"/bin/rustc --print sysroot)/lib:${DYLD_LIBRARY_PATH} export DYLD_LIBRARY_PATH fi
ShellCheck
header-args: :mkdirp yes :tangle ~/.bashrc.d/300-shellcheck.bash
k20e_shellcheck
will run shellcheck
against the result of tangling all of this configuration to the files that the
shell will actually execute.
command -v shellcheck >/dev/null 2>&1 && alias k20e_shellcheck='find $HOME/.bash_profile $HOME/.bashrc $K20E_BASHRC_DIR -type f -exec shellcheck '\''{}'\'' \;'
~/.shellcheckrc
header-args: :mkdirp yes :tangle ~/.shellcheckrc
color=always shell=bash
skim
header-args: :mkdirp yes :tangle ~/.bashrc.d/120-skim.bash
Possibly replaced by Television.
export SKIM_DEFAULT_COMMAND="git ls-tree -r --name-only HEAD || rg --files || find ." export SKIM_DEFAULT_OPTIONS="--ansi --bind 'alt-a:select-all+accept,ctrl-o:execute(emacsclient --no-wait {})+accept' --prompt '❯ ' --cmd-prompt 'C❯ ' --color 'light' --multi --tiebreak=score,begin,end"
skim takes over C-t
in the terminal. I live by that key binding to transpose typographical errors. Set it
explicitly:
bind -r '\C-t' bind '\C-t: transpose-chars'
SSH
On macOS, 1Password requires this to work with the Environment properly:
mkdir -p ~/.1password && ln -s ~/Library/Group\ Containers/2BUA8C4S2C.com.1password/t/agent.sock ~/.1password/agent.sock
~/.ssh/config
header-args: :mkdirp yes :tangle ~/.ssh/config
ServerAliveCountMax 5 ServerAliveInterval 60 Host * IdentityAgent ~/.1password/agent.sock StrictHostKeyChecking accept-new Include ~/.ssh/config.d/*
Personal
header-args: :mkdirp yes :tangle ~/.ssh/config.d/personal
Splitting work & personal to allow for using multiple GitHub accounts. See https://developer.1password.com/docs/ssh/agent/advanced/#use-multiple-github-accounts.
Host personal.localhost HostName github.com User git IdentityFile ~/.ssh/personal.pub IdentitiesOnly yes PreferredAuthentications publickey PasswordAuthentication no
Work
header-args: :mkdirp yes :tangle ~/.ssh/config.d/work
Host work.localhost HostName github.com User git IdentityFile ~/.ssh/work.pub IdentitiesOnly yes PreferredAuthentications publickey PasswordAuthentication no
Environment
header-args: :mkdirp yes :tangle ~/.bashrc.d/101-ssh-env.bash
export SSH_AUTH_SOCK=~/.1password/agent.sock
Starship
header-args: :mkdirp yes :tangle ~/.bashrc.d/999-starship.bash
if command -v starship >/dev/null 2>&1; then function k20e_starship_precmd_user_func() { # Immediately append commands to HISTFILE rather than waiting for logout # NB this does not affect the current session's history but it does mean that a login will have access to all # recent commands from any current sessions history -a } # See https://starship.rs/advanced-config/#custom-pre-prompt-and-pre-execution-commands-in-bash # shellcheck disable=SC2034 starship_precmd_user_func='k20e_starship_precmd_user_func' # Only init one time, I found issues w/ this executing multiple time, e.g., via interactive `source ~/.bashrc` if [ ! -v STARSHIP_SHELL ]; then eval "$(starship init bash)" fi fi
~/.config/starship.toml
header-args: :mkdirp yes :tangle ~/.config/starship.toml
https://starship.rs/config/#prompt
This section must be first!
# Get editor completions based on the config schema "$schema" = 'https://starship.rs/config-schema.json' format = """ $aws\ $gcloud\ $kubernetes\ $docker_context\ $line_break\ $username\ $hostname\ $localip\ $shlvl\ $directory\ ${custom.jj} \ $git_branch\ $git_commit\ $git_state\ $git_metrics\ $git_status\ $package\ $c\ $cmake\ $golang\ $helm\ $java\ $julia\ $kotlin\ $gradle\ $lua\ $nodejs\ $opa\ $perl\ $python\ $ruby\ $rust\ $scala\ $swift\ $terraform\ $zig\ $buf\ $memory_usage\ $env_var\ $crystal\ $custom\ $sudo\ $cmd_duration\ $line_break\ $jobs\ $battery\ $time\ $status\ $os\ $container\ $shell\ $character"""
Presets
Started with starship preset nerd-font-symbols
and removed stuff I'll never need.
[buf] symbol = " " [c] symbol = " " [hostname] ssh_symbol = " " [java] symbol = " " [lua] symbol = " " [memory_usage] symbol = " " [nodejs] symbol = " " [ocaml] symbol = " " [os.symbols] Alpine = " " Amazon = " " Android = " " Arch = " " CentOS = " " Debian = " " Linux = " " Macos = " " Raspbian = " " Redhat = " " RedHatEnterprise = " " Ubuntu = " " Unknown = " " [ruby] symbol = " " [rust] symbol = " "
https://starship.rs/config/#aws
[aws] symbol = 'aws ' format = '[$symbol($profile )(\($region\) )(\[$duration\] )]($style)'
https://starship.rs/config/#battery
[battery] disabled = true
https://starship.rs/config/#character
[character] success_symbol = '[#](bold green)' error_symbol = '[#](bold red)'
https://starship.rs/config/#command-duration
[cmd_duration] format = '[$duration]($style) '
https://starship.rs/config/#directory
[directory] read_only = ' ' truncation_length = 4 format ='[$path]($style)[$read_only]($read_only_style) '
https://starship.rs/config/#docker-context
[docker_context] symbol = '' format = '[$symbol $context]($style) '
https://starship.rs/config/#go
[golang] symbol = ' ' format = '[$symbol($version )]($style) '
https://starship.rs/config/#google-cloud-gcloud
[gcloud] symbol = 'gcp ' format = '[$symbol$project(\($region\))]($style) '
https://starship.rs/config/#git-branch
[git_branch] always_show_remote = false symbol = '' format = '[$symbol $branch(:$remote_branch)]($style) ' disabled = true [custom.git_branch] when = "! jj --ignore-working-copy root" command = "starship module git_branch" description = "Only show git_branch if we're not in a jj repo" style = "" shell = ["bash", "--norc", "--noprofile"]
https://starship.rs/config/#git-commit
[git_commit] disabled = true [custom.git_commit] when = "! jj --ignore-working-copy root" command = "starship module git_commit" style = "" description = "Only show git_commit if we're not in a jj repo" shell = ["bash", "--norc", "--noprofile"]
https://starship.rs/config/#git-status
[git_status] # all_status = '$conflicted$stashed$deleted$renamed$modified$staged$untracked' format = '([$conflicted$deleted$renamed$modified$staged$untracked$ahead_behind]($style) )' disabled = true [custom.git_status] when = "! jj --ignore-working-copy root" command = "starship module git_status" style = "" # This disables the default "(bold green)" style description = "Only show git_status if we're not in a jj repo" shell = ["bash", "--norc", "--noprofile"]
Jujutsu
No official support yet, need to install this tool https://gitlab.com/lanastara_foss/starship-jj before configuring. See also https://github.com/starship/starship/issues/6076.
[custom.jj] command = "prompt" format = "$output" ignore_timeout = true shell = ["starship-jj", "--ignore-working-copy", "starship"] use_stdin = false when = true
~/.config/starship-jj/starship-jj.toml
header-args: :mkdirp yes :tangle ~/.config/starship-jj/starship-jj.toml
https://gitlab.com/lanastara_foss/starship-jj
# Get editor completions based on the config schema "$schema" = 'https://gitlab.com/lanastara_foss/starship-jj/-/raw/main/schema.json' module_separator = " " reset_color = false [bookmarks] search_depth = 100 exclude = [] [[module]] type = "Symbol" symbol = "" color = "Blue" [[module]] type = "Bookmarks" separator = " " color = "Magenta" behind_symbol = "⇡" surround_with_quotes = false [[module]] type = "Commit" max_length = 48 empty_text = "(no description set)" surround_with_quotes = true [[module]] type = "State" separator = " " [module.conflict] disabled = false text = "💥" color = "Red" [module.divergent] disabled = false text = "🚧" color = "Cyan" [module.empty] disabled = false text = "∅" color = "Yellow" [module.immutable] disabled = false text = "🔒" color = "Yellow" [module.hidden] disabled = false text = "👻" color = "Yellow" [[module]] type = "Metrics" template = "[{changed} {added}{removed}]" color = "Magenta" [module.changed_files] prefix = "" suffix = "" color = "Cyan" [module.added_lines] prefix = "+" suffix = "" color = "Green" [module.removed_lines] prefix = "-" suffix = "" color = "Red"
https://starship.rs/config/#kubernetes
[kubernetes] disabled = false symbol = 'k8s ' format = '[$symbol$context( \($namespace\))]($style) '
https://starship.rs/config/#package-version
[package] format = '[$symbol$version]($style) ' symbol = ' '
https://starship.rs/config/#python
[python] symbol = ' ' format = '[${symbol}${pyenv_prefix}(${version} )(\($virtualenv\) )]($style)'
terminal-notifier
header-args: :mkdirp yes :tangle ~/.bashrc.d/599-terminal-notifier.bash
command -v terminal-notifier >/dev/null 2>&1 && alias notify=terminal-notifier
Terraform
header-args: :mkdirp yes :tangle ~/.bashrc.d/525-terraform.bash
command -v terraform >/dev/null 2>&1 && complete -C terraform terraform
Television
A fuzzy finder https://alexpasmantier.github.io/television/
Smart Autocomplete & Shell History
header-args: :mkdirp yes :tangle ~/.bashrc.d/140-television.bash
This eats =
Modified output of tv init bash
:
if command -v tv >/dev/null 2>&1; then function tv_smart_autocomplete() { local current_prompt="${READLINE_LINE:0:$READLINE_POINT}" local output output=$(tv --autocomplete-prompt "$current_prompt") if [[ -n $output ]]; then # add a space if the prompt does not end with one [[ "${current_prompt}" != *" " ]] && current_prompt="${current_prompt} " READLINE_LINE=$current_prompt$output READLINE_POINT=${#READLINE_LINE} fi } function tv_shell_history() { local current_prompt="${READLINE_LINE:0:$READLINE_POINT}" local output output=$(tv --no-preview bash-history --input "$current_prompt") if [[ -n $output ]]; then READLINE_LINE=$output READLINE_POINT=${#READLINE_LINE} fi } bind -x '"\C-X\C-T": tv_smart_autocomplete' # NB I need C-t as transpose-chars bind -x '"\C-R": tv_shell_history' fi
Configuration
header-args: :mkdirp yes :tangle ~/.config/television/config.toml
Modified from https://github.com/alexpasmantier/television/blob/main/.config/config.toml
# CONFIGURATION FILE LOCATION ON YOUR SYSTEM: # ------------------------------------------- # Defaults: # --------- # Linux: `$HOME/.config/television/config.toml` # macOS: `$HOME/.config/television/config.toml` # Windows: `%APPDATA%\television\config.toml` # # XDG dirs: # --------- # You may use XDG_CONFIG_HOME if set on your system. # In that case, television will expect the configuration file to be in: # `$XDG_CONFIG_HOME/television/config.toml` # # General settings # ---------------------------------------------------------------------------- tick_rate = 50 [ui] # How much space to allocate for the UI (in percentage of the screen) # ┌───────────────────────────────────────┐ # │ │ # │ Terminal screen │ # │ ┌─────────────────────────────┐ │ # │ │ │ │ # │ │ │ │ # │ │ │ │ # │ │ Television UI │ │ # │ │ │ │ # │ │ │ │ # │ │ │ │ # │ │ │ │ # │ └─────────────────────────────┘ │ # │ │ # │ │ # └───────────────────────────────────────┘ ui_scale = 100 # The theme to use for the UI # A list of builtin themes can be found in the `themes` directory of the television # repository. You may also create your own theme by creating a new file in a `themes` # directory in your configuration directory (see the `config.toml` location above). theme = "default" [ui.input_bar] # Where to place the input bar in the UI (top or bottom) position = "bottom" [ui.help_panel] # Whether to split the help panel by categories show_categories = true hidden = true [ui.preview_panel] # Preview panel size (percentage of screen width/height) size = 50 #header = "" #footer = "" scrollbar = true border_type = "rounded" # padding = {"left": 0, "right": 0, "top": 0, "bottom": 0} hidden = false # Previewers settings # ---------------------------------------------------------------------------- [previewers.file] # The theme to use for syntax highlighting. # Bulitin syntax highlighting uses the same syntax highlighting engine as bat. # To get a list of your currently available themes, run `bat --list-themes` # Note that setting the BAT_THEME environment variable will override this setting. theme = "TwoDark" # Keybindings # ---------------------------------------------------------------------------- # # Channel mode # ------------------------ [keybindings] # Quit the applicatione esc = "quit" ctrl-c = "quit" ctrl-g = "quit" # Scrolling through entries down = "select_next_entry" ctrl-n = "select_next_entry" ctrl-j = "select_next_entry" up = "select_prev_entry" ctrl-p = "select_prev_entry" ctrl-k = "select_prev_entry" pagedown = "select_next_page" pageup = "select_prev_page" # Scrolling the preview pane ctrl-d = "scroll_preview_half_page_down" ctrl-u = "scroll_preview_half_page_up" # Add entry to selection and move to the next entry tab = "toggle_selection_down" # Add entry to selection and move to the previous entry backtab = "toggle_selection_up" # Confirm selection enter = "confirm_selection" # Copy the selected entry to the clipboard ctrl-y = "copy_entry_to_clipboard" # Toggle the remote control mode ctrl-r = "toggle_remote_control" # Toggle the send to channel mode # ctrl-s = "toggle_send_to_channel" # Toggle the help bar ctrl-h = "toggle_help" # Toggle the preview panel ctrl-o = "toggle_preview" # Shell integration # ---------------------------------------------------------------------------- # # The shell integration feature allows you to use television as a picker for # your shell commands (as well as your shell history with <CTRL-R>). # E.g. typing `git checkout <CTRL-T>` will open television with a list of # branches to choose from. [shell_integration.channel_triggers] # Add your channel triggers here. Each key is a channel that will be triggered # by the corresponding commands. # Example: say you want the following commands to trigger the following channels # when pressing <CTRL-T>: # `git checkout` should trigger the `git-branches` channel # `ls` should trigger the `dirs` channel # `cat` and `cp` should trigger the `files` channel # # You would add the following to your configuration file: # ``` # [shell_integration.channel_triggers] # "git-branches" = ["git checkout"] # "dirs" = ["ls"] # "files" = ["cat", "cp"] # ``` "alias" = ["alias", "unalias"] "env" = ["export", "unset"] "dirs" = [ "cd", "ls", "ll", "ltl", "rmdir", ] "files" = [ "cat", "less", "head", "tail", "vim", "nano", "bat", "cp", "mv", "rm", "touch", "chmod", "chown", "ln", "tar", "zip", "unzip", "gzip", "gunzip", "xz", ] "git-diff" = ["git add", "git restore"] "git-branch" = [ "g co", "git checkout", "git branch", "git merge", "git rebase", "git pull", "git push", ] "git-log" = [ "g l", "g lo", ] "git-repos" = ["nvim", "code", "hx", "git clone"] "docker-images" = ["docker run"] [shell_integration.keybindings] # controls which key binding should trigger tv # for shell autocomplete "smart_autocomplete" = "ctrl-t" # controls which keybinding should trigger tv # for command history "command_history" = "ctrl-r"
Cable Channels
Modified from https://github.com/alexpasmantier/television/tree/main/cable/unix
TODO migrate these to the 0.12+ format :/
# Git [[cable_channel]] name = "git-diff" source_command = "git diff --name-only" preview_command = "git diff --color=always {0}" [[cable_channel]] name = "git-reflog" source_command = 'git reflog' preview_command = 'git show -p --stat --pretty=fuller --color=always {0}' [[cable_channel]] name = "git-log" source_command = "git log --oneline --date=short --pretty=\"format:%h %s %an %cd\" \"$@\"" preview_command = "git show -p --stat --pretty=fuller --color=always {0}" [[cable_channel]] name = "git-branch" source_command = "git --no-pager branch --all --format=\"%(refname:short)\"" preview_command = "git show -p --stat --pretty=fuller --color=always {0}" [[cable_channel]] name = "docker-images" source_command = "docker image list --format \"{{.ID}}\"" preview_command = "docker image inspect {0} | jq -C" [[cable_channel]] name = "my-dotfiles" source_command = "find $HOME/.bashrc $HOME/.bashrc.d -type f" preview_command = ":files:" [[cable_channel]] name = "bash-history" source_command = "sed '1!G;h;$!d' ${HISTFILE:-${HOME}/.bash_history} | rg -v '^#' | nl | sort -k2 -u | sort -n | cut -f 2"
Bash History
header-args: :mkdirp yes :tangle ~/.config/television/cable/bash-history.toml
# UNTESTED [metadata] name = "bash-history" description = "A channel to select from your bash history" requirements = ["bash"] [source] command = "sed '1!G;h;$!d' ${HISTFILE:-${HOME}/.bash_history} | rg -v '^#' | nl | sort -k2 -u | sort -n | cut -f 2"
Files
header-args: :mkdirp yes :tangle ~/.config/television/cable/files.toml
[metadata] name = "files" description = "A channel to select files and directories" requirements = ["fd", "bat"] [source] command = ["fd -t f", "fd -t f -H"] [preview] command = "bat -n --color=always '{}'" env = { BAT_THEME = "ansi" } [keybindings] shortcut = "f1"
Theme
header-args: :mkdirp yes :tangle ~/.config/television/themes/default.toml
# general # background = 'black' border_fg = 'bright-black' text_fg = 'bright-blue' dimmed_text_fg = 'white' # input input_text_fg = 'bright-red' result_count_fg = 'bright-red' # results result_name_fg = 'bright-blue' result_line_number_fg = 'bright-yellow' result_value_fg = 'white' selection_fg = 'bright-green' selection_bg = 'bright-black' match_fg = 'bright-red' # preview preview_title_fg = 'bright-magenta' # modes channel_mode_fg = 'black' channel_mode_bg = 'green' remote_control_mode_fg = 'black' remote_control_mode_bg = 'yellow' send_to_channel_mode_fg = 'cyan'
WezTerm
header-args: :mkdirp yes :tangle ~/.wezterm.lua
TERM
setup https://wezfurlong.org/wezterm/config/lua/config/term.html
local wezterm = require 'wezterm' local act = wezterm.action local config = {} if wezterm.config_builder then config = wezterm.config_builder() end -- term https://wezfurlong.org/wezterm/config/lua/config/term.html config.term = "wezterm" -- Shell if wezterm.target_triple == 'aarch64-apple-darwin' then config.default_prog = {'/opt/homebrew/bin/bash'} elseif wezterm.target_triple == 'x86_64-unknown-linux-gnu' then config.default_prog = {'/bin/bash'} end -- Font config.font = wezterm.font('PragmataPro Liga') config.font_size = 22 -- GUI config.initial_rows = 48 config.initial_cols = 110 config.enable_tab_bar = false -- Theme function get_appearance() if wezterm.gui then return wezterm.gui.get_appearance() end return 'Dark' end function scheme_for_appearance(appearance) if appearance:find 'Dark' then return 'Tomorrow Night Bright' else return 'Tomorrow' end end config.color_scheme = scheme_for_appearance(get_appearance()) -- Bindings config.keys = { -- macOS move forward/backward by word with ⌘-f, ⌘-b { key = 'b', mods = 'CMD', action = act.SendString '\x1bb' }, { key = 'f', mods = 'CMD', action = act.SendString '\x1bf' }, -- macOS backward erase word (see -- https://apple.stackexchange.com/questions/101754/os-x-disable-cmd-h-or-hide-app-command for re-mapping ⌘-h from -- "Hide WezTerm" to something else) { key = 'h', mods = 'CMD', action = act.SendString '\x1b\x7f' }, -- macOS forward erase word { key = 'd', mods = 'CMD', action = act.SendString '\x1bd' }, -- Search, rather than ⌘-f { key = 's', mods = 'CMD', action = act.Search 'CurrentSelectionOrEmptyString' }, } return config
yamllint
header-args: :mkdirp yes :tangle ~/.config/yamllint/config
See https://yamllint.readthedocs.io/en/stable/configuration.html and https://yamllint.readthedocs.io/en/stable/rules.html.
--- yaml-files: - '*.yaml' - '*.yml' - '.yamllint' rules: braces: level: warning brackets: enable colons: level: warning commas: enable comments: level: warning comments-indentation: level: warning document-end: disable document-start: level: warning empty-lines: enable empty-values: disable float-values: disable hyphens: enable indentation: enable key-duplicates: enable key-ordering: disable line-length: disable new-line-at-end-of-file: level: warning new-lines: enable octal-values: disable quoted-strings: disable trailing-spaces: level: warning truthy: level: warning
~/.inputrc
header-args: :mkdirp yes :tangle ~/.inputrc
set bell-style none set colored-completion-prefix on set colored-stats on set completion-ignore-case off set convert-meta off set expand-tilde on set input-meta on set output-meta on set show-all-if-ambiguous on set visible-stats on