diff --git a/bash/aliases/common_alias.sh b/bash/aliases/common_alias.sh new file mode 100644 index 0000000..9b940f3 --- /dev/null +++ b/bash/aliases/common_alias.sh @@ -0,0 +1,58 @@ +#!/usr/bin/env bash + +alias ..='cd ..' +alias ...='cd ../..' +alias ....='cd ../../..' +alias .....='cd ../../../..' +alias ......='cd ../../../../..' +alias -- -='cd -' + +alias ls='ls --color=auto' +alias l='ls -lFh' +alias la='ls -lAFh' +alias lr='ls -tRFh' +alias lt='ls -ltFh' +alias ll='ls -l' +alias ldot='ls -ld .*' +alias lss='ls -1FSsh' +alias lS='lss' +alias lart='ls -1Fcart' +alias lrt='ls -1Fcrt' +alias lsr='ls -lARFh' +alias lsn='ls -1' + +alias grep='grep --color' +alias sgrep='grep -R -n -H -C 5 --exclude-dir={.git,.svn,CVS}' +alias t='tail -f' + +alias weather='curl wttr.in' +alias moon='curl wttr.in/Moon' +alias quote='curl -s https://api.quotable.io/random | jq -r .content' +alias joke='curl -s -H "Accept: application/json" https://icanhazdadjoke.com/ | jq -r .joke' +alias dadjoke='curl -s -H "Accept: application/json" https://icanhazdadjoke.com/ | jq -r .joke' + +alias dud='du -d 1 -h' +alias ff='find . -type f -name' + +alias h='history' +alias hgrep='history | grep' +alias help='man' +alias p='ps -f' +alias sortnr='sort -n -r' +alias unexport='unset' + +alias rm='rm -i' +alias cp='cp -i' +alias mv='mv -i' + +# Interactive directory picker from nushell cdi behavior. +cdi() { + if ! command -v fzf >/dev/null 2>&1; then + echo "fzf is not installed." + return 1 + fi + + local selected_dir + selected_dir="$(find . -type d 2>/dev/null | sed 's#^\./##' | fzf)" + [[ -n "$selected_dir" ]] && cd "$selected_dir" +} diff --git a/bash/aliases/helix_alias.sh b/bash/aliases/helix_alias.sh new file mode 100644 index 0000000..ae50c30 --- /dev/null +++ b/bash/aliases/helix_alias.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +pj_helix() { + if command -v helix >/dev/null 2>&1; then + command helix -c "$BASH_POLYJUICE_HELIX_CONFIG_FILE" "$@" + elif command -v hx >/dev/null 2>&1; then + command hx -c "$BASH_POLYJUICE_HELIX_CONFIG_FILE" "$@" + else + echo "HELIX/HX is not installed" + return 1 + fi +} + +helix() { + pj_helix "$@" +} + +hx() { + pj_helix "$@" +} diff --git a/bash/aliases/python_alias.sh b/bash/aliases/python_alias.sh new file mode 100644 index 0000000..b748bf1 --- /dev/null +++ b/bash/aliases/python_alias.sh @@ -0,0 +1,101 @@ +#!/usr/bin/env bash + +py() { + if command -v py >/dev/null 2>&1; then + command py "$@" + elif command -v python3 >/dev/null 2>&1; then + command python3 "$@" + else + echo "Error: Python is not installed or could not be found." + return 1 + fi +} + +pyclean() { + find "${@:-.}" -type f -name "*.py[co]" -delete + find "${@:-.}" -type d -name "__pycache__" -delete + find "${@:-.}" -depth -type d -name ".mypy_cache" -exec rm -r "{}" + + find "${@:-.}" -depth -type d -name ".pytest_cache" -exec rm -r "{}" + +} + +alias pygrep='grep -nr --include="*.py"' +alias pyserver='python3 -m http.server' + +py_create_default_venv() { + local venv_parent + venv_parent="$(dirname "$BASH_POLYJUICE_DEFAULT_PYTHON_VENV")" + + if ! command -v uv >/dev/null 2>&1; then + echo "uv command not found. Please install uv first." + return 1 + fi + + mkdir -p "$venv_parent" + + if [[ -d "$BASH_POLYJUICE_DEFAULT_PYTHON_VENV" && -f "$BASH_POLYJUICE_DEFAULT_PYTHON_VENV/bin/activate" ]]; then + ( + cd "$venv_parent" || exit 1 + uv sync + ) + else + ( + cd "$venv_parent" || exit 1 + uv init --name gvenv + uv sync + ) + fi +} + +py_vrun() { + local current_dir="$PWD" + local venv_names=(".venv" "venv" ".virtualenv" "env") + local venv_path="" + local found_name="" + local max_depth=20 + local depth=0 + local venv_name + + echo "searching nearest python virtual environment..." + + while [[ "$current_dir" != "/" && "$current_dir" != "$HOME" && "$depth" -lt "$max_depth" ]]; do + for venv_name in "${venv_names[@]}"; do + if [[ -d "$current_dir/$venv_name" && -f "$current_dir/$venv_name/bin/activate" ]]; then + venv_path="$current_dir/$venv_name" + found_name="$venv_name" + break 2 + fi + done + current_dir="$(dirname "$current_dir")" + ((depth++)) + done + + if [[ -z "$venv_path" && -d "$BASH_POLYJUICE_DEFAULT_PYTHON_VENV" && -f "$BASH_POLYJUICE_DEFAULT_PYTHON_VENV/bin/activate" ]]; then + venv_path="$BASH_POLYJUICE_DEFAULT_PYTHON_VENV" + found_name="$(basename "$BASH_POLYJUICE_DEFAULT_PYTHON_VENV")" + fi + + if [[ -n "$venv_path" ]]; then + if [[ -n "${VIRTUAL_ENV:-}" ]]; then + if [[ "$VIRTUAL_ENV" == "$venv_path" ]]; then + echo "already activated: $venv_path" + return 0 + fi + + echo "another virtual environment is already activated: $(basename "$VIRTUAL_ENV")" + read -r -p "Switch to $(basename "$(dirname "$venv_path")")/$found_name? (y/N): " -n 1 reply + echo + if [[ ! "$reply" =~ ^[Yy]$ ]]; then + return 0 + fi + deactivate >/dev/null 2>&1 || true + fi + + echo "activating virtual environment: $venv_path/bin/activate" + # shellcheck disable=SC1090 + source "$venv_path/bin/activate" + return 0 + fi + + echo "no python virtual environment found." + return 1 +} diff --git a/bash/bash_profile b/bash/bash_profile new file mode 100644 index 0000000..a4728d3 --- /dev/null +++ b/bash/bash_profile @@ -0,0 +1,7 @@ +#!/usr/bin/env bash + +if [[ -n "${BASH_VERSION:-}" ]]; then + _profile_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + [[ -f "$_profile_dir/bashrc" ]] && source "$_profile_dir/bashrc" + unset _profile_dir +fi diff --git a/bash/bashrc b/bash/bashrc new file mode 100644 index 0000000..64d0bcd --- /dev/null +++ b/bash/bashrc @@ -0,0 +1,39 @@ +#!/usr/bin/env bash + +if [[ -z "${BASH_VERSION:-}" ]]; then + echo "Unsupported shell" + return 1 2>/dev/null || exit 1 +fi + +_bash_polyjuice_source="${BASH_SOURCE[0]}" +export BASH_POLYJUICE_PATH="$(cd "$(dirname "$_bash_polyjuice_source")" && pwd)" +export BASH_POLYJUICE_SETTINGS_PATH="$BASH_POLYJUICE_PATH/settings" +export BASH_POLYJUICE_ALIASES_PATH="$BASH_POLYJUICE_PATH/aliases" +export BASH_POLYJUICE_FUNCTIONS_PATH="$BASH_POLYJUICE_PATH/functions" +export BASH_POLYJUICE_INTEGRATIONS_PATH="$BASH_POLYJUICE_PATH/integrations" +export BASH_POLYJUICE_KEYBINDINGS_PATH="$BASH_POLYJUICE_PATH/keybindings" +export BASH_POLYJUICE_STARSHIP_CONFIG_FILE="$BASH_POLYJUICE_PATH/../starship/starship_default.toml" +export BASH_POLYJUICE_HELIX_CONFIG_FILE="$BASH_POLYJUICE_PATH/../helix/config.toml" + +for _file in "$BASH_POLYJUICE_SETTINGS_PATH"/*.sh; do + [[ -f "$_file" ]] && source "$_file" +done + +for _file in "$BASH_POLYJUICE_ALIASES_PATH"/*.sh; do + [[ -f "$_file" ]] && source "$_file" +done + +for _file in "$BASH_POLYJUICE_FUNCTIONS_PATH"/*.sh; do + [[ -f "$_file" ]] && source "$_file" +done + +for _file in "$BASH_POLYJUICE_INTEGRATIONS_PATH"/*.sh; do + [[ -f "$_file" ]] && source "$_file" +done + +for _file in "$BASH_POLYJUICE_KEYBINDINGS_PATH"/*.sh; do + [[ -f "$_file" ]] && source "$_file" +done + +unset _file +unset _bash_polyjuice_source diff --git a/bash/functions/check.sh b/bash/functions/check.sh new file mode 100644 index 0000000..0b83489 --- /dev/null +++ b/bash/functions/check.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash + +pj_check() { + local missing=0 + local cmd + + for cmd in zoxide fzf starship python3 jq; do + if ! command -v "$cmd" >/dev/null 2>&1; then + echo "$cmd is not installed." + missing=1 + fi + done + + if [[ "$missing" -eq 0 ]]; then + echo "All core tools are available." + fi +} + +pj_check_tools() { + local cmd + for cmd in git python cargo verilator iverilog javac sbt; do + if ! command -v "$cmd" >/dev/null 2>&1; then + echo "$cmd is not installed." + fi + done +} diff --git a/bash/functions/starship.sh b/bash/functions/starship.sh new file mode 100644 index 0000000..d22a8aa --- /dev/null +++ b/bash/functions/starship.sh @@ -0,0 +1,34 @@ +#!/usr/bin/env bash + +pj_starship() { + local config_file_dir + config_file_dir="$(dirname "$BASH_POLYJUICE_STARSHIP_CONFIG_FILE")" + + case "$1" in + list) + ls "$config_file_dir" + ;; + set) + local target + target="$config_file_dir/starship_$2.toml" + if [[ -f "$target" ]]; then + export STARSHIP_CONFIG="$target" + echo "Starship config set to '$target'" + else + echo "Config '$target' does not exist." + return 1 + fi + ;; + reset) + export STARSHIP_CONFIG="$BASH_POLYJUICE_STARSHIP_CONFIG_FILE" + ;; + *) + echo "Usage: pj_starship [args]" + echo "Commands:" + echo " list List available Starship configs in the polyjuice directory." + echo " set Select a config by base name (omit the .toml extension)." + echo " reset Reset Starship to the default polyjuice configuration." + return 1 + ;; + esac +} diff --git a/bash/integrations/fzf.sh b/bash/integrations/fzf.sh new file mode 100644 index 0000000..2e107a8 --- /dev/null +++ b/bash/integrations/fzf.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash + +if [[ -z "${FZF_DEFAULT_COMMAND:-}" ]]; then + if command -v fd >/dev/null 2>&1; then + export FZF_DEFAULT_COMMAND='fd --type f --hidden --exclude .git' + elif command -v rg >/dev/null 2>&1; then + export FZF_DEFAULT_COMMAND='rg --files --hidden --glob "!.git/*"' + elif command -v ag >/dev/null 2>&1; then + export FZF_DEFAULT_COMMAND='ag -l --hidden -g "" --ignore .git' + fi +fi + +if command -v fzf >/dev/null 2>&1; then + if [[ -f "$HOME/.fzf.bash" ]]; then + source "$HOME/.fzf.bash" + elif [[ -f "/usr/share/fzf/key-bindings.bash" ]]; then + source "/usr/share/fzf/key-bindings.bash" + [[ -f "/usr/share/fzf/completion.bash" ]] && source "/usr/share/fzf/completion.bash" + elif [[ -f "/usr/share/doc/fzf/examples/key-bindings.bash" ]]; then + source "/usr/share/doc/fzf/examples/key-bindings.bash" + [[ -f "/usr/share/doc/fzf/examples/completion.bash" ]] && source "/usr/share/doc/fzf/examples/completion.bash" + fi +fi diff --git a/bash/integrations/starship.sh b/bash/integrations/starship.sh new file mode 100644 index 0000000..7f2c517 --- /dev/null +++ b/bash/integrations/starship.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +if command -v starship >/dev/null 2>&1; then + export STARSHIP_CONFIG="${STARSHIP_CONFIG:-$BASH_POLYJUICE_STARSHIP_CONFIG_FILE}" + eval "$(starship init bash)" +fi diff --git a/bash/integrations/zoxide.sh b/bash/integrations/zoxide.sh new file mode 100644 index 0000000..2b0e80e --- /dev/null +++ b/bash/integrations/zoxide.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +if command -v zoxide >/dev/null 2>&1; then + eval "$(zoxide init --cmd z bash)" +fi diff --git a/bash/keybindings/fzf_keybindings.sh b/bash/keybindings/fzf_keybindings.sh new file mode 100644 index 0000000..df80e19 --- /dev/null +++ b/bash/keybindings/fzf_keybindings.sh @@ -0,0 +1,56 @@ +#!/usr/bin/env bash + +if ! command -v fzf >/dev/null 2>&1; then + return +fi + +_pj_readline_append() { + local text="$1" + [[ -z "$text" ]] && return 0 + READLINE_LINE="${READLINE_LINE:0:READLINE_POINT}${text}${READLINE_LINE:READLINE_POINT}" + READLINE_POINT=$((READLINE_POINT + ${#text})) +} + +__pj_fzf_file_widget() { + local selected_file + local command_to_run + + if command -v fd >/dev/null 2>&1; then + command_to_run='fd --type f --hidden --exclude .git | fzf' + elif command -v rg >/dev/null 2>&1; then + command_to_run='rg --files --hidden --glob "!.git/*" | fzf' + elif command -v ag >/dev/null 2>&1; then + command_to_run='ag -l --hidden -g "" --ignore .git | fzf' + else + command_to_run='find . -type f 2>/dev/null | fzf' + fi + + selected_file="$(eval "$command_to_run")" + _pj_readline_append "$selected_file" +} + +__pj_fzf_dir_widget() { + local selected_dir + local command_to_run + + if command -v fd >/dev/null 2>&1; then + command_to_run='fd --type d --hidden --no-ignore --exclude .git | fzf' + else + command_to_run='find . -type d 2>/dev/null | fzf' + fi + + selected_dir="$(eval "$command_to_run")" + _pj_readline_append "$selected_dir" +} + +__pj_fzf_history_widget() { + local selected_command + + selected_command="$({ HISTTIMEFORMAT= history; } | sed 's/^[[:space:]]*[0-9]\+[[:space:]]*//' | fzf --height 40% --reverse --border)" + _pj_readline_append "$selected_command" +} + +# Alt-f: file selector, Alt-d: directory selector, Alt-h: history selector +bind -x '"\ef":__pj_fzf_file_widget' +bind -x '"\ed":__pj_fzf_dir_widget' +bind -x '"\eh":__pj_fzf_history_widget' diff --git a/bash/settings/exports.sh b/bash/settings/exports.sh new file mode 100644 index 0000000..60d4251 --- /dev/null +++ b/bash/settings/exports.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash + +# Preferred editor for local and remote sessions. +if command -v helix >/dev/null 2>&1; then + export EDITOR="helix" +elif command -v nvim >/dev/null 2>&1; then + export EDITOR="nvim" +else + export EDITOR="vim" +fi + +export OS="$(uname -s)" +export BASH_POLYJUICE_DEFAULT_PYTHON_VENV="$HOME/.default_pyvenv/.venv" diff --git a/bash/settings/history.sh b/bash/settings/history.sh new file mode 100644 index 0000000..3ac12a6 --- /dev/null +++ b/bash/settings/history.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash + +export HISTFILE="${HISTFILE:-$HOME/.bash_history}" +export HISTSIZE=50000 +export HISTFILESIZE=10000 +export HISTCONTROL="ignoreboth:erasedups" +export HISTTIMEFORMAT="%F %T " + +shopt -s histappend +shopt -s cmdhist +shopt -s lithist + +# Keep history synchronized across interactive shells. +if [[ -z "${BASH_POLYJUICE_HISTORY_INITIALIZED:-}" ]]; then + export BASH_POLYJUICE_HISTORY_INITIALIZED=1 + if [[ -n "${PROMPT_COMMAND:-}" ]]; then + PROMPT_COMMAND="history -a; history -n; ${PROMPT_COMMAND}" + else + PROMPT_COMMAND="history -a; history -n" + fi +fi