diff --git a/.gitconfig b/.gitconfig index 5d2466e..9a6cc11 100644 --- a/.gitconfig +++ b/.gitconfig @@ -7,10 +7,13 @@ st = status cm = commit -m aa = add --all . + show-origin-url = remote get-url origin cam = !git add --all . && git commit --amend --no-edit rbs = !git checkout main && git pull && git checkout - && git rebase main cop = "!f() { git checkout ${1-main}; git pull; }; f" lazy = commit -C HEAD@{1} + cp = cherry-pick + anne = commit --amend --no-edit [init] defaultBranch = main [pull] @@ -22,3 +25,8 @@ lowSpeedLimit = 1000 lowSpeedTime = 60 postBuffer = 524288000 +[filter "lfs"] + clean = git-lfs clean -- %f + smudge = git-lfs smudge -- %f + process = git-lfs filter-process + required = true diff --git a/.gitignore b/.gitignore index 611522a..6daba93 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /history +/.vscode/extensions diff --git a/.init_profile b/.init_profile new file mode 100644 index 0000000..d433f66 --- /dev/null +++ b/.init_profile @@ -0,0 +1,44 @@ +#!/usr/bin/env sh + +## Source all scripts in ~/.rc.d +if [ -d "$HOME/.rc.d" ]; then + for f in "$HOME/.rc.d"/*.sh; do + if [ -r "$f" ]; then + . "$f" + fi + done + + # Source shell-specific scripts if any + if [ -n "$BASH_VERSION" ]; then + for f in "$HOME/.rc.d"/*.bash; do + if [ -r "$f" ]; then + . "$f" + fi + done + elif [ -n "$ZSH_VERSION" ]; then + for f in "$HOME/.rc.d"/*.zsh; do + if [ -r "$f" ]; then + . "$f" + fi + done + fi +fi + +## Autocompletion (Bash) +if [ -n "$BASH_VERSION" ]; then + if ! shopt -oq posix; then + if [ -f /usr/share/bash-completion/bash_completion ]; then + . /usr/share/bash-completion/bash_completion + elif [ -f /etc/bash_completion ]; then + . /etc/bash_completion + fi + fi +fi + +## Paths +# Prepend common personal bin directories to path +if [ -d "$HOME/bin" ] ; then PATH="$HOME/bin:$PATH"; fi +if [ -d "$HOME/.bin" ] ; then PATH="$HOME/.bin:$PATH"; fi +if [ -d "$HOME/.local/bin" ] ; then PATH="$HOME/.local/bin:$PATH"; fi +if [ -d "$HOME/Applications/bin" ] ; then PATH="$HOME/Applications/bin:$PATH"; fi +export PATH diff --git a/.rc.d/aliases.sh b/.rc.d/aliases.sh index cf2a146..2271bb1 100755 --- a/.rc.d/aliases.sh +++ b/.rc.d/aliases.sh @@ -6,50 +6,67 @@ ensure_alias() { fi } -# Detect WSL -is_wsl=false -if grep -qi microsoft /proc/version 2>/dev/null; then - is_wsl=true -fi +is_macos() { [ "$(uname)" = "Darwin" ]; } -# TODO: detect color support and enable/disable color in aliases based on that. -# File Manipulation -# TODO: bash ls doesn't need -G or maybe macs don't. Figure that out and use that test here. -alias ls='ls -G --color=auto' -alias lsd='ls -G --color=auto -d' -alias ll='ls -G --color=auto -l' -alias lld='ls -G --color=auto -l -d' -alias lsg='ls | grep --color' -alias llg='ls -l| grep --color' -#alias ln='ln -ivw' -alias ln='ln -iv' -alias grep='grep --color=auto' -alias fgrep='fgrep --color=auto' -alias egrep='egrep --color=auto' +is_linux() { [ "$(uname)" = "Linux" ]; } + +is_wsl() { + # Detect WSL1/WSL2/WSLg kernels + case "$(uname -r)" in + *Microsoft*|*microsoft*|*WSL2*|*WSLg*) return 0 ;; + esac + return 1 +} + +if is_macos; then alias ls='ls -G' +elif is_linux; then alias ls='ls --color=auto'; fi +alias lsd='ls -d' +alias ll='ls -l' +alias lld='ls -l -d' +alias lsg='ls | grep' +alias llg='ls -l | grep' +if is_macos; then alias ln='ln -ivw' +elif is_linux; alias ln='ln -iv'; fi +if is_linux; then + alias grep='grep --color=auto' + alias fgrep='grep --color=auto -F' + alias egrep='grep --color=auto -E' +else + alias fgrep='grep -F' + alias egrep='grep -E' +fi alias slash='ls -SlAhr' alias slasher='ls -SlAh' alias slashed='ls -SlAhrd' -alias ds='function f() { du -h -d 1 $* | sort -h | tee ~/dirsize ; unset -f f; }; f' -alias dud='function { du -h -d 1 $* | sort -h }' -alias dud='function f() { du -h -d 1 "$@" 2>/dev/null | sort -h ; unset -f f; }; f' -alias dudr='function { du -h -d 1 $* | sort -h -r }' -alias dudr='function f() { du -h -d 1 "$@" 2>/dev/null | sort -h -r ; unset -f f; }; f' +ds() { + du -h -d 1 "$@" | sort -h | tee "$HOME/dirsize" +} +dud() { + du -h -d 1 "$@" 2>/dev/null | sort -h +} +dudr() { + du -h -d 1 "$@" 2>/dev/null | sort -h -r +} alias mvn='mv -n' -alias gmv='mv $* ~/Google\ Drive/My\ Drive/' -alias gmvn='mv -n $* ~/Google\ Drive/My\ Drive/' -alias omv='mv $* ~/OneDrive/' -alias omvn='mv -n $* ~/OneDrive/' +gmv() { mv "$@" "$HOME/Google Drive/My Drive/"; } +gmvn() { mv -n "$@" "$HOME/Google Drive/My Drive/"; } +omv() { mv "$@" "$HOME/OneDrive/"; } +omvn() { mv -n "$@" "$HOME/OneDrive/"; } alias mv='mv -i' alias rm='rm -i' alias rs='rsync -avhz --progress' -alias rsfat='rs --no-perms --no-owner --no-group --no-times' -alias rscheck='function f() { rsync -avhzc --itemize-changes --dry-run "$1" "$2" | grep "^>f[^+].*[sc]" ; unset -f f; } ; f' +alias rsfat='rsync -avhz --progress --no-perms --no-owner --no-group --no-times' +rscheck() { + rsync -avhzc --itemize-changes --dry-run "$@" | + grep "^>f[^+].*[sc]" +} alias md=mkdir alias rd=rmdir # Git shortcuts alias it=git -alias rsgit='rsync -avhz --no-perms --exclude='\''.git'\'' --exclude='\''.vscode'\' +alias rsgit="rsync -avhz --no-perms --exclude='.git' --exclude='.vscode'" + # Bazel shortcuts alias refresh_bazel='bazel run @hedron_compile_commands//:refresh_all' @@ -63,17 +80,30 @@ alias cbq='clear && bazel query //...' # Utilities alias iwyu='include-what-you-use' -alias show-android-emulators="ps aux | head -n 1 && ps aux | grep avd | sed '$d'" -alias kill-all-android-emulators='adb devices | grep emulator | cut -f1 | while read line; do adb -s $line emu kill; done' +show_android_emulators() { + ps aux | head -n 1 + ps aux | grep avd | sed '$d' +} +kill_all_android_emulators() { + adb devices | + awk '/emulator/{print $1}' | + while read -r dev; do adb -s "$dev" emu kill; done +} alias freespace="df -I -h -T nodevfs | grep -i -v -E '/\.timemachine/|/System/Volumes/|/com\.apple\.TimeMachine\.localsnapshots/' | sed -e 's/ / /g'" alias fs="df -I -h -T nodevfs | grep -i -v -E '/\.timemachine/|/System/Volumes/|/com\.apple\.TimeMachine\.localsnapshots/' | sed -e 's/ / /g'" alias hashes='md5deep -r' # Mac equivalent of lsusb on linux -alias lsusb='system_profiler SPUSBDataType' +if is_macos; then alias lsusb='system_profiler SPUSBDataType'; fi alias tea='tee -a' -alias find_recent='function { find . $* -exec ls -ltr {} + }' -alias find_recent='function f() { find . $* -exec ls -ltr {} + ; unset -f f; }; f' -alias mount-nas='sshfs deepthought:/home/tom ~/nas/home' +find_recent() { + find . "$@" -exec ls -ltr "{}" + +} + +mount_nas() { + mkdir -p "$HOME/nas/home" + remote_home=$(ssh deepthought "printf %s \"\$HOME\"") + sshfs "deepthought:$remote_home" "$HOME/nas/home" +} # pbcopy if ! command -v pbcopy >/dev/null 2>&1; then @@ -81,7 +111,9 @@ if ! command -v pbcopy >/dev/null 2>&1; then ensure_alias pbcopy 'wl-copy' elif command -v xclip >/dev/null 2>&1; then ensure_alias pbcopy 'xclip -selection clipboard' - elif [ "$is_wsl" = true ] && command -v clip.exe >/dev/null 2>&1; then + elif command -v xsel >/dev/null 2>&1; then + ensure_alias pbcopy 'xsel --clipboard --input' + elif is_wsl && command -v clip.exe >/dev/null 2>&1; then ensure_alias pbcopy 'clip.exe' fi fi @@ -92,40 +124,83 @@ if ! command -v pbpaste >/dev/null 2>&1; then ensure_alias pbpaste 'wl-paste' elif command -v xclip >/dev/null 2>&1; then ensure_alias pbpaste 'xclip -selection clipboard -o' - elif [ "$is_wsl" = true ] && command -v powershell.exe >/dev/null 2>&1; then + elif command -v xsel >/dev/null 2>&1; then + ensure_alias pbpaste 'xsel --clipboard --output' + elif is_wsl && command -v powershell.exe >/dev/null 2>&1; then ensure_alias pbpaste 'powershell.exe -noprofile Get-Clipboard' fi fi +log_and_do() { + printf '# %s\n' "$1" >> "$2" + bash -c "$1" +} + # In Development -# Dosn't work if command is piped e.g. `log_and_do "ls | tee out.txt" my_other_file.txt` -# or stdout is redirected e.g. `log_and_do "ls > out.txt" my_other_file.txt` -alias log_and_do='function { `echo "# $1 >> $2\n" > $2 && echo $1` >> $2 }' - -# This should get the PIDs of any avd commands running and kill-9 them and then do the -# same as kill-all-android-emulators to clean them up after. -# alias kaae="kill -9 `ps aux | grep avd | sed '$d' | cut -f 2 -w` > /dev/null" - -# TODO: Stuff I don't know why other configs setup -#alias dir='dir --color=auto' -#alias vdir='vdir --color=auto' -#alias ll='ls -alF' -#alias la='ls -A' -#alias l='ls -CF' # From Bash on Ubuntu # Add an "alert" alias for long running commands. Use like so: # sleep 10; alert #alias alert='notify-send --urgency=low -i "$([ $? = 0 ] && echo terminal || echo error)" "$(history|tail -n1|sed -e '\''s/^\s*[0-9]\+\s*//;s/[;&|]\s*alert$//'\'')"' +alert() { + local last_cmd exit_status + exit_status=$? + + # Get last command text + if [[ -n "$ZSH_VERSION" ]]; then + last_cmd=$(fc -ln -1) + else + last_cmd=$(history | tail -n1 | sed 's/^[ ]*[0-9]\+[ ]*//') + fi + + # macOS notification + if is_macos; then + terminal-notifier -message "$last_cmd" \ + -title "Command finished (exit $exit_status)" + return + fi + + # Linux notification + if command -v notify-send >/dev/null 2>&1; then + notify-send "Command finished (exit $exit_status)" "$last_cmd" + fi +} -# WSL Specific -#alias pbcopy=clip.exe -#alias pbpaste="powershell.exe -noprofile Get-Clipboard" # SSH-Agent setup -# alias sshgo='eval $(ssh-agent -s) && ssh-add ~/.ssh/id_ed25519 ~/.ssh/id_rsa ~/.ssh/id_win_ed25519 ~/.ssh/id_win_rsa' -alias sshgo='eval $(ssh-agent -s) && for key in ~/.ssh/id_*; do [[ -f "$key" && "${key##*/}" != *.* ]] && ssh-add "$key"; done' +sshgo() { + # Start agent only if this shell doesn't already have one + if [[ -n "$SSH_AUTH_SOCK" && -n "$SSH_AGENT_PID" ]] && + ps -p "$SSH_AGENT_PID" >/dev/null 2>&1; then + echo "ssh-agent already running for this session." + else + eval "$(ssh-agent -s)" + fi + + # Load keys only if not already loaded + for key in "$HOME"/.ssh/id_*; do + [[ -f "$key" ]] || continue + [[ "$key" == *.pub ]] && continue + + fingerprint=$(ssh-keygen -lf "$key" | awk '{print $2}') + if ssh-add -l 2>/dev/null | grep -q "$fingerprint"; then + continue + fi + + ssh-add "$key" + done +} + +install_local_bin() { + sudo install -m 755 -o root -g root "$1" /usr/local/bin +} + +install_user_bin() { + mkdir -p "$HOME/bin" + cp "$1" "$HOME/bin/" +} +alias build_and_test='cmake -S . -B build && cmake --build build -- -j$(nproc) && ctest --test-dir build --output-on-failure' alias inspect-video='mediainfo --Inform="Video;Codec: %Format%\nProfile: %Format_Profile%\nResolution: %Width%x%Height%\nBitrate: %BitRate/String%\nBitrate mode: %BitRate_Mode%\nFrame rate: %FrameRate% fps\n"' alias wget-rip='wget --page-requisites --convert-links --adjust-extension --no-clobber --span-hosts' diff --git a/.rc.d/google-cloud-sdk.sh b/.rc.d/google-cloud-sdk.sh index 31c8b4e..8a61d02 100644 --- a/.rc.d/google-cloud-sdk.sh +++ b/.rc.d/google-cloud-sdk.sh @@ -1,6 +1,6 @@ # The next line updates PATH for the Google Cloud SDK. -if [ -f '/home/tom/Downloads/GCloud/google-cloud-sdk/path.bash.inc' ]; then . '/home/tom/Downloads/GCloud/google-cloud-sdk/path.bash.inc'; fi +if [ -f "$HOME/google-cloud-sdk/path.bash.inc" ]; then source "$HOME/google-cloud-sdk/path.bash.inc"; fi # The next line enables shell command completion for gcloud. -if [ -f '/home/tom/Downloads/GCloud/google-cloud-sdk/completion.bash.inc' ]; then . '/home/tom/Downloads/GCloud/google-cloud-sdk/completion.bash.inc'; fi +if [ -f "$HOME/google-cloud-sdk/completion.bash.inc" ]; then source "$HOME/google-cloud-sdk/completion.bash.inc"; fi diff --git a/import.sh b/import.sh index b6b03c4..a57d08c 100755 --- a/import.sh +++ b/import.sh @@ -1,11 +1,11 @@ #!/usr/bin/env bash SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -source "$SCRIPT_DIR/files.sh" +source "$SCRIPT_DIR/install_files" cd "$SCRIPT_DIR" || exit 1 -for file in "${FILES[@]}"; do +for file in "${IMPORT_FILES[@]}"; do if [ -e "../$file" ] || [ -L "../$file" ]; then cp -r "../$file" ./ fi diff --git a/install.sh b/install.sh index 44f4adc..3bb8063 100755 --- a/install.sh +++ b/install.sh @@ -1,13 +1,24 @@ #!/usr/bin/env bash SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -source "$SCRIPT_DIR/files.sh" +source "$SCRIPT_DIR/install_files" cd "$SCRIPT_DIR" || exit 1 -for file in "${FILES[@]}"; do +# Copy files and directories +for file in "${INSTALL_FILES[@]}"; do if [ -e "./$file" ] || [ -L "./$file" ]; then cp -r "./$file" ../ fi done +# Ensure ~/.bashrc and ~/.zshrc exist and source ~/.init_profile +SOURCE_LINE='[ -f "$HOME/.init_profile" ] && . "$HOME/.init_profile"' + +for rc in "$HOME/.bashrc" "$HOME/.zshrc"; do + touch "$rc" + if ! grep -qF "$SOURCE_LINE" "$rc"; then + printf "\n# Initialize profile environment\n%s\n" "$SOURCE_LINE" >> "$rc" + fi +done + diff --git a/files.sh b/install_files similarity index 73% rename from files.sh rename to install_files index 2d9ee1f..b423306 100644 --- a/files.sh +++ b/install_files @@ -1,18 +1,20 @@ -#!/usr/bin/env bash - -FILES=( - ".bash_logout" - ".bashrc" - ".config" +INSTALL_FILES=( ".gitconfig" ".gitignore" ".gitignore_global" ".hgignore_global" - ".profile" + ".init_profile" ".rc.d" ".yarnrc" + ".zsh_functions" +) + +IMPORT_FILES=( + "${INSTALL_FILES[@]}" + ".bash_logout" + ".bashrc" + ".profile" ".zprofile" ".zshenv" - ".zsh_functions" ".zshrc" )