#!/usr/bin/env bash # shellcheck shell=bash # vim: filetype=zsh # Set XDG directories if not already set # https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html [ -z "$XDG_CONFIG_HOME" ] && export XDG_CONFIG_HOME="$HOME/.config" [ -z "$XDG_DATA_HOME" ] && export XDG_DATA_HOME="$HOME/.local/share" [ -z "$XDG_CACHE_HOME" ] && export XDG_CACHE_HOME="$HOME/.cache" [ -z "$XDG_STATE_HOME" ] && export XDG_STATE_HOME="$HOME/.local/state" [ -z "$XDG_BIN_HOME" ] && export XDG_BIN_HOME="$HOME/.local/bin" [ -z "$XDG_RUNTIME_DIR" ] && export XDG_RUNTIME_DIR="$HOME/.local/run" # if DOTFILES is not set, set it to the default location [ -z "$DOTFILES" ] && export DOTFILES="$HOME/.dotfiles" # zsh completions directory [ -z "$ZSH_COMPLETIONS" ] && export ZSH_COMPLETIONS="$XDG_CONFIG_HOME/zsh/completion" export PATH="$XDG_BIN_HOME:$DOTFILES/local/bin:$XDG_DATA_HOME/bob/nvim-bin:$XDG_DATA_HOME/cargo/bin:/opt/homebrew/bin:/usr/local/bin:$PATH" # Add zsh completions to FPATH, compinit will be called later FPATH="$ZSH_COMPLETIONS:$FPATH" if ! command -v msg &> /dev/null; then # Function to print messages if VERBOSE is enabled # $1 - message (string) msg() { [[ $VERBOSE -eq 1 ]] && msgr msg "-> $1" return 0 } fi # Cache commands using bkt if installed if command -v bkt &> /dev/null; then bkt() { command bkt --cache-dir="$XDG_CACHE_HOME/bkt" "$@" } else # If bkt isn't installed, skip its arguments and just execute directly. # Optionally write a msg to stderr suggesting users install bkt. bkt() { while [[ $1 == --* ]]; do shift; done "$@" } fi # Shorthand for checking if the system has the bin in path, # this version does not use caching. # Usage: have_command php && php -v have_command() { [ -z "$1" ] && { echo "Usage: have_command " return 1 } command -v "$1" &> /dev/null } # Shorthand for checking if the system has the bin in path, # this version uses caching. # Usage: have php && php -v have() { bkt -- which "$1" &> /dev/null } # Function to run dark-notify and change alacritty theme # It uses flock to prevent running multiple instances. # Install flock with `brew install flock` on macOS. darknotify_alacritty() { x-have flock && [[ -f /tmp/dark-notify-alacritty.lock ]] && return x-have dark-notify && { # subprocess is used to prevent the command from showing it was backgrounded ( flock /tmp/dark-notify-alacritty.lock dark-notify \ -c "$HOME/.dotfiles/local/bin/x-change-alacritty-theme" & ) &> /dev/null } return 0 } # darknotify_alacritty # Function to list installed Homebrew packages using bkt caching brew_installed() { bkt -- brew list } # Shorthand for checking if a Homebrew package is installed # Usage: have_brew php && php -v have_brew() { ! have brew && return 125 if bkt -- brew list "$1" &> /dev/null; then return 0 else return 1 fi } # Alacritty preexec hook to update dynamic title preexec() { print -n -P "\e]0;$1%~\a" } # Update dotfiles dfu() { ( cd "$DOTFILES" && git rebase --ff --autostash && ./install ) } # Weather in Tampere, or other city weather() { # https://github.com/chubin/wttr.in#usage local city="${1:-Tampere}" curl "http://wttr.in/${city// /+}?2nFQM&lang=fi" } # Docker ssh_docker() { docker exec -it "$@" bash } # Rector project to php version 8.2 by default. rector() { local php="${1:-82}" docker run -v "$(pwd)":/project rector/rector:latest process \ "/project/" \ --set "php${php}" \ --autoload-file /project/vendor/autoload.php } # Commit everything commit() { local commitMessage="$*" if [ -z "$commitMessage" ]; then commitMessage="Automated commit" fi git add . git commit -a -m "$commitMessage" } scheduler() { while :; do php artisan schedule:run echo "Sleeping 60 seconds..." sleep 60 done } # Run command silently # Usage: silent uptime silent() { "$@" >&/dev/null } # Check if a file contains non-ascii characters nonascii() { LC_ALL=C grep -n '[^[:print:][:space:]]' "${@}" } # Remove non-ascii characters from string # Usage: strip_nonascii "string" strip_nonascii() { # shellcheck disable=SC2001 echo "$1" | LC_ALL=C sed 's/[^[:print:][:space:]]//g' } # Slugify a string # Usage: slugify "string" slugify() { echo "$1" | iconv -t ascii//TRANSLIT | sed -r s/[^a-zA-Z0-9]+/-/g | sed -r s/^-+\|-+$//g | tr '[:upper:]' '[:lower:]' } # https://stackoverflow.com/a/85932 fn_exists() { declare -f -F "$1" > /dev/null return $? } # Creates a random string rnd() { echo $RANDOM | md5sum | head -c 20 } # return sha256sum for file # $1 - filename (string) get_sha256sum() { sha256sum "$1" | head -c 64 } # Replaceable file # # $1 - filename (string) # $2 - filename (string) # # Returns 1 when replaceable, 0 when not replaceable. replacable() { FILE1="$1" FILE2="$2" [[ ! -r $FILE1 ]] && { [[ $VERBOSE -eq 1 ]] && msgr err "File 1 ($FILE1) does not exist" return 0 } [[ ! -r $FILE2 ]] && { [[ $VERBOSE -eq 1 ]] && msgr err "File 2 ($FILE2) does not exist, replaceable" return 1 } FILE1_HASH=$(get_sha256sum "$FILE1") FILE2_HASH=$(get_sha256sum "$FILE2") [[ $FILE1_HASH == "" ]] && { [[ $VERBOSE -eq 1 ]] && msgr err "Could not get hash for file 1 ($FILE1)" return 0 } [[ $FILE2_HASH == "" ]] && { [[ $VERBOSE -eq 1 ]] && msgr err "Could not get hash for file 2 ($FILE2), replaceable" return 1 } [[ $FILE1_HASH == "$FILE2_HASH" ]] && { [[ $VERBOSE -eq 1 ]] && msgr ok "Files match, not replaceable: $FILE1" return 0 } [[ $VERBOSE -eq 1 ]] && msgr warn "Files do not match ($FILE1_HASH != $FILE2_HASH), replaceable" return 1 } export COMPLETION_WAITING_DOTS=true # Bash completion file location export BASH_COMPLETION_USER_FILE="${XDG_CONFIG_HOME}/bash-completion/bash_completion" # History env variables export HIST_STAMPS="yyyy-mm-dd" export HISTFILE="${XDG_STATE_HOME}/zsh/history" # Larger bash history (allow 32³ entries; default is 500) export HISTSIZE=32768 export HISTFILESIZE=$HISTSIZE # don't put duplicate lines or lines starting with space in the history. # See bash(1) for more options export HISTCONTROL=ignoreboth # Make some commands not show up in history export HISTIGNORE="ls:cd:cd -:pwd:exit:date:* --help" # And include the parameter for ZSH export HISTORY_IGNORE="(ls|cd|cd -|pwd|exit|date|* --help)" # Less history location export LESSHISTFILE="$XDG_STATE_HOME"/less/history # Highlight section titles in manual pages # export LESS_TERMCAP_md="$ORANGE" # zsh autoloaded terminfo export TERMINFO="${XDG_DATA_HOME}/terminfo" export TERMINFO_DIRS="${XDG_DATA_HOME}/terminfo":/usr/share/terminfo # Don't clear the screen after quitting a manual page export MANPAGER="less -X" # Always enable colored `grep` output export GREP_OPTIONS="--color=auto" # check the window size after each command and, if necessary, # update the values of LINES and COLUMNS. hash shopt 2> /dev/null && shopt -s checkwinsize # shellcheck disable=SC2155 export SHORT_HOST=$(hostname -s) # asdf # https://github.com/asdf-vm/asdf msg "Setting up asdf configuration" export ASDF_DIR="${XDG_BIN_HOME}/asdf" if [[ -d $ASDF_DIR ]]; then [[ -d $ASDF_DIR/completions ]] && FPATH="$ASDF_DIR/completions:$FPATH" [[ -d $ASDF_DIR/plugins ]] && FPATH="$ASDF_DIR/plugins:$FPATH" export ASDF_CONFIG_FILE="${XDG_CONFIG_HOME}/asdf/asdfrc" export ASDF_DATA_DIR="${ASDF_DIR}" export ASDF_PLUGIN_MANAGER_PLUGIN_VERSIONS_FILENAME="${XDG_CONFIG_HOME}/asdf/plugin-versions" export ASDF_LOG_FILE="${XDG_CACHE_HOME}/asdf/asdf.log" export ASDF_FORCE_PREPEND=yes ## Default package files export ASDF_CRATE_DEFAULT_PACKAGES_FILE="${XDG_CONFIG_HOME}/asdf/cargo-packages" export ASDF_GEM_DEFAULT_PACKAGES_FILE="${XDG_CONFIG_HOME}/asdf/gem-packages" export ASDF_GOLANG_DEFAULT_PACKAGES_FILE="${XDG_CONFIG_HOME}/asdf/golang-packages" export ASDF_NPM_DEFAULT_PACKAGES_FILE="${XDG_CONFIG_HOME}/asdf/npm-packages" export ASDF_PYTHON_DEFAULT_PACKAGES_FILE="${XDG_CONFIG_HOME}/asdf/python-packages" ## Plugin configuration export ASDF_DIRENV_IGNORE_MISSING_PLUGINS=1 export ASDF_GOLANG_MOD_VERSION_ENABLED=true export ASDF_NODEJS_LEGACY_FILE_DYNAMIC_STRATEGY="latest_available" ## Add asdf to path export PATH="${ASDF_DIR}/bin:${PATH}" source "$ASDF_DIR/asdf.sh" fi # Antidote configuration # https://getantidote.github.io/ msg "Setting up Antidote configuration" export ANTIDOTE_DIR="$DOTFILES/tools/antidote" export ANTIDOTE_HOME="$XDG_CACHE_HOME/antidote" export ANTIDOTE_PLUGINS="$XDG_CONFIG_HOME/zsh/antidote_plugins" # Antigen configuration # https://github.com/zsh-users/antigen/wiki/Configuration msg "Setting up Antigen configuration" export ADOTDIR="$XDG_DATA_HOME/antigen" export ANTIGEN_CACHE="$XDG_CACHE_HOME/antigen" export ANTIGEN_SYSTEM_RECEIPT_F=".local/share/antigen/antigen_system_lastupdate" export ANTIGEN_PLUGIN_RECEIPT_F=".local/share/antigen/antigen_plugin_lastupdate" # Ansible configuration # https://docs.ansible.com/ansible/latest/reference_appendices/config.html msg "Setting up Ansible configuration" export ANSIBLE_HOME="$XDG_CONFIG_HOME/ansible" export ANSIBLE_CONFIG="$XDG_CONFIG_HOME/ansible.cfg" export ANSIBLE_GALAXY_CACHE_DIR="$XDG_CACHE_HOME/ansible/galaxy_cache" x-dc "$ANSIBLE_HOME" x-dc "$ANSIBLE_GALAXY_CACHE_DIR" # aws # https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-files.html # https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-envvars.html # https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-profiles.html msg "Setting up AWS configuration" export AWS_CONFIG_FILE="${XDG_STATE_HOME}/aws/config" export AWS_SHARED_CREDENTIALS_FILE="${XDG_STATE_HOME}/aws/credentials" export AWS_DATA_PATH="${XDG_DATA_HOME}/aws" export AWS_DEFAULT_REGION="eu-west-1" export AWS_DEFAULT_OUTPUT="table" export AWS_CONFIGURE_KEYS=true export AWS_CONFIGURE_REGION=true export AWS_CONFIGURE_OUTPUT=true export AWS_CONFIGURE_PROFILE=true export AWS_CONFIGURE_PROMPT=true export AWS_CONFIGURE_PROMPT_DEFAULT="default" # bob manages nvim versions msg "Setting up bob configuration" x-path-prepend "$XDG_DATA_HOME/bob/nvim-bin" # bkt (shell command caching tool) configuration msg "Setting up bkt configuration" export BKT_TTL=1m # brew, https://docs.brew.sh/Manpage msg "Setting up Homebrew configuration" export HOMEBREW_NO_ANALYTICS=true export HOMEBREW_NO_ENV_HINTS=true export HOMEBREW_BUNDLE_MAS_SKIP=true export HOMEBREW_BUNDLE_FILE="$XDG_CONFIG_HOME/homebrew/Brewfile" x-have brew && { # Add brew autocompletion to fpath FPATH="$(brew --prefix)/share/zsh/site-functions:${FPATH}" eval "$(brew shellenv)" } # composer, https://getcomposer.org/ msg "Setting up Composer configuration" export COMPOSER_HOME="$XDG_STATE_HOME/composer" export COMPOSER_BIN="$COMPOSER_HOME/vendor/bin" export PATH="$COMPOSER_BIN:$PATH" # direnv, https://direnv.net/ # https://direnv.net/docs/hook.html # Set the hook to show the direnv message in a different color # export DIRENV_LOG_FORMAT=$'\033[2mdirenv: %s\033[0m' export DIRENV_LOG_FORMAT= # docker, https://docs.docker.com/engine/reference/commandline/cli/ msg "Setting up Docker configuration" export DOCKER_CONFIG="${XDG_CONFIG_HOME}/docker" x-dc "$DOCKER_CONFIG" # Docker: Disable snyk ad export DOCKER_SCAN_SUGGEST=false # fzf export FZF_BASE="${XDG_CONFIG_HOME}/fzf" export FZF_DEFAULT_OPTS='--height 40% --tmux bottom,40% --layout reverse --border top' # GnuPG # https://gnupg.org/documentation/manuals/gnupg/Invoking-GPG.html msg "Setting up GnuPG configuration" export GNUPGHOME="${XDG_DATA_HOME}/gnupg" # Go # https://golang.org/doc/code.html msg "Setting up Go configuration" export GOPATH="$XDG_DATA_HOME/go" export GOBIN="$XDG_BIN_HOME" # Lando export PATH="$HOME/.lando/bin${PATH+:$PATH}" #landopath # NPM: Add npm packages to path msg "Setting up NPM configuration" x-have node && { NVM_NODE_BIN_DIR="$(dirname "$(which node)")" export PATH="$NVM_NODE_BIN_DIR:$PATH" } # oh-my-posh (omp) configuration msg "Setting up oh-my-posh configuration" export OHMYPOSH_CFG="$DOTFILES/config/omp/own.toml" # op (1Password cli) is present msg "Setting up 1Password CLI configuration" export OP_CACHE="$XDG_STATE_HOME/1password" # Python # # pyenv, python environments msg "Setting up Python configuration" export WORKON_HOME="$XDG_DATA_HOME/virtualenvs" export PYENV_ROOT="$XDG_STATE_HOME/pyenv" ## for MichaelAquilina/zsh-autoswitch-virtualenv export AUTOSWITCH_VIRTUAL_ENV_DIR="$WORKON_HOME" export PATH="$PYENV_ROOT/bin:$PYENV_ROOT/shims:$PATH" [[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH" x-have pyenv && eval "$(pyenv init -)" # Rust / cargo msg "Setting up Rust/Cargo configuration" export RUST_WITHOUT=rust-docs # screen # https://www.gnu.org/software/screen/manual/screen.html msg "Setting up screen configuration" export SCREENRC="$XDG_CONFIG_HOME/misc/screenrc" # sonarlint # https://www.sonarlint.org/ msg "Setting up Sonarlint configuration" export SONARLINT_USER_HOME="$XDG_DATA_HOME/sonarlint" # terraform # https://www.terraform.io/docs/cli/config/config-file.html # https://www.terraform.io/docs/cli/config/environment-variables.html msg "Setting up Terraform configuration" export TF_DATA_DIR="$XDG_STATE_HOME/terraform" export TF_CLI_CONFIG_FILE="$XDG_CONFIG_HOME/terraform/terraformrc" export TF_PLUGIN_CACHE_DIR="$XDG_CACHE_HOME/terraform/plugin-cache" # tmux # https://tmux.github.io/ msg "Setting up tmux configuration" export TMUX_PLUGINS="$XDG_CONFIG_HOME/tmux/plugins" export TMUX_CONF="$XDG_CONFIG_HOME/tmux/tmux.conf" ## These settings are for zsh-tmux export ZSH_TMUX_AUTOSTART=false export ZSH_TMUX_CONFIG="$DOTFILES/config/tmux/tmux.conf" export ZSH_TMUX_UNICODE=true export ZSH_TMUX_AUTOQUIT=false export ZSH_TMUX_DEFAULT_SESSION_NAME=main # tms, https://github.com/jrmoulton/tmux-sessionizer export TMS_CONFIG_FILE="${XDG_CONFIG_HOME}/tms/config.toml" # wakatime, https://github.com/wakatime/wakatime-cli msg "Setting up Wakatime configuration" export WAKATIME_HOME="$XDG_STATE_HOME/wakatime" x-dc "$WAKATIME_HOME" # Misc msg "Setting up miscellaneous configuration" export ZSHZ_DATA="$XDG_STATE_HOME/z" export CHEAT_USE_FZF=true export SQLITE_HISTORY="${XDG_CACHE_HOME}/sqlite_history" X_EXPORTS_FILES=( "$HOME/.config/exports-secret" "$HOME/.config/exports-$(hostname)" "$HOME/.config/exports-$(hostname)-secret" ) for exportFile in "${X_EXPORTS_FILES[@]}"; do # shellcheck source=$HOME/.config/exports-secret [ -f "$exportFile" ] && source "$exportFile" && msg "Sourced $exportFile" done unset X_EXPORTS_FILES