- Target platforms: macOS and Red Hat-like Linuxes (eg. CentOS).
- Set-up method:
Beautiful and intricate snowflakeincredibly over-engineered Ansible orchestration. - Visible in the screenshot:
- default-dark Base16 color scheme.
- Adobe Source Code Pro (Light) font.
- Vim, running inside tmux, inside iTerm2, on macOS "High Sierra".
A set of dotfiles that I've been tweaking and twiddling since the early 2000s (under version control since 2009). Characteristics include:
- Sane Vim pasting via bracketed paste mode.
- Write access to local clipboard from local and remote hosts, inside and outside of tmux (via Clipper).
- Full mouse support (pane/split resizing, scrolling, text selection) in Vim and tmux.
- Focus/lost events for Vim inside tmux.
- Cursor shape toggles on entering Vim.
- Italics in the terminal.
- Bundles a (not-excessive) number of useful Vim plug-ins.
- Conservative Vim configuration (very few overrides of core functionality; most changes are unobtrusive enhancements; some additional functionality exposed via
<Leader>and<LocalLeader>mappings. - Relatively restrained Zsh config, Bash-like but with a few Zsh perks, such as right-side prompt, auto-cd hooks, command elapsed time printing and such.
- Unified color-handling (across iTerm2 and Vim) via Base16 Shell.
- Encrypted versioning of files with sensitive content (via git-cipher).
- Comprehensive Hammerspoon config.
On macOS, the homebrew role installs a bunch of useful software.
On macOS, Karabiner-Elements is used for the following:
- Make Caps Lock serve as Backspace (when tapped) and Left Control (when chorded with another key). When held down alone, Caps Lock fires repeated Backspace events.
- Make Return serve as Return (when tapped) and Right Control (when chorded with another key). When held down alone, Return fires repeated Return events.
- Maps Control-I to F6 (only in MacVim and the terminal) so that it can be mapped independently from Tab in Vim.
- Toggle Caps Lock on by tapping both Shift keys simultaneously.
- Makes the function keys on my external Realforce keyboard behave like the "media" keys on Apple's keyboards.
- Swap Option and Command keys on my external Realforce keyboard.
- Make the "application" key (extra modifier key on right-hand side) behave as "fn" on Realforce keyboard.
- Make "pause" (at far-right of function key row) behave as "power" (effectively, sleep) on Realforce keyboard.
- Adds a "SpaceFN" layer that can be activated by holding down Space while hitting other keys; I use this to make the cursor keys available on or near the home row in any app.
ag: Transparently wraps theagexecutable so as to provide a centralized place to set defaults for that command (seeing as it has no "rc" file).bounce: bounce the macOS Dock icon if the terminal is not in the foreground.color: change terminal and Vim color scheme.email: convenience wrapper to spawn (or attach to) a tmux session runningmuttandmbsync.fd: "find directory" using fastbfsandsk; automaticallycds into the selected directory.fh: "find [in] history"; selecting a history item inserts it into the command line but does not execute it.history: overrides the (tiny) default history count.jump(aliased toj): to jump to hashed directories.regmv: bulk-rename files (eg.regmv '/\.tif$/.tiff/' *).scratch: create a random temporary scratch directory andcdinto it.tick: moves an existing time warp (eg.tick +1h); seetwbelow for a description of time warp.tmux: wrapper that reattches to pre-existing sessions, or creates new ones based on the current directory name; additionally, looks for a.tmuxfile to set up windows and panes (note that the first time a given.tmuxfile is encountered the wrapper asks the user whether to trust or skip it).tw("time warp"): overridesGIT_AUTHOR_DATEandGIT_COMMITTER_DATE(eg.tw -1d).
Zsh is configured with the following prompt:
Visible here are:
- Concise left-hand prompt consisting of:
- Last component of current directory (abbreviates
$HOMEto~if possible). - Prompt marker,
❯, the "HEAVY RIGHT-POINTING ANGLE QUOTATION MARK ORNAMENT" (that's\u276f, ore2 9d afin UTF-8).
- Last component of current directory (abbreviates
- Extended right-hand size prompt which auto-hides when necessary to make room for long commands and contains:
- Duration of previous command in adaptive units (seconds, minutes, hours, days, depending on duration).
- Current version control branch name.
- Current version control worktree status using colors that match those used in
git status:- Green dot indicates staged changes.
- Red dot indicates unstaged changes.
- Blue dot indicates untracked files.
- Full version of current working directory (again, abbreviating
$HOMEto~).
Nested shells are indicated with additional prompt characters. For example, one nested shell:
Two nested shells:
Root shells are indicated with a different color prompt character and the word "root":
Nesting within a root shell is indicated like this:
Two nested shells:
If the last command exited with a non-zero status (usually indicative of an error), a yellow exclamation is shown:
If there are background processes, a yellow asterisk is shown:
A number of tools are used to provide command-line access to Gmail and Office IMAP accounts.
- mutt: For reading email.
- isync: For maintaining a local cache of messages for offline access.
- notmuch: For fast search.
- msmtp: For sending email.
- elinks: For viewing HTML emails.
- urlview: For opening URLs from inside mutt.
- terminal-notifier: For notifications.
- lbdb: Contact autocompletion drawing from a number of sources, such as previous messages, aliases, and macOS Contacts (which can be configured to synchronize Google contacts as well).
- imapfilter: For filtering.
- passage: For mediating interaction with the macOS keychain.
In order for all this to work, a few items have to be stored in the macOS keychain:
- A "generic" (A.K.A. "application") keychain items (that is, without protocols, only hostnames):
- "Keychain Item Name": example.net (corresponds to the "host" field in
~/.msmtprc, and "Host" field in~/.mbsyncrc). - "Account Name": username+mutt@example.net (corresponds to the "user" field in
~/.msmtprc, and "PassCmd" field in~/.mbsynrc).
- "Keychain Item Name": example.net (corresponds to the "host" field in
The following Gmail-like/Vim-like bindings are configured:
e: Archive (but note: leaves copy of mail in mailbox until next sync; force an immediate sync with$).#: Trash mail.!: Mark as spam.gi: Go to inbox.ga: Go to archive.gt: Go to sent mail.gd: Go to drafts.gs: Go to starred mail.gl: Go to a label (folder).x: Toggle selection on entry (see alsot).c: Compose new message.s: Toggle star.*a: Select all.*n: Deselect all (mnemonic: "select none").*r: Select read messages.*u: Select unread messages.Shift-U: Mark as unread.Shift-I: Mark as read.
Standard mutt stuff:
v: View attachments (including alternate parts for a multipart message).
Non-Gmail extensions:
t: Toggle selection on entire thread (see alsox).A: Show alternate MIME-type in MIME-multipart messages.O: Save original message.S: Search all using Xapian query syntax (notmuch-specific reference documentation):+foo: Must include "foo".-bar: Must not include "bar".AND,OR,NOT,XOR: Self-evident.foo NEAR bar: "foo" within 10 words of "bar" (order-independent).foo ADJ bar: LikeNEAR, but "foo" must appear earlier than "bar"."foo bar": Match entire phrase.foo*: Match "foo", "food", "foobar" etc.subject:this,subject:"one two"(two consecutive words),subject:(one two)(either or both words anywhere in subject),subject:one AND subject:two(both words anywhere in subject).subject:/regex.*/(but note, quotes are needed for patterns containing spaces; eg.subject:"/a b/").from:john,from:me@example.comto:john,to:me@example.comdate:todaydate:yesterdaydate:3d(exactly 3 days ago)date:14d..7d(a week ago)date:10d..(since 10 days ago)date:..3d(until 3 days ago)date:"last week"(preceding Monday through Sunday)date:"this week"ordate:this_weekordate:this-week(Monday to present day)date:"last year"(also works withyears,months,hours/hrs,minutes/mins,seconds/secsetc).date:junedate:2018-06-01is:{tag}: eg.is:unread,is:flagged(ie. starred); to see all tags, runnotmuch search --output=tags '*':attachmentflaggedinbox(not very meaningful as everything gets this tag when indexed vianotmuch new)repliedsignedunread
id:messageId@example.net(search by Message-Id).
l: Limit listed messages:~f bob(from bob)~s foo(subject contains "foo"; "Foo" would search case-sensitively)~s foo.+bar(subject contains pattern)!~s foo(subject does not contain "foo")~d >1m(messages more than 1 month old)
\u: Open list of URLs in message (viaurlview).b: Toggle (mailboxes) sidebar.m: Move message(s).
Other stuff:
<Tab>autocompletes addresses from the lbdb database.<C-t>autocompletes aliases.
Attachment menu bindings:
S: Save all attachments.
To have mailto links open up in mutt in iTerm:
- In iTerm2 → Preferences → Profiles → General, select the "Mutt" profile.
- Under URL Schemes → Schemes handled:, select
mailto.
Notes:
$$URL$$is documented here.- The convoluted use of
envandzshis required to get terminal colors working correctly.
- tmux 2.3 or later.
- Neovim or Vim 8.0 or later with Ruby and Python support (although there's a reasonable amount of feature detection in order to degrade gracefully).
- Relatively recent Zsh.
- Relatively recent Git.
- Clipper for transparent access to the local system clipboard.
- On macOS, iTerm2. Additionally, only the latest version of macOS (although at the time of writing, I'm still on High Sierra) gets actively tested.
- Python to perform setup via the included
installcommand. - Ruby.
- Adobe Source Code Pro or any other fixed-width font that includes the Powerline glyphs.
git clone --recursive https://github.com/wincent/wincent.gitNote that if you're behind a firewall you may need to set up a temporary ~/.gitconfig with appropriate proxy configuration with a format such as:
[http]
proxy = fwdproxy:8080
Or alternatively:
env http_proxy=http://fwdproxy:8080 https_proxy=http://fwdproxy:8080 git clone --recursive https://github.com/wincent/wincent./install # Installs everything on the local machine.
./install --help # Info on installing specific roles, force-installing etc.
./install dotfiles # Just install dotfiles.This sets up a local Python environment using the bundled virtualenv, bootstraps Ansible, and then uses Ansible to copy the dotfiles and configure the machine.
Again, if you're behind a firewall, you may need to make use of a proxy during the initial run:
env http_proxy=http://fwdproxy:8080 https_proxy=http://fwdproxy:8080 ./installAs a fallback strategy, in case the install script fails, you can symlink the dotfiles by hand with a command like the following:
for DOTFILE in $(find roles/dotfiles/files -maxdepth 1 -name '.*' | tail -n +2); do
ln -sf $PWD/$DOTFILE ~
doneNote: The ln -sf command will overwrite existing files, but will fail to overwrite existing directories.
Note: Given that ~/.gitconfig is included with these dotfiles, any local modifications or overrides that you apply should be added to ~/.gitconfig.local instead; for example:
git config --file ~/.gitconfig.local user.name "John Doe"
git config --file ~/.gitconfig.local user.email johndoe@example.comFlags passed to ./install are propagated to the underlying Ansible invocation, which means that you can do things like:
# Run in "check" (dry-run) mode.
./install --check
# Show before-and-after delta of changes.
./install --diff
# Both of the above together.
./install --check --diff
# Show various levels of debug output.
./install --verbose
./install -vv
./install -vvv
./install -vvvv
# Confirm each task before running it (--step), and begin
# execution from a specific task (--start-at-task).
./install --step --start-at-task='dotfiles | create backup directory'You can also inspect variables by adding a task that uses the "debug" module in a role:
- name: buggy task
stat: path="~/{{ item }}"
register: stat_result
with_items: '{{ dotfile_files + dotfile_templates }}'
- name: debugging bad stat info
debug:
var: stat_resultNote that for convenience, "debug" tasks have already been inserted for all variables that are register-ed in the existing roles, with verbosity thresholds of 2, meaning that they will be logged automatically when the install is run using ./install -vv or more.
If pycrypto causes the install to fail at:
src/_fastmath.c:36:11: fatal error: 'gmp.h' file not founddue to a missing GMP dependency, try:
brew install gmp
env "CFLAGS=-I/usr/local/include -L/usr/local/lib" pip install pycryptoAnd then installing again:
./install --forceIf Unicode symbols appear missing or corrupted in Vim, first ensure that your terminal emulator supports UTF-8. Then, check to see if you've properly configured your system-wide UTF-8 support.
Issue this test command:
export LC_ALL=en_US.UTF-8Then run vim. Unicode in the statusline should be working.
To persist this LC_* variable binding, edit your locale accordingly:
/etc/locale.conf
LANG=en_US.UTF-8
LC_ALL=en_US.UTF-8Unless otherwise noted, the contents of this repo are in the public domain. See the LICENSE for details.
The repo is written and maintained by Greg Hurrell <greg@hurrell.net>. Other contributors that have submitted patches include, in alphabetical order:
- Joe Lencioni
- Jonathan Wilkins
- Mark Stenglein
- Matthew Byrne
- Stone C. Lasley
- Victor Igor
- Zac Collier
This list produced with:
:read !git shortlog -s HEAD | grep -v 'Greg Hurrell' | cut -f 2-3 | sed -e 's/^/- /'








