- 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 theag
executable 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 runningmutt
andmbsync
.fd
: "find directory" using fastbfs
andsk
; automaticallycd
s 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 andcd
into it.tick
: moves an existing time warp (eg.tick +1h
); seetw
below 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.tmux
file to set up windows and panes (note that the first time a given.tmux
file is encountered the wrapper asks the user whether to trust or skip it).tw
("time warp"): overridesGIT_AUTHOR_DATE
andGIT_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
$HOME
to~
if possible). - Prompt marker,
❯
, the "HEAVY RIGHT-POINTING ANGLE QUOTATION MARK ORNAMENT" (that's\u276f
, ore2 9d af
in 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
$HOME
to~
).
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": [email protected] (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:[email protected]
to:john
,to:[email protected]
date:today
date:yesterday
date: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_week
ordate:this-week
(Monday to present day)date:"last year"
(also works withyears
,months
,hours
/hrs
,minutes
/mins
,seconds
/secs
etc).date:june
date:2018-06-01
is:{tag}
: eg.is:unread
,is:flagged
(ie. starred); to see all tags, runnotmuch search --output=tags '*'
:attachment
flagged
inbox
(not very meaningful as everything gets this tag when indexed vianotmuch new
)replied
signed
unread
id:[email protected]
(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
env
andzsh
is 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
install
command. - Ruby.
- Adobe Source Code Pro or any other fixed-width font that includes the Powerline glyphs.
git clone --recursive https://github.com/wincent/wincent.git
Note 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 ./install
As 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 ~
done
Note: 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 [email protected]
Flags 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_result
Note 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 found
due to a missing GMP dependency, try:
brew install gmp
env "CFLAGS=-I/usr/local/include -L/usr/local/lib" pip install pycrypto
And then installing again:
./install --force
If 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-8
Then 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-8
Unless 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 <[email protected]>. 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/^/- /'