This repository contains my "public" shell configuration files. The ones in this repository are not in any way specific to me, and could theoretically be used by others who share similar preferences.
However, possibly the most interesting thing here is the link_files
script,
which is used to hard-link the files from this repository into the home
directory, while allowing platform-specific files and local overrides. See
link_files --help
.
This is a checklist for me when I set up a new machine.
- ArkkuDvorak
- XCode
- Homebrew
- gpg
- also pinentry program and config
- tmux
- neovim
- mosh
- VS Code
- VS Code colour theme
- File Icons
- Auto Dark Mode
- extensions for C, Swift, Ruby, Awk, zsh, Assembler, Jekyll, Liquid, etc.
- zsh-syntax-highlighting
- hub
- fzf
- fasd
- in my config, remember to
touch ~/.fasd-init-zsh
- in my config, remember to
- ripgrep
- fd
- on some systems may have to
ln -s /usr/bin/fdfind ~/bin/fd
- on some systems may have to
- bat
- on some systems may have to
ln -s /usr/bin/batcat ~/bin/bat
- need to run
bat cache --build
for themes to be detected
- on some systems may have to
- rvm
- SF Mono font
/System/Applications/Utilities/Terminal.app/Contents/Resources/Fonts
~/.ssh
(keys, permissions, authorized keys, include shared config)~/.gitconfig
(account, signing, editor, merge tool, shared config)~/.profile
(source~/.profile_shared
)/etc/locale.gen
This is an incomplete set of features, mainly as a reminder for myself when some years later I have forgotten what I set up. =)
Configuration and colour scheme (imaginatively named arkku
) for Vim and
Neovim. The colour scheme supports both light and dark backgrounds, and works in
an EGA/VGA text-mode terminal. Even if the background is mistakenly set as
light, the colour scheme is still usable, allowing me to keep light background
as the default.
Some other general settings done:
- if
rg
is installed, use it instead ofgrep
(also in plugins), otherwise useag
if that is installed - if
fzf
is installed (viabrew
,apt
, or in~./fzf
), load its plugin, and use the first offd
,rg
orag
that is installed to power the search g:markdown_fenced_languages
is set to contain a variety of popular languages but only if the filetype is known (e.g.,swift
is not currently shipped with Vim, so it would cause an error if added without the plugin installed)- formatting of markdown lists is fixed
- the Neovim configuration tries to detect the background colour from the
environment variables
$BACKGROUND
(dark
orlight
) and$COLORFGBG
(<fgcolor>;<bgcolor>
, e.g.,7;0
is gray on black)
Many settings assume that my plugin collection is installed, and some plugin-related settings are in that collection (and not duplicated here anymore).
p
– in visual mode, put (paste) over the selection without yanking the replaced textK
– show documentation for word under cursor (usingcoc
orale
if available, otherwise the normal Vim behaviour)- arrows (with Ctrl and Alt) escape sequences explicitly bound for various different terminals (not in Neovim)
- Alt-arrow mapped the same way as in macOS, i.e., skip words left/right, or to beginning/end of line
- Ctrl–left and Ctrl–right mapped the same way as in macOS, i.e., line beginning/end
- Ctrl–up and Ctrl–down move visually, i.e., lines on screen instead of lines in file
- Ctrl-A – go to the beginning of line
- Ctrl-E – go to the end of line (unless pop-up completion menu is open, in which case close it)
- Ctrl–B – in insert mode, insert the character below the cursor (the default mapping for Ctrl–E, but even the mnemonic makes more sense now)
- Ctrl–B – toggle paste mode, paste, and toggle paste mode again (Vim only)
- Esc – exit integrated terminal (press twice quickly to send to
- Esc Esc – in insert mode, clear highlighting of previous search
- Ctrl-_ – various bindings in different modes, not settled on a final choice yet
- Ctrl–J and Ctrl–K right after putting text in normal change the text that was put by cycling put history (depends on Yoink plugin)
- Ctrl-Q – in normal mode works as the original Tab binding (since usually I use a configuration that rebinds it), i.e., jump to newer cursor position (such as after jumping to an older position with Ctrl–O, which is also conveniently adjacent in Dvorak)
- Ctrl-Q – in insert mode inserts the previously inserted text, i.e., the original behaviour of Ctrl–A
Some additional bindings in the style of the "unimpaired" plugin:
[oa
/]oa
– turn auto-formatting (formatoptions+=a
) on/off[ot
/]ot
– turn text formatting (formatoptions+=t
) on/off]w
,[w
– jump to next/previous warning/error (using coc, ale, or the location list, in that order)
These bindings are for the normal mode, preceded by the leader (\):
1
–0
– switch to vim-buffet buffer 1–10f
– open quickfix if there are warnings/errorsF
– close quickfixl
– open location listL
– close location listq
– delete bufferx
– wipeout bufferd
– jump to definition of thing under cursor (if coc installed)r
– show references to the thing under cursor (if coc installed)c
– coc code action (if installed)cf
– coc autofix (if installed)R
orcr
– coc rename (if installed)s
– run Syntastic check, and open the location list if there are errorsS
– reset Syntastic, clearing all errorst
– toggle a split terminal console (the session remains even if toggled away from view) – Neovim onlyT
– split and open a terminal with the given commandu
– open function search/
– openfzf
search for lines in open buffers (if plugin installed)- Tab – create a new tab
- Shift + Tab – close tab
These bindings are for the normal mode, preceded by the local leader (Space):
1
–0
– switch to tab 1–10q
– close tabx
– force close tab- Tab – go to next tab
- Shift + Tab – go to previous tab
w
– open warnings/errors list (coc, or location list)W
– close warnings/errors listh
– openfzf
fuzzy search for "recently opened files" (if plugin installed)/
– openfzf
search for lines in this buffert
– open tag search (if fzf plugin is installed)T
– open tag search (if CtrlP plugin is installed)z
– openfzf
fuzzy search for files (powered byfd
if installed)
CD
– change the current window's working directory to that of the current fileCD!
– change every window's working directory to that of the current file
I have switched my default shell on most computers from bash
to zsh
. Many
of the features described here work specifically on zsh
, but many also work
on bash
, especially if they were configured in the 20 years before I made the
switch.
Configuration exists for .inputrc
and ls
colours for both GNU and BSD
variants. The autocompletion suggestions for zsh
are also coloured. If
zsh-syntax-highlighting
is installed, it is loaded. The colours somewhat
match my Vim colour scheme where applicable (although there is no separate dark
variant so some exceptions had to be made).
There is also my .profile_shared
configuration, which is meant to be sourced
from .profile
and .zprofile
. The settings are quite specific to me, so if
anyone else uses these config files, they probably shouldn't use it. But, to do
so, simply:
. "$HOME/.profile_shared"
It sets EDITOR
and VISUAL
to nvim
, vim
, or vi
, whichever is installed
(in that order). Flow control is disabled for the terminal, allowing
Ctrl–S and Ctrl–Q to be used for
keyboard shortcuts.
The profiles generally ensure that rvm
is loaded if installed, and that
PATH
contains rvm
directories in the correct order. ~/bin
and
/usr/local/bin
are also added to the path, in that order, so that things
installed in /usr/local/bin
override older versions shipped with the OS, and
~/bin
can be used to override both.
On machines where I set umask 027
(i.e., no default permissions for others),
it is also helpful to add to sudoers
or /etc/sudoers.d
:
Defaults umask_override
Defaults umask=0022
- the prompt truncates the current working directory in various ways, e.g., the
home directory is replaced by
~
, any long path before the root of the current git repository (if any) is truncated, if there are more than four directories remaining, only the first and last two are kept, and then the remaining is truncated from the left according to available space - the current git repository and branch are shown on the right-hand side (zsh
RPROMPT
feature – it disappears if input comes too close to it), and there are little+~
characters to indicate staged/unstaged changes to the repository - the repository name is truncated from the left according to available space, and removed entirely if it is already visible in the working directory (which is true most of the time since the repository root is used as the path root)
- the branch name on the prompt is truncated according to various rules, e.g.,
master
often becomesm
(but in a different colour to distinguish from a hypotheticalm
branch) - there is a single line above the prompt, which contains the current history
number (
$!
), and the exit status of the previous command if it failed (i.e., a non-zero$?
) - git merge/rebase/patch status is also show on this line
- the vi command-mode is shown with a
(vi)
indicator on the above line
Autocompletion is set to be case-, hyphen-, and underscore-insensitive. If
fzf
is installed, autocompletion is also made fuzzy.
- the window/screen/tmux title shows
user@host
when idle, followed by the git repository and branch (if any) - when executing a command, the title shows the command line, but precedes it
with the username if
sudo
has been used and the hostname if it is anssh
session - the file URL for
Terminal.app
is set if not in tmux and$TERM_PROGRAM
isApple_Terminal
If fasd
or z.sh
is installed (in that order) and the initially empty file
~/.fasd-init-zsh
(or ~/.z
for z.sh
) exists, then it is loaded and its
aliases setup. Both include at least z
, which jumps to a directory matching
the partial name, e.g., z dot
probably jumps to ~/.dotfiles
if you have
been using that directory.
If fasd
and fzf
are both enabled, then all interactive selections in fzf
are replaced by fzf
.
For fasd
, the set of aliases is:
z dir
– jump from anywhere to directory matching the partial namedir
zz dir
– asz
, but interactively select the directory if there are multiple matcheszzz file
– interactively select a file or directory, and jump to the directory containing it (even if it is a directory in itself)d dir
– print the directory matching the partial namedir
sd dir
– as above, but interactively disambiguatef file
– print the file matching the partial namefile
sf dir
– as above, but interactively disambiguatea any
– print the directory or file matching the partial nameany
any any
– print the directory or file matching the partial nameany
v file
– edit the file in vivv file
– as above, but interactively disambiguate
.inputrc
has bindings for a large selection of terminals- arrow keys with alt are bound as per macOS defaults
- Ctrl–A and Ctrl–E go to the beginning/end of the line
- Alt-arrow mapped the same way as in macOS, i.e., skip words left/right, or to beginning/end of line
- Ctrl–left and Ctrl–right mapped the same way as in macOS, i.e., line beginning/end
- Ctrl-Space – opens the current command line in an editor
- Ctrl-Q –
push-line-or-edit
, if you are in a multi-line command it makes all prior lines editable again, otherwise it kills the line and pastes it back on the next empty prompt (e.g., use this to get rid of an unfinished command while you look atman
, then it comes back automatically on the next prompt) - Ctrl-R in zsh Vi insert mode activates a fuzzy command history search with the current command-line's contents and replaces the command-line with the selection (mnemonic: Repeat command)
- Ctrl-S in zsh Vi insert mode toggles
sudo
at the beginning of the command-line (also toggles the aliasplease
on an empty line, and betweenvi
/$EDITOR
and the aliassvi
) - Ctrl-Z on an empty prompt in insert mode – if the
on the first line, execute
fg
(i.e., bring suspended process to foreground, allowing to toggle suspend/resume with the same keystroke), otherwise make previous lines of the multi-line prompt editable again - Ctrl-U – kills the whole line (not just backwards from the cursor, as is the default)
- Ctrl-Y – yanks (or, more accurately, puts) the previously-killed line
- Ctrl-F – in zsh Vi insert mode starts a fuzzy file finder (requires fzf and fd), with keyboard shortcuts to change the list to show everything, only directories, only the current directory, or Git repository contents (including submodules)
- Ctrl-G – in zsh Vi insert mode shows a prompt to choose from Git commits, branches, tags, or files (not including submodules), or GitHub issues or pull requests, and starts a fuzzy finder for the choice, with live preview
S
+ surround – in visual selection mode surrounds the selection with the given quotes, e.g.,v$S"
in vi command mode selects to the end of the line and surrounds the selection with" "
quotes
ls
–ls
with color optionsll
–ls -l
la
–la
l.
– list hidden files onlymd
– make a directory, including the parent directories (mkdir -p
) andcd
to itplease
– re-run the entire previous command withsudo
(note: this is not just puttingsudo
in front of the command, but rather the entire command is executed undersudo
so any pipes and redirects also gain privileges)clc
– copy the last command to system clipboardclct
– copy the last command to tmux bufferplc
– paste command-line from system clipboard (but do not execute it)plct
– paste command-line from tmux buffer (but do not execute it)cpwd
– copy the current working directory to system clipboardcpath
– copy the current path, with symlinks expanded, to system clipboardgr
–grep
, excluding.git
vi
–nvim
(if installed)nvis
–nvim -S Session.vim
(if installed and the file exists)svi
–sudo -e
psg
–grep
the output ofps
hgrep
–grep
historyagrep
–grep
aliasescdf
– openfzf
to fuzzily search for directories andcd
to the selected one (can take arguments, e.g.,cdf /
will search from the root instead of from the current directory)fzh
– usefzf
to fuzzily search command history, and paste the selection on the command-line (but do not execute it)fzk
– usefzf
to fuzzily search running processes, and pass them (and any arguments) tokill
Also adds the following reusable zsh
aliases that just print the selection to
stdout
:
ffz
– fuzzily find a file or directoryfff
– fuzzily find a find a fileff.
– fuzzily find a file in the current directoryffd
– fuzzily find a directory
Each of these can take a path as an argument, e.g., ffz /
will seach from the
root instead of from the current directory. Remember that Tab can
complete the search in zsh when pressed after the closing backtick
`
. But also note that Ctrl–F is bound to
these same features in my zsh configuration…
cdr
–cd
to the root of the repositorycdrr
–cd
to the root of the outermost repository (from submodules at any depth)gs
–git status
glast
– show the last commitggl
–git log
with a branching graphgcl
–git clone --recurse-submodules
gpull
–git pull
gupdate
–git pull --rebase --autostash -v
gpush
–git push
gpusht
–git push && git push --tags
gpusha
–git push --all && git push --tags
gsubu
–git submodule update --init --recursive
gsubr
–git submodule update --remote --recursive
gls
–git ls-files --exclude-standard
glsm
–git ls-files -m -o --exclude-standard
(modified files)gbranch
–git checkout -b
gfeature
– make a new branch, prefixing the name given as argument withfeature/
, and push the branch to upstream (defaultorigin
, but may be given as the second argument)gfeaturedone
– push and then delete the current branch if its name starts withfeature/
and check outmaster
(or the branch given as argument)gtag
– create a new signed tag, and push tagsgresetmb
–git reset
to merge base ofHEAD
and the commit or branch (defaultmaster
) given as argument (e.g.,gresetmb develop
will reset the current feature branch to the point where it diverged from the branchdevelop
, and all changes since will show as changes to the working copy)
The following aliases have an interactive, fuzzy-searchable selection which
requires fzf
, and most are only for zsh. Where applicable, there
is an additional binding of Ctrl–A to select
all. Pressing Esc leaves the selection (e.g., for gdf
which
intentionally doesn't close after selection).
gcommit
– interactively select files to commit, stage, unstage, edit, diff, etcgdf
– view the diff of modified files without leaving the selection, with a live preview of the diff (this supports multiple keyboard shortcuts, shown on the screen, to perform various actions, such as staging/unstaging files, opening them in the editor or difftool, etc.)gdfs
orgstaged
– view staged files and diff, unstage, or commit themge
– open a file in$EDITOR
gadd
– select modified files to stage (git add
)gunstage
– select staged files to unstage (git restore --staged
)gdiscard
– select modified files to discard changes of (git restore
)gdt
– select modified files to open ingit difftool
gmt
– select unmerged files to open ingit mergetool
gstash
– view stashes and diff them; there are also keyboard shortcuts to apply/pop the stash (Ctrl–A), and to branch the stash (Ctrl–B)gcheckout
orgco
– check out a branch or taggcheckoutb
orgcobranch
– check out a branchgcheckoutt
orgcotag
– check out a taggcheckoutc
orgcocommit
– check out a commitgrebase
– select branch and rebasegrebasei
– select branch and rebase interactivelygrebasec
– select commit and rebase interactivelygmerge
– select branch and mergegmergef
– select branch and merge, no fast forward (e.g., merge a feature branch and force there to be a new commit)greset
– select a branch and reset to its stateglog
– view individual commits and their logsgcherry
– cherry-pick an individual commit (this can take a branch as the first argument, other arguments are passed to thegit commit
command)gfixup
– select a commit to fix-up with a new commitgrevert
– select a commit to revertgbranchdel
– select a branch to removegmovetobranch newbranch
– move the current state to the new branchnewbranch
(also stashing any changes to working copy and moving them), then interactively pick a commit and hard reset the current branch to that commit (i.e., the chosen commit is the last one to keep on the current branch), then switch to the new branch (e.g., realize that the most recent commits should have been on a new feature branch, and retroactively move them to one)gtagdel
– select a tag to removegissues
– view GitHub issues interactively (requireshub
)gissuecommit
– select an issue and pre-populate "Closes #" into the message of a new commit (requireshub
)gpullrs
– view GitHub pull requests interactively (requireshub
)gcistatus
– select a commit and view its CI status (requireshub
)fzc
– select one or more commits and print their hashes (e.g., to be used as part of other commands, like:git rebase --onto `fzc`Tab
)fzbr
– select a branch and print its name (e.g., to be used as part of other commands)fzbrr
– select a branch, including remotes, and print its name (e.g., to be used as part of other commands)fztag
– select a tag and print its name (e.g., to be used as part of other commands)fzbrt
– select a branch or tag and print its name (e.g., to be used as part of other commands)fzgf
– select a file from the git repository and print its namefzgcf
– select from changed files in the git repository and print its namefzgfr
– select a file from the git repository, or its submodules, and print its namefziss
– select a GitHub issue and print its number (e.g., to be used as part of other commands)fzpullr
– select a GitHub pull request and print its number (e.g., to be used as part of other commands)
Most of the commands will take arguments, which will generally be passed on to
the eventual git command (e.g., gmerge --squash
will result in git merge --squash
). Most of commands that select a commit can take a branch name to
choose commits from a branch other than the current, e.g., gcherry master
would cherry-pick from commits on master
. In cases where the argument doesn't
make sense otherwise, it is used as the initial search, e.g., gco origin
would start the branch selection with origin
already written into the
search. This is handy when you know that a given search term will only give one
result, then you can just do gco f/bar
EnterEnter
(although it is identical to gco
Enterf/bar
Enter, the
former retains the search string in shell command history).
Global aliases are a zsh
feature that allows alias expansions anywhere on the
command-line. All of mine are uppercase and begin with a :
to make accidental
use unlikely. The command-line is configured to expand such aliases immediately
when pressing space, e.g., cat file :H1
will expand the :H1
to | head -1
so that it may be edited or followed by more pipes.
:L
–| less
:LE
-|& less
:G
–| grep
:FG
–| grep -F
:EG
–| egrep
:GR
–|& grep
:FGR
–|& grep -F
:H1
–| head -1
:T1
–| tail -1
:H
–| head
:T
–| tail
:S
–| sort
:SN
–| sort -n
:SU
–| sort -u
:N
–>/dev/null
:NUL
–>/dev/null 2>&1
:WC
–| wc -l
:VL
–| viless
(an included script for use ofvim
ornvim
asless
):VI
–| vim -R -
:VIM
–|& vim -R -
:AG
–| ag
Plugins that need extensive external utilities or configuration are not included in my plugin collection. Some that I may use include:
Also note that coc has various extensions that it can install by itself, e.g.:
:CocInstall coc-tag
:CocInstall coc-emoji
The scripts clipcopy
and clippaste
copy and paste to/from the system
clipboard (trying to auto-detect macOS, X11, etc.). They fall back to the tmux
buffer if no known system clipboard is available.
The tmux configuration enables sensible modern defaults (e.g., mouse, focus events), status bar, window titles, on-demand pane titles and borders.
Unless otherwise noted, the following bindings are all after the prefix (Ctrl–T in my configuration):
r
– reload configuration from disk|
– split the window horizontally, opening in the current directory\
– split the window horizontally at full width-
– split the window horizontally, opening in the current directory_
– split the window horizontally at full widthh
– split the window vertically at full width, opening in the current directory (yes, theh
splits vertically andv
horizontally in tmux terminology, to match the Vim terminology where the direction describes the new pane and not the split)v
– split the window horizontally at full width, opening in the current directoryV
– split the window horizontally and select another pane to place in the splitH
– split the window vertically and select another pane to place in the splitM
– choose a window to move to (swap with) the current<
– swap the pane left>
– swap the pane right!
– break the current pane into a new window (tab)A
– rename the current windowO
– toggle mouse on/offR
– refresh the screenS
– toggle synchronize panes (i.e., all panes get the same keyboard input)x
– kill the current paneX
– kill the current windowy
– in copy mode, copies to the system clipboard
The included bin/tmx
script is useful for launching tmux
. If creates
separate "master" and "slave" sessions, which allows multiple computers on the
same master session to have their individual state in their private slave
session. Running it without arguments generally does the correct thing, i.e.,
creates a new slave session and attaches it to any existing master, or creates
the master if it doesn't exit.
A master session name can be given as the argument, e.g., tmx foo
uses the
session foo
instead of the default (0
), and creates the foo
master if it
doesn't already exist, and attaches a new slave to it. If the master session
name is given, a slave session name may be given as the second argument. This
will detach and recycle any existing slave session of that name, e.g.,
a network connection can use the same slave session to detach any hanging old
connections on reconnect.
As a special case, tmx ls
simply does tmux ls
and exits. Also, if the first
argument is prefix
, the prefix is set to the second argument, and then the
two first arguments are discarded. For example, tmx prefix '^a' foo
would use
foo
as the master session name and set the prefix to Ctrl-A.
The included .gitconfig_shared
is not used by default, it needs to be
included by copying this to .gitconfig
:
[include]
path = .gitconfig_shared
The shared configuration enables a global ignorefile ~/.gitignore_global
(which ignores some common rubbish). The following aliases are added:
unstage
– unstage staged changeslast
– show the last commitl
– pretty-print the log with colorsll
– pretty-print the loggl
– log with branching graphdt
– difftoolmt
– mergetoolpur
–pull --rebase
pura
–pull --rebase --autostash
puf
–push --force-with-lease
put
–push --tags
subu
–submodule update --init --recursive
subr
–submodule update --remote --recursive
pushu
–push -u origin HEAD
The .gitconfig_shared
also contains a difftool and mergetool definitions for
nvim
, as well as an additional mergetool definition for nvimfugitive
for
nvim
using the fugitive.vim
plugin. The tools are not enabled in this
configuration, rather copy the following to your .gitconfig
:
[diff]
tool = nvim
[merge]
tool = nvimfugitive
The configuration .ssh/config_shared
sets up some defaults. It is not used by
default, i.e., it needs to be included from ~/.ssh/config
with:
Include config_shared
The included .XResources
sets up xterm
with my light background colour
scheme.
The files ~/Documents/Arkku.terminal
and ~/Documents/Arkku Dark.terminal
(on macOS only) contain settings for Terminal.app, including keyboard bindings
and colour schemes (the light is almost the same as my ancient xterm
theme
and the dark is the same as my Neovim colour scheme). These files need to be
opened and imported into Terminal settings to take effect.
A legacy configuration for screen
is included, since screen
is still useful
as a serial port terminal.
Settings are provided in .indent.pro
for sensible C indentation.
Settings are provided for lldb and gdb, that both simply set Intel syntax for assembly.
Settings are provided for radare2, mainly to set Intel syntax for assembly and to enable fancy UTF-8.
Colour schemes and key bindings are included for XCode. They need to be selected from preferences to be active.
To use the Swift development toolchain:
export PATH="/Library/Developer/Toolchains/swift-latest.xctoolchain/usr/bin:$PATH"
:CocInstall coc-json
:CocInstall coc-html
:CocInstall coc-css
:CocInstall coc-yaml
:CocInstall coc-sourcekit
:CocInstall coc-tsserver
:CocInstall coc-solargraph