mirror of
https://github.com/jimeh/dotfiles.git
synced 2026-02-19 13:26:40 +00:00
329 lines
10 KiB
Bash
329 lines
10 KiB
Bash
#
|
|
# Z-Shell Init
|
|
#
|
|
|
|
# In our zshenv file we have on macOS disabled loading ZSH startup files from
|
|
# /etc to avoid /etc/zprofile messing up our carefully constructed PATH. So we
|
|
# need to manually load the other files we care about.
|
|
if [[ "$OSTYPE" == "darwin"* ]] && [ -f "/etc/zshrc" ]; then
|
|
source "/etc/zshrc"
|
|
fi
|
|
|
|
# ==============================================================================
|
|
# Zinit
|
|
# ==============================================================================
|
|
|
|
declare -A ZINIT
|
|
ZINIT[HOME_DIR]="$HOME/.local/zsh/zinit"
|
|
ZINIT[BIN_DIR]="${ZINIT[HOME_DIR]}/bin"
|
|
|
|
# Load zinit module if it exists. For more info, run: zinit module help
|
|
if [ -d "${ZINIT[HOME_DIR]}/module/Src/zdharma_continuum" ]; then
|
|
module_path+=("${ZINIT[HOME_DIR]}/module/Src")
|
|
zmodload zdharma_continuum/zinit
|
|
fi
|
|
|
|
# Ask to clone Zinit if it's not already available on disk.
|
|
[ ! -d "${ZINIT[BIN_DIR]}" ] &&
|
|
read -q "REPLY?Zinit not installed, clone to ${ZINIT[BIN_DIR]}? [y/N]:" &&
|
|
echo &&
|
|
git clone --depth=1 "https://github.com/zdharma-continuum/zinit.git" "${ZINIT[BIN_DIR]}"
|
|
|
|
# Load Zinit
|
|
source "${ZINIT[BIN_DIR]}/zinit.zsh"
|
|
|
|
# Enable interactive selection of completions.
|
|
zinit for @OMZ::lib/completion.zsh
|
|
|
|
# Set various sane defaults for ZSH history management.
|
|
zinit for @OMZ::lib/history.zsh
|
|
|
|
# Enable Ruby Bundler plugin from oh-my-zsh.
|
|
zinit for @OMZ::plugins/bundler
|
|
|
|
zinit light-mode wait lucid \
|
|
atinit"ZINIT[COMPINIT_OPTS]=-C; zicompinit; zicdreplay" \
|
|
for @zdharma-continuum/fast-syntax-highlighting
|
|
|
|
zinit light-mode wait lucid blockf \
|
|
for @zsh-users/zsh-completions
|
|
|
|
zinit light-mode wait lucid atload"!_zsh_autosuggest_start" \
|
|
for @zsh-users/zsh-autosuggestions
|
|
|
|
# ==============================================================================
|
|
# Helpers
|
|
# ==============================================================================
|
|
|
|
# setup-completions is a helper function to set up shell completions for a given
|
|
# command. It generates Zsh completion scripts and places them in the specified
|
|
# completions directory. If the completion file already exists, it checks if the
|
|
# source file has been updated and regenerates the completions if necessary.
|
|
#
|
|
# Arguments:
|
|
#
|
|
# $1 - cmd: The name of the command for which completions are being
|
|
# set up.
|
|
# $2 - source: The source file used to determine if completions need to
|
|
# be re-generated. For example, the binary file of the
|
|
# command (e.g., rustup).
|
|
# $@ - args: The command to run to generate the completions. This
|
|
# should produce Zsh completion scripts.
|
|
#
|
|
# Example usage:
|
|
#
|
|
# setup-completions rustup "$(command -v rustup)" rustup completions zsh
|
|
#
|
|
# This example sets up completions for the 'rustup' command by running
|
|
# 'rustup completions zsh', and places the generated completion script in the
|
|
# appropriate completions directory. If the source file is newer than the target
|
|
# completion file, the command is re-executed and the completion script is
|
|
# updated.
|
|
#
|
|
# The completions are placed in the directory specified by the ZSH_COMPLETIONS
|
|
# environment variable. If ZSH_COMPLETIONS is not set, the completions are
|
|
# placed in $HOME/.zsh/completions by default.
|
|
setup-completions() {
|
|
local cmd="$1"
|
|
local source="$2"
|
|
local setup_cmd="$3"
|
|
shift 3
|
|
|
|
local target_dir="${ZSH_COMPLETIONS:-$HOME/.zsh/completions}"
|
|
local target_file="${target_dir}/_${cmd}"
|
|
|
|
if [[ -z "$(command -v "$cmd")" ]]; then
|
|
echo "setup-completions: Command not found: $cmd" >&2
|
|
return 1
|
|
fi
|
|
|
|
if [[ -z "$(command -v "$setup_cmd")" ]]; then
|
|
echo "setup-completions: Command not found: $setup_cmd" >&2
|
|
return 1
|
|
fi
|
|
|
|
if [[ -z "$cmd" || -z "$source" || -z "$setup_cmd" ]]; then
|
|
echo "setup-completions: Missing required arguments." >&2
|
|
return 1
|
|
fi
|
|
|
|
# Check if the target completion file needs to be updated
|
|
if [[ ! -f "$target_file" || "$source" -nt "$target_file" ]]; then
|
|
echo "setup-completions: Setting up completion for $cmd --> $target_file" >&2
|
|
mkdir -p "$target_dir"
|
|
"$setup_cmd" "$@" >| "$target_file"
|
|
chmod +x "$target_file"
|
|
|
|
# Only run compinit if not already loaded
|
|
if ! (whence -w compinit &> /dev/null); then
|
|
autoload -U compinit && compinit
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# Convert a bash/zsh alias to a function. It prints the unalias command and the
|
|
# function definition, meaning the output needs to be evaluated to take effect.
|
|
#
|
|
# Arguments:
|
|
# $1: The alias to convert. Should be a single line like "alias ll='ls -alF'"
|
|
# or "ll='ls -alF'".
|
|
#
|
|
# Example:
|
|
# alias brew="op plugin run -- brew"
|
|
# convert_alias_to_function "$(alias brew)"
|
|
#
|
|
# This will print:
|
|
# unalias brew
|
|
# brew() {
|
|
# op plugin run -- brew "$@"
|
|
# }
|
|
convert-alias-source-to-function-source() {
|
|
local line="$1"
|
|
|
|
# Remove Bash's "alias " prefix if present.
|
|
line=${line#alias }
|
|
|
|
# Extract the alias name and the raw command.
|
|
local alias_name="$(echo "$line" | cut -d'=' -f1)"
|
|
local raw_command="$(echo "$line" | cut -d'=' -f2)"
|
|
|
|
# Evaluate the raw command to ensure we get the correct command, with any
|
|
# quotes or shell escape characters handled correctly.
|
|
local command
|
|
eval "command=$raw_command"
|
|
|
|
# Abort if the command is empty.
|
|
if [ -z "$command" ]; then
|
|
echo "Error: Empty command for alias $alias_name" >&2
|
|
return 1
|
|
fi
|
|
|
|
# Print the unalias command and the function definition.
|
|
echo -e "unalias ${alias_name}"
|
|
echo -e "${alias_name}() {\n ${command} \"\$@\"\n}"
|
|
}
|
|
|
|
# Convert a bash/zsh alias to a function. It replaces the alias with a function
|
|
# definition in the current shell that has the same behavior as the alias.
|
|
#
|
|
# Arguments:
|
|
# $1: The alias to convert. Should be the name of the alias.
|
|
#
|
|
# Example:
|
|
# alias brew="op plugin run -- brew"
|
|
# convert-alias-to-function brew
|
|
#
|
|
# This will replace the alias "brew" with a function that has the same behavior.
|
|
convert-alias-to-function() {
|
|
local alias_name="$1"
|
|
|
|
# Get the alias source.
|
|
local alias_source="$(alias "$alias_name")"
|
|
|
|
# Abort if the alias does not exist.
|
|
if [ -z "$alias_source" ]; then
|
|
echo "Error: Alias $alias_name does not exist" >&2
|
|
return 1
|
|
fi
|
|
|
|
eval "$(convert-alias-source-to-function-source "$alias_source")"
|
|
}
|
|
|
|
# ==============================================================================
|
|
# Completion
|
|
# ==============================================================================
|
|
|
|
# Group completions by type under group headings
|
|
zstyle ':completion:*' group-name ''
|
|
zstyle ':completion:*:descriptions' format '%B%d%b'
|
|
|
|
# Improve selection of Makefile completions - from:
|
|
# https://github.com/zsh-users/zsh-completions/issues/541#issuecomment-384223016
|
|
zstyle ':completion:*:make:*:targets' call-command true
|
|
zstyle ':completion:*:make:*' tag-order targets
|
|
|
|
if [ -d "$ZSH_COMPLETIONS" ]; then fpath=("$ZSH_COMPLETIONS" $fpath); fi
|
|
if [ -d "$DOTZSH_SITEFUNS" ]; then fpath=("$DOTZSH_SITEFUNS" $fpath); fi
|
|
if [ -d "$BREW_SITEFUNS" ]; then fpath=("$BREW_SITEFUNS" $fpath); fi
|
|
|
|
autoload -Uz compinit
|
|
compinit
|
|
|
|
# ==============================================================================
|
|
# Edit command line
|
|
# ==============================================================================
|
|
|
|
autoload -z edit-command-line
|
|
zle -N edit-command-line
|
|
bindkey "^X^E" edit-command-line
|
|
|
|
# ==============================================================================
|
|
# Private Dotfiles
|
|
# ==============================================================================
|
|
|
|
if [ -f "$DOTPFILES/zshrc" ]; then
|
|
source "$DOTPFILES/zshrc"
|
|
fi
|
|
|
|
# ==============================================================================
|
|
# Environment and Tool Managers
|
|
# ==============================================================================
|
|
|
|
# If available, make sure to load direnv shell hook before mise.
|
|
if command-exists direnv; then
|
|
cached-eval "$(command -v direnv)" direnv hook zsh
|
|
fi
|
|
|
|
MISE_HOME="$HOME/.local/share/mise"
|
|
MISE_ZSH_INIT="$MISE_HOME/shell/init.zsh"
|
|
export MISE_INSTALL_PATH="$MISE_HOME/bin/mise"
|
|
|
|
if ! command-exists mise; then
|
|
read -q 'REPLY?mise is not installed, install with `curl https://mise.run | sh`? [y/N]:' &&
|
|
echo && curl https://mise.run | sh
|
|
fi
|
|
|
|
if command-exists mise; then
|
|
alias mi="mise"
|
|
|
|
cached-eval "$MISE_INSTALL_PATH" mise activate zsh
|
|
setup-completions mise "$MISE_INSTALL_PATH" mise completions zsh
|
|
fi
|
|
|
|
# ==============================================================================
|
|
# Prompt
|
|
# ==============================================================================
|
|
|
|
if ! command-exists starship && [ -f "$MISE_INSTALL_PATH" ]; then
|
|
read -q 'REPLY?starship is not installed, install with `mise install starship`? [y/N]:' &&
|
|
echo && "$MISE_INSTALL_PATH" install starship
|
|
fi
|
|
|
|
if command-exists starship; then
|
|
cached-eval "$(command -v starship)" starship init zsh --print-full-init
|
|
setup-completions starship "$(command -v starship)" starship completions zsh
|
|
else
|
|
echo "WARN: starship not found, skipping prompt setup" >&2
|
|
echo " install with: mise install starship" >&2
|
|
|
|
fi
|
|
|
|
# ==============================================================================
|
|
# Tool specific setup
|
|
# ==============================================================================
|
|
|
|
# Aliases
|
|
source "$DOTZSH/aliases.zsh"
|
|
|
|
# OS specific
|
|
if [[ "$OSTYPE" == "darwin"* ]]; then source "$DOTZSH/macos.zsh"; fi
|
|
if [[ "$OSTYPE" == "linux"* ]]; then source "$DOTZSH/linux.zsh"; fi
|
|
|
|
# Utils
|
|
source "$DOTZSH/1password.zsh"
|
|
source "$DOTZSH/copilot.zsh"
|
|
source "$DOTZSH/emacs.zsh"
|
|
source "$DOTZSH/fzf.zsh"
|
|
source "$DOTZSH/less.zsh"
|
|
source "$DOTZSH/mise.zsh"
|
|
source "$DOTZSH/neovim.zsh"
|
|
source "$DOTZSH/nix.zsh"
|
|
source "$DOTZSH/tldr.zsh"
|
|
source "$DOTZSH/tmux.zsh"
|
|
source "$DOTZSH/zoxide.zsh"
|
|
|
|
# Development
|
|
source "$DOTZSH/containers.zsh"
|
|
source "$DOTZSH/git.zsh"
|
|
source "$DOTZSH/golang.zsh"
|
|
source "$DOTZSH/google-cloud.zsh"
|
|
source "$DOTZSH/kubernetes.zsh"
|
|
source "$DOTZSH/nodejs.zsh"
|
|
source "$DOTZSH/python.zsh"
|
|
source "$DOTZSH/ruby.zsh"
|
|
source "$DOTZSH/rust.zsh"
|
|
source "$DOTZSH/scaleway.zsh"
|
|
|
|
# ==============================================================================
|
|
# Basic Z-Shell settings
|
|
# ==============================================================================
|
|
|
|
# Disable auto-title.
|
|
DISABLE_AUTO_TITLE="true"
|
|
|
|
# Disable shared history.
|
|
unsetopt share_history
|
|
|
|
# Disable attempted correction of commands (is wrong 98% of the time).
|
|
unsetopt correctall
|
|
|
|
# ==============================================================================
|
|
# Local Overrides
|
|
# ==============================================================================
|
|
|
|
if [ -f "$HOME/.zshrc.local" ]; then
|
|
source "$HOME/.zshrc.local"
|
|
fi
|
|
|
|
autoload -U +X bashcompinit && bashcompinit
|