Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
784 lines (593 sloc) 19.4 KB

Dotfiles Configuration

Shell and CLI Tooling configuration

bashrc

CLI Colors

For commands that support colors, enable the use of colors to better visually understand the output of commands.

export CLICOLOR=1

$PATH

/usr/local/bin

Binaries stored in the /usr/local/bin directory take precedence over their counterparts stored elsewhere on the PATH

export PATH=/usr/local/bin:/usr/local/sbin:$PATH

bin

I keep personal scripts in ~/bin. Ensure that scripts found in ~/bin are available on the PATH so they can be executed without providing full paths:

For example, instead of typing ~/bin/script-name simply type script-name.

export PATH=$PATH:$HOME/bin

Aliases

*nix aliases

ls

Make ls output more information about files and directories in a human readable format.

alias ls='ls --color'

grep

Make grep highlight matches.

alias grep='grep --color'

pbcopy

Add a shorthand to copy data to the system clipboard on the cli

alias pbcopy='xclip -selection clipboard'

Git aliases

gs is shorthand for the status of a git repository.

alias gs="git status"

gl shows the railroad tracks of the current head ref

alias gl='git log --graph --oneline --decorate --max-count 10'

Prompt

Configure the shell prompt. This happens to check if we’re in a git managed directory and adds some status info to the command line.

# Get a graphical representation of the clean/dirty state of a git repository
# colors
case "$TERM" in
    xterm*|rxvt*|screen*|eterm-color)
        ESC="\033"
        RED="\[$ESC[01;31m\]"
        LIGHT_RED="\[$ESC[1;31m\]"
        GREEN="\[$ESC[01;32m\]"
        LIGHT_GREEN="\[$ESC[1;32m\]"
        GREY="\[$ESC[0;37m\]"
        CYAN="\[$ESC[01;36m\]"
        YELLOW="\[$ESC[0;33m\]"
        LIGHT_VIOLET="\[$ESC[1;35m\]"
        RESET="\[$ESC[0m\]"
    ;;
    *)
        ESC=""
        RED=""
        LIGHT_RED=""
        GREEN=""
        LIGHT_GREEN=""
        GREY=""
        CYAN=""
        YELLOW=""
        LIGHT_VIOLET=""
        RESET=""
    ;;
esac

# prints path to git directory
__git_dirname() {
    local dirname
    if [ -d .git ]; then
        dirname=".git"
    else
        dirname="$(git rev-parse --git-dir 2>/dev/null)"
    fi
    echo "$dirname"
}

# gets the branching state of the repository
# optional arg: path to git directory
__git_branching_state() {
    local gitdir="$1" || "$(__git_dirname)"
    local state

    if [ -f "$gitdir/rebase-merge/interactive" ]; then
        state="rebase-i"
    elif [ -d "$gitdir/rebase-merge" ]; then
        state="rebase-m"
    else
        if [ -d "$gitdir/rebase-apply" ]; then
            if [ -f "$gitdir/rebase-apply/rebasing" ]; then
                state="rebase"
            elif [ -f "$gitdir/rebase-apply/applying" ]; then
                state="am"
            else
                state="am/r"
            fi
        elif [ -f "$gitdir/MERGE_HEAD" ]; then
            state="merge" # merging
        elif [ -f "$gitdir/BISECT_LOG" ]; then
            state="bisect" # bisecting
        fi
    fi
    echo "$state"
}

# prints the working directory state of the repository using symbols
# these could be expensive.. would make sense to have configs to turn off
# * - modified / + - staged / ^ - stashed / % - untracked
__git_working_dir_symbols() {
    local symbols

    # in working dir
    if [ true = "$(git rev-parse --is-inside-work-tree 2>/dev/null)" ]; then
        git diff --no-ext-diff --quiet --exit-code || symbols="*"
        if git rev-parse --quiet --verify HEAD >/dev/null; then
            git diff-index --cached --quiet HEAD -- || symbols="${symbols}+"
        fi
    fi

    # stashed
    git rev-parse --verify refs/stash >/dev/null 2>&1 && symbols="${symbols}^"

    # untracked files
    if [ -n "$(git ls-files --others --exclude-standard)" ]; then
        symbols="${symbols}%"
    fi
    echo "$symbols"
}

# prints current / parent branch name
# optional arg: 'parent' -- returns a limited guess of the parent
# optional arg: path to git directory
__git_branch_name() {
    # current branch name
    local branch
    local gitdir="$2" || "$(__git_dirname)"
    branch="$(git symbolic-ref HEAD 2>/dev/null)" || {
        branch="$(git describe --contains --all HEAD 2>/dev/null)" ||
            branch="$(cut -c1-7 "$gitdir/HEAD" 2>/dev/null)..." ||
                branch="unknown"

        branch="${branch##remotes/}"
        branch="($branch)"
    }
    branch="${branch##refs/heads/}"

    # parent branch name
    if [ parent = "$1" ]; then
        if [ master = "$branch" ]; then
            local refs="$(git for-each-ref --format="%(refname:short)")"
            case "$refs" in
                *git-svn*) # git-svn repo
                    branch='git-svn' ;;
                *origin*) # remote clone
                    branch='origin' ;;
                *)
                    branch='HEAD' ;; # same repo
            esac
        else
            # TODO.. would be nice to improve this to determine the actual
            # merge base (git merge-base) and compare against that instead of
            # always assuming master. In this way a 'topic/feature' branch
            # would show the diff counts for its parent 'next/develop' branch
            # rather than those plus those on the 'next/develop' branch.
            # I don't think we want to loop over the refs comparing ... that's
            # fuzzy.
            branch='master' # on a branch
        fi
    fi
    echo "$branch"
}

# prints if inside git directory or bare git repository
__git_in_gitdir() {
    if [ true = "$(git rev-parse --is-inside-git-dir 2>/dev/null)" ]; then
        if [ true = "$(git rev-parse --is-bare-repository 2>/dev/null)" ]; then
            echo 'bare'
        else
            echo 'gitdir'
        fi
    fi
}

# prints number of commits that are available on ref B but not ref A
# arg1: reference A
# arg2: reference B
__git_commit_diff_count() {
    echo "$(git rev-list $1..$2 2>/dev/null | awk 'END {print NR}')"
}

# build combined (+/-) counts for related commits
__git_count_str() {
    local str
    local parent="$(__git_branch_name parent)"
    local ahead_count="$(__git_commit_diff_count $parent HEAD)"
    local behind_count="$(__git_commit_diff_count HEAD $parent)"

    if [ 0 -lt "$ahead_count" ]; then
        str="${GREEN}+${ahead_count}${RESET}"
    fi

    if [ 0 -lt "$behind_count" ]; then
        [ -n "$str" ] && str="$str/"
        str="${str}${LIGHT_RED}-${behind_count}${RESET}"
    fi

    [ -n "$str" ] && str="($str)"
    echo "$str"
}

# install git integration into PS1
__git_prompt() {
    local last_exit="$?" # keep here.. so we get the last command

    # setup PS1
    local host="${LIGHT_GREEN}\h:${RESET}"
    local dir="${YELLOW}\W${RESET}"
    PS1="[$host $dir]"

    # when in git repository
    local gitdir="$(__git_dirname)"
    if [ -n "$gitdir" ]; then
        local branch
        local extras

        local in_gitdir="$(__git_in_gitdir)"
        case "$in_gitdir" in
            gitdir|bare)
                branch="~$(echo $in_gitdir | tr "[:lower:]" "[:upper:]")~"
                extras=""
            ;;
            *)
                local branch="$(__git_branch_name current ${gitdir})"
                local br_state="$(__git_branching_state $gitdir)"

                # rebasing..use merge head for branch name
                case "$br_state" in
                    rebase-*)
                        # get the ref head during rebase
                        branch="$(cat "$gitdir/rebase-merge/head-name")"
                        branch="${branch##refs/heads/}"
                        branch="${branch##remotes/}"
                    ;;
                esac

                # extras (count strings, working dir symbols)
                local countstr="$(__git_count_str)"
                local wd_syms="${LIGHT_VIOLET}$(__git_working_dir_symbols)${RESET}"
                extras="${countstr} ${wd_syms}"
            ;;
        esac
        branch="${GREY}${branch}${RESET}"

        # update PS1
        PS1="${PS1} ${branch}${extras}"
    fi

    # setup marker that acts off of last exit code
    local marker
    if [ 0 -eq "$last_exit" ]; then
        marker="$GREEN"
    else
        marker="$RED"
    fi
    marker="${marker}\$${RESET}"
    PS1="\n${PS1} →\n${marker} "
}
PROMPT_COMMAND=__git_prompt

Editors

Use emacs as the default editor for the shell

export EDITOR=emacs

History

A ton of the following is ripped directly from the How To Use Bash History Commands and Expansions on a Linux VPS guide.

Immediately store commands

To do this correctly, we need to do a bit of a hack. We need to append to the history file immediately with history -a

export PROMPT_COMMAND="history -a; $PROMPT_COMMAND"

Append to the history logs

By default, bash writes its history at the end of each session, overwriting the existing file with an updated version. This means that if you are logged in with multiple bash sessions, only the last one to exit will have its history saved.

shopt -s histappend

Store Unique Commands

Store only unique commands in bash history. Also provide a way to manually exclude commands from being recorded in the history. To do this, prefix the command with whitespace.

export HISTCONTROL=ignoreboth:erasedups

Number of History Entries

Set the number of commands which can be stored in the history.

export HISTSIZE=5000
export HISTFILESIZE=10000

Bash Completion

if type brew 2&>/dev/null; then
  for completion_file in $(brew --prefix)/etc/bash_completion.d/*; do
    source "$completion_file"
  done
fi

ASDF Version Manager

I’ve used disparate version managers for ruby, elixir, node, etc for years. ASDF promises to unify the interface across all of these version managers - so I’m going to give it a shot.

source $HOME/.asdf/asdf.sh
source $HOME/.asdf/completions/asdf.bash

ruby

Spring

Too many times have I been bitten by the spring gem. Kill it with fire.

DISABLE_SPRING=1

Bundler

Sometimes bundler installs and pins gems to palatform specific versions - IE gems which would only be valid on OSx hosts. To prevent this, the bundler documentation suggests setting the BUNDLE_FORCE_RUBY_PLATFORM variable to ignore the host’s platform when installing gems and compile native extensions on gem install instead.

BUNDLE_FORCE_RUBY_PLATFORM=1

exercism

Load the exercism bash completions if they exits

if [ -f ~/.config/exercism/exercism_completion.bash ]; then
    source ~/.config/exercism/exercism_completion.bash
fi

go

export GOPATH=$HOME/Developer/go
export PATH=$PATH:$GOPATH/bin

Departure

We use departure at work with MySQL. It makes stuff break all the time. Here I globally disable it.

export DISABLE_DEPARTURE=1

Power

Source in the power user credentials/secrets

if [ -f ~/credentials/.power ]
then source ~/credentials/.power
fi

bash_profile

Use the same configuration for .bash_profile as the .bashrc

if [ -f ~/.bashrc ];
then source ~/.bashrc
fi

ASDF Version manager

.asdfrc

Each language’s version manager communities seem to have come to different conclusions on how to represent “required versions”. This setting tells asdf to allow the language specific plugin to attempt to use the language’s version manager community’s default file for specifying a version.

legacy_version_file = yes
  

gnome-terminal

This is my gnome-terminal configuration. This configuration will be tangled to ~/.gruvbox-profile.dconf. At some point I’ll automate the installation, but for now to import the profile:

  1. Open gnome-terminal
  2. Create a new profile
  3. Take node of the UUID of the Profile
  4. Import the profile settings into the new profile cat ~/.gruvbox-profile.dconf | dconf load /org/gnome/terminal/legacy/profiles:/:<profile-uuid-here>/
[/]
foreground-color='rgb(235,219,178)'
visible-name='Gruvbox'
palette=['rgb(40,40,40)', 'rgb(204,36,29)', 'rgb(152,151,26)', 'rgb(184,187,38)', 'rgb(69,133,136)', 'rgb(177,98,134)', 'rgb(104,157,106)', 'rgb(168,153,132)', 'rgb(146,131,116)', 'rgb(251,73,52)', 'rgb(184,187,38)', 'rgb(250,189,47)', 'rgb(131,165,152)', 'rgb(211,134,155)', 'rgb(142,192,124)', 'rgb(235,219,178)']
scroll-on-output=true
use-system-font=true
use-theme-colors=false
scrollback-unlimited=false
background-color='rgb(40,40,40)'
audible-bell=false

git

Git Configuration

.gitconfig

Author

Configure information used by git to determine how to write the author information for commits

[user]
  name = Aaron Kuehler
  email = aaron.kuehler@gmail.com
  signingkey = 9E3E4C59E2694215

Github Credentials

Include credentials for CLI authentication with the github gist API

[include]
  path = ~/credentials/.github

Core configuration

In addition to any files included in a project’s .gitignore file, also include those listed in the ~/.gitconfig.

Use Emacs as the commit editor

[core]
  excludesfile = ~/.gitignore
  editor = emacs -nw --eval '(global-git-commit-mode t)'

Colors

Enable coloring of git output

[color]
  ui = true

Aliases

Set aliases for frequently used git incantations.

[alias]
  co  = checkout
  cb  = checkout -b
  db  = branch -d
  rclone = clone --recursive

Commit

GPG Sign commits

[commit]
  gpgsign = true

Clean

Disable the safeguard flag when running git clean

[clean]
  requireForce = false

Push

Only push the current branch, rather than all branches, when git push is invoked.

[push]
  default = simple

Filter

[filter "lfs"]
  clean = git-lfs clean %f
  smudge = git-lfs smudge %f
  required = true

.gitignore

Mac OS Finder cache

Never ever store Mac OS Finder metadata in a git repository.

.DS_Store

Emacs temp files

Never store Emacs autosave and backup files in a git repository.

*~
.#*
*#

tab completion

Enable tab completion for the git.

GIT_TAB_COMPLETION_FILE=/usr/local/etc/bash_completion.d/git-completion.bash
if [ -f $GIT_TAB_COMPLETION_FILE ];
   then source $GIT_TAB_COMPLETION_FILE
fi

gem

Ruby gems configuration

Documentation

When a gem is installed forego the generation of its documentation.

gem: --no-document

Rspec

rspec CLI configuration

Color

Enable colorized output

--color

Output format

Output from spec runs should look like a progress bar

--format progress

Ordering

Always run specs in a random order to ensure that examples are independent of one another.

--order random

Scripts

Version controlled scripts used to automate various repetitive tasks

Flush DNS cache

Invalidates the local DNS cache:

Usage

$ flush_dns

Source

# Purpose:
#   Flush the local DNS cache
# Usage:
#   $ flush_dns_cache

if [[ `uname` == "Darwin" ]]; then
    sudo killall -HUP mDNSResponder
fi

Refresh local git tags

Ensures that a local git repository’s tags are in sync with the remote origin

Usage

$ refresh_tags

Source

# Purpose:
#   Delete all local tags and refresh from origin
# Usage:
#   $ refresh_tags

git tag -l | xargs git tag -d && git fetch

ssh

Automatically load the private key into the ssh-agent and store passwords in the keychain on OS X hosts.

Host *
 AddKeysToAgent yes
 UseKeychain yes

Librem hardware fixes

Keyboard

The purism keyboard screws up the pipe key, it outputs a right angle bracket. This bit corrects the output of that key specifically. Add this to /etc/udev/hwdb.d/90-purism-pipe-symbol-fix.hwdb.

evdev:atkbd:dmi:bvn*:bvr*:bd*:svnPurism:pnLibrem13v2*
 KEYBOARD_KEY_56=backslash

Afterward run:

sudo systemd-hwdb update
sudo udevadm trigger

For reference: https://forums.puri.sm/t/keyboard-layout-unable-to-recognize-pipe/2022/10

You can’t perform that action at this time.