-
Notifications
You must be signed in to change notification settings - Fork 23
/
config.fish
393 lines (338 loc) · 12.5 KB
/
config.fish
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
if not status --is-interactive
# Problem: Scripts are slow because my configuration in this file is slow.
# Solution: Skip the configuration if not running interactively.
#
# Unlike files like `~/.bashrc` (which runs only for interactive shells)
# shells, `config.fish` is run for *every* fish shell, including
# non-interactive shells. This was surprising to me.
#
# By skipping it, I speed up things like:
#
# * scripts that run with `#!/usr/bin/env fish`
# * fzf, surprisingly: $FZF_DEFAULT_COMMAND is run with $SHELL, approximately
# equivalent to doing `fish -c $FZF_DEFAULT_COMMAND`
#
# As a rough benchmark, skipping my configuration saves ~130ms on `fzf`
# initialization.
if not set -q I_REALLY_WANT_TO_RUN_FISH_CONFIG_FOR_FIND_LOCATION_OF
# This escape hatch means that things below can run in a non-interactive
# shell, so there are more checks below for `status --is-interactive`.
return 0
end
end
# tmux {{{
function inside_ssh
[ -n "$SSH_CLIENT" ] || [ -n "$SSH_TTY" ]
end
function in_vs_code
[ "$TERM_PROGRAM" = "vscode" ]
end
if not inside_ssh; and not in_vs_code; and status --is-interactive
# Connect to most recent tmux session
if not set -q TMUX; and tmux has-session 2>/dev/null
# We're not in tmux now, but a tmux session exists
# Get the name of the most recent tmux session, sorted by time the session
# was last attached.
set -f most_recent_tmux_session (
tmux list-sessions -F "#{session_last_attached} #{session_name}" | \
sort -r | \
cut -d' ' -f2 | \
head -1
)
tmux attach -t $most_recent_tmux_session
end
end
# }}}
# Aliases {{{
alias va "vim ~/.aliases.fish"
alias q "vim (readlink ~/.config/fish/config.fish)"
alias qq "source ~/.config/fish/config.fish"
alias cp "cp -iv"
alias rm "rm -Iv"
alias mv "mv -iv"
alias ls "ls -FGh"
alias du "du -cksh"
alias df "df -h"
# Use modern regexps for sed, i.e. "(one|two)", not "\(one\|two\)"
alias sed "sed -E"
alias dup "pushd dotfiles; and git checkout main &>/dev/null; and git pull; and git checkout - &>/dev/null; and popd; and qq"
# Remove fish's alias, which breaks completions when I add another one
functions -e diff
function diff -w diff
command diff --color=auto -U3 $argv
end
# It can be used anywhere, not just in git
alias diff-long-lines "git diff --word-diff=porcelain"
alias mkdir "command mkdir -p"
function serialnumber
ioreg -l | rg IOPlatformSerialNumber | sed -e 's/^.*= "(.+)"/\1/' | tee /dev/tty | pbcopy
echo '(Copied for you)'
end
alias prettyjson "jq ."
# xmllint is from `brew install libxml2`
alias prettyxml "xmllint --format -"
alias prettyhtml "prettier --stdin-filepath any-name-here.html"
alias prettyjavascript "prettier --stdin-filepath any-name-here.js"
# Remove EXIF data
alias exif-remove "exiftool -all "
alias hexdump hexyl
# All the flags I always want turned on
alias fd-basic "command fd --no-ignore --ignore-case --full-path --type file"
alias fd "fd-basic --type file"
[ -r ~/.rgrc ] && set -x RIPGREP_CONFIG_PATH ~/.rgrc
# Note that `bat` does not understand `~`, so we need `$HOME`
set -x BAT_CONFIG_PATH "$HOME/.config/bat/config"
alias cat bat
alias less bat
abbr -a -- - 'cd -'
alias dotfiles 'cd dotfiles'
# Slice out a piece of a string using a regex.
# For example:
# $ slice 'sd[fg]' 'asdf'
# sdf
function slice -a pattern s
string match -r $pattern $s
end
function dig-all -a url
if not string match -qre '^www\.' $url
printf "!! Note that CNAME cannot be on the bare domain\n\n" >&1
end
# Add a period to the end to canonicalize it, otherwise many records don't
# show up with the +norecurse flag
if not string match -qre '\.$' $url
set -f url "$url."
end
for record in a aaaa cname mx ns txt
# +noall: Turn off all output
# +answer: Show just the answer
dig +noall +answer $record $url
end
# Fastmail-specific email stuff
# https://www.fastmail.help/hc/en-us/articles/1500000280261-Setting-up-your-domain-MX-only#domain-registration
for fm in fm1 fm2 fm3
dig +noall +answer CNAME $fm._domainkey.$url
end
dig +noall +answer TXT _dmarc.$url
end
# Show a Notification Center notification. Good for long-running tasks:
# long_running_task && notifyme "All done"
function notifyme
set -l words (string join " " $argv)
osascript -e "display notification \"$words\" with title \"Title\""
end
# }}}
# Options {{{
# Note that these FZF options are used by fzf.vim automatically! Yay!
# Use a separate tool to smartly ignore files
set -x FZF_DEFAULT_COMMAND 'rg --hidden --files --ignore-file ~/.ignore'
set -x FZF_DEFAULT_OPTS_FILE $HOME/.fzfrc # Doesn't expand ~, so use $HOME
# }}}
# Completion {{{
if status --is-interactive
complete -c tcd --no-files -a "(__fish_complete_directories)"
# Ensure we never limit to 1 file (the conditions accrete)
complete -c t --no-files
# Complete exactly 1 argument (drawn from tmux session names)
# The special printing format is `#{?condition,IF_TRUE,IF_FALSE}`.
# So we only print the session name if it's not the current attached session.
# This prints an empty new line for the current session, which fish
# automatically ignores.
complete -c t -a "(tmux ls -F '#{?session_attached,,#{session_name}}')" --condition "__fish_is_first_arg"
complete -c viw -w which
complete -c find-location-of -w which
complete -c fly -w flyctl
# Complete `staging` like the `heroku` command
complete -c staging -w heroku
# Add a `deploy` subcommand, while keeping the standard Heroku completions
complete -c staging -n __fish_use_subcommand -a deploy -d "Deploy to staging"
# Complete `production` like the `heroku` command
complete -c production -w heroku
# Add a `deploy` subcommand, while keeping the standard Heroku completions
complete -c production -n __fish_use_subcommand -a deploy -d "Deploy to production"
for script in ~/.config/fish/completions/*.fish
source $script
end
end
# }}}
# Key bindings {{{
# Vim-style line editing
if status --is-interactive
fish_vi_key_bindings
set fish_cursor_default block
set fish_cursor_replace_one underscore
set fish_cursor_visual block blink
end
# Fuzzy match against history, edit selected value
# For exact match, start the query with a single quote: 'curl
function fuzzy-history
test -n "$FZF_TMUX_HEIGHT"; or set FZF_TMUX_HEIGHT 40%
set -lx FZF_DEFAULT_OPTS "--height $FZF_TMUX_HEIGHT $FZF_DEFAULT_OPTS $FZF_CTRL_T_OPTS"
# Copied from `fzf-history-widget`:
# https://github.com/junegunn/fzf/blob/master/shell/key-bindings.fish
# `-z` uses null bytes to terminate lines so we can find multi-line commands.
history -z | fzf --read0 --print0 -q (commandline) | read -lz result
and commandline -- $result
commandline -f repaint
end
# Use Alfred's database of clipboard history and run it through FZF
function fuzzy-clipboard-history
set -l clipboard_db "$HOME/Library/Application Support/Alfred/Databases/clipboard.alfdb"
set -l column_name "item"
set -l query (string join ' ' 'SELECT replace(item, CHAR(10), "") as ' $column_name ' FROM clipboard ORDER BY ts DESC;')
sqlite3 -line -noheader "$clipboard_db" $query 2>/dev/null | \
sed -n -e "s/$column_name = //p" | \
fzf --no-sort --multi
end
if status --is-interactive
# Ctrl-r triggers fuzzy history search
bind -M insert \cr 'fuzzy-history'
# Ctrl-v opens command line in your editor
bind -M insert \cv edit_command_buffer
# Ctrl-p shows clipboard history in FZF and copies the selected item
bind -M insert \cp 'fuzzy-clipboard-history'
end
# }}}
# cdpath {{{
if status --is-interactive
function add_dir_to_cdpath -a directory
if [ -d "$directory" ]
set -g CDPATH $CDPATH $directory
end
end
function add_subdirs_to_cdpath -a directory
for subdir in $directory/*/
set -g CDPATH $CDPATH (string replace -r '/$' '' $subdir)
end
end
add_dir_to_cdpath $HOME/code
add_subdirs_to_cdpath $HOME/code
add_subdirs_to_cdpath $HOME/code/work
# Prepend `.` so that directories in the current dir are tried first
set -g --prepend CDPATH .
end
# }}}
# Prompt {{{
if status --is-interactive
starship init fish | source
end
# }}}
# Git {{{
alias gd "git diff"
alias gdm "git master-to-main-wrapper diff origin/%BRANCH%"
alias amend "git commit --amend -Chead"
alias amend-new "git commit --amend"
alias ga "git add"
alias gcp "git rev-parse HEAD | xargs echo -n | pbcopy"
# }}}
# Editor {{{
# Why set $VISUAL instead of $EDITOR?
# http://robots.thoughtbot.com/visual-ize-the-future
set -x VISUAL vim
set -x EDITOR $VISUAL
alias vi $VISUAL
# }}}
# Ruby/Rails {{{
alias h heroku
alias migrate "be rake db:migrate db:test:prepare"
alias rollback "be rake db:rollback"
alias remigrate "migrate && rake db:rollback && migrate"
alias rrg "rails routes | rg"
alias db-reset "be rake db:drop db:create db:migrate db:test:prepare"
alias unfuck-gemfile "git checkout HEAD -- Gemfile.lock"
# Bundler
alias be "bundle exec"
alias tagit '/usr/local/bin/ctags -R'
# }}}
# Postgres {{{
# Set filetype on editing. Use `\e` to open the editor from `psql`.
set -x PSQL_EDITOR "vim -c ':set ft=sql'"
# }}}
# Homebrew {{{
# Opt out of sending Homebrew information to Google Analytics
# https://docs.brew.sh/Analytics
set -x HOMEBREW_NO_ANALYTICS 1
# Do not auto-update Homebrew.
set -x HOMEBREW_NO_AUTO_UPDATE 1
# Always cleanup after installing or upgrading
set -x HOMEBREW_INSTALL_CLEANUP 1
# }}}
# Set up SSH helper (mostly for Git)
if status --is-interactive
ssh-add -K ~/.ssh/id_rsa 2> /dev/null
end
# The `$TERM` is `alacritty`, which is non-standard and makes various CLI
# commands on Digital Ocean think they're in an unsupported terminal.
# The `SetEnv` option (e.g. `-o 'SetEnv TERM=xterm-256color'` or adding it to
# `~/.ssh/config`) only works on OpenSSH >= 8.7, which is not built in on macOS.
# So we'll just do this for now.
alias ssh "TERM=xterm-256color command ssh"
# $PATH {{{
# $PATH stuff is last so that other things don't add their own $PATH stuff
# before it.
# Note that `fish_add_path` will prepend by default.
# It is also universal by default, unless you pass "--path".
# Add Homebrew to the path.
fish_add_path --path /usr/local/bin /usr/local/sbin
# Heroku standalone client
fish_add_path --path /usr/local/heroku/bin
# Node
set PATH $PATH ".git/safe/../../node_modules/.bin/"
# Postgres.app takes precedence
fish_add_path --path /Applications/Postgres.app/Contents/Versions/latest/bin
fish_add_path --path --move $HOME/.bin
# Rust
[ -d "$HOME/.cargo/bin" ] && fish_add_path --path $HOME/.cargo/bin
# rbenv
status --is-interactive; and rbenv init - fish | source
# Prepend binstubs *after* doing rbenv.
# Do not use `fish_add_path` because that will expand `.` to wherever you are
# when you sourced `config.fish`. I want it to refer to the current directory
# wherever I am.
set PATH ./bin/stubs $PATH
# Node
if status --is-interactive
eval "$(fnm env --use-on-cd --log-level=error)"
end
# Go
# `go install` will install executables to ~/.bin
set -x GOBIN ~/.bin
# }}}
[ -r ~/.aliases.fish ] && source ~/.aliases.fish
if status --is-interactive
set -U fish_greeting ""
# Erase a global (non-universal) variable if set, since it interferes with the
# universal one.
set --erase fish_features
# ampersand-nobg-in-token: `&` is no longer interpreted as the backgrounding
# operator in the middle of a token, so dealing with URLs becomes easier.
# qmark-noglob: `?` is no longer interpreted as a glob operator in the middle
# of a token, so dealing with URLs becomes easier.
set -U fish_features stderr-nocaret ampersand-nobg-in-token qmark-noglob
# Colorscheme: Dracula
set -U fish_color_normal normal
set -U fish_color_command F8F8F2
set -U fish_color_quote F1FA8C
set -U fish_color_redirection 8BE9FD
set -U fish_color_end 50FA7B
set -U fish_color_error FFB86C
set -U fish_color_param FF79C6
set -U fish_color_comment 6272A4
set -U fish_color_match --background=brblue
set -U fish_color_selection white --bold --background=brblack
set -U fish_color_search_match bryellow --background=brblack
set -U fish_color_history_current --bold
set -U fish_color_operator 00a6b2
set -U fish_color_escape 00a6b2
set -U fish_color_cwd green
set -U fish_color_cwd_root red
set -U fish_color_valid_path --underline
set -U fish_color_autosuggestion BD93F9
set -U fish_color_user brgreen
set -U fish_color_host normal
set -U fish_color_cancel --reverse
set -U fish_pager_color_prefix normal --bold --underline
set -U fish_pager_color_progress brwhite --background=cyan
set -U fish_pager_color_completion normal
set -U fish_pager_color_description B3A06D
set -U fish_pager_color_selected_background --background=brblack
end