From d2643508d83e47bdbfe2336b01f6cb942001f843 Mon Sep 17 00:00:00 2001 From: Alexander Hess Date: Sun, 10 Jul 2022 18:51:26 +0200 Subject: [PATCH 01/27] Initialize the repo with a short README --- README.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..7c57cc5 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# Dotfiles + +This repository contains useful (config) files that I use on my machines. From f27b84fecdd40f6a6f9ad5a46018c18a99be62e4 Mon Sep 17 00:00:00 2001 From: Alexander Hess Date: Sun, 10 Jul 2022 20:54:42 +0200 Subject: [PATCH 02/27] Open-source the project --- LICENSE.txt | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 LICENSE.txt diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..75bb60c --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,19 @@ +Copyright (c) 2022 Alexander Hess [alexander@webartifex.biz] + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. From c90d4825a73a060a2c2a356d0f4fd36f79e900d7 Mon Sep 17 00:00:00 2001 From: Alexander Hess Date: Sun, 10 Jul 2022 20:57:19 +0200 Subject: [PATCH 03/27] Hide LICENSE.txt and README.md in Ubuntu's Nautilus --- .hidden | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .hidden diff --git a/.hidden b/.hidden new file mode 100644 index 0000000..d99978a --- /dev/null +++ b/.hidden @@ -0,0 +1,2 @@ +LICENSE.txt +README.md From 9c4ea2ecfe706e4ea90ec3b345bfbabf5d4c8409 Mon Sep 17 00:00:00 2001 From: Alexander Hess Date: Mon, 11 Jul 2022 04:05:56 +0200 Subject: [PATCH 04/27] Initial version of the shells' dotfiles - add config files for both bash and zsh - as some utilities regard git to be present, git's config files are included as well --- .bash_login | 4 + .bash_logout | 4 + .bash_profile | 8 + .bashrc | 238 ++++ .config/git/commit_msg_template.txt | 39 + .config/git/ignore | 4 + .config/shell/README.md | 3 + .config/shell/aliases.sh | 135 +++ .config/shell/logout.sh | 7 + .config/shell/utils.sh | 335 ++++++ .gitconfig | 205 ++++ .p10k.zsh | 1622 +++++++++++++++++++++++++++ .profile | 46 + .zlogout | 3 + .zprofile | 5 + .zshenv | 20 + .zshrc | 177 +++ 17 files changed, 2855 insertions(+) create mode 100644 .bash_login create mode 100644 .bash_logout create mode 100644 .bash_profile create mode 100644 .bashrc create mode 100644 .config/git/commit_msg_template.txt create mode 100644 .config/git/ignore create mode 100644 .config/shell/README.md create mode 100644 .config/shell/aliases.sh create mode 100644 .config/shell/logout.sh create mode 100644 .config/shell/utils.sh create mode 100644 .gitconfig create mode 100644 .p10k.zsh create mode 100644 .profile create mode 100644 .zlogout create mode 100644 .zprofile create mode 100644 .zshenv create mode 100644 .zshrc diff --git a/.bash_login b/.bash_login new file mode 100644 index 0000000..ac43f9a --- /dev/null +++ b/.bash_login @@ -0,0 +1,4 @@ +# Executed by bash when a login shell starts + +# Mimic bash's default behavior and source `~/.profile` +source "$HOME/.profile" diff --git a/.bash_logout b/.bash_logout new file mode 100644 index 0000000..c38a2a8 --- /dev/null +++ b/.bash_logout @@ -0,0 +1,4 @@ +# Executed by bash when a login shell exits + + +source "$HOME/.config/shell/logout.sh" diff --git a/.bash_profile b/.bash_profile new file mode 100644 index 0000000..1d22c11 --- /dev/null +++ b/.bash_profile @@ -0,0 +1,8 @@ +# Executed by bash when a login shell starts + +# Mimic bash's default behavior and source `~/.bash_login` next +if [ -f "$HOME/.bash_login" ]; then + source "$HOME/.bash_login" +else + source "$HOME/.profile" +fi diff --git a/.bashrc b/.bashrc new file mode 100644 index 0000000..0549e39 --- /dev/null +++ b/.bashrc @@ -0,0 +1,238 @@ +# Executed by bash when a non-login shell starts + + +# Ensure bash is running interactively +[[ $- != *i* ]] && return + + +# Check if a command can be found on the $PATH +command_exists() { + command -v "$1" 1>/dev/null 2>&1 +} + + + +# ================== +# Base Configuration +# ================== + + +# Disable Ctrl-S and Ctrl-Q +stty -ixon + +# Report status of background jobs immediately +set -o notify +# Show # of running jobs when exiting a shell +shopt -s checkjobs + +# Just type the directory to cd into it +shopt -s autocd +# Correct minor spelling mistakes with cd +shopt -s cdspell + +# Include hidden files in * glob expansion +shopt -s dotglob +shopt -s extglob +# Expand ** into (recursive) directories +shopt -s globstar +# Ignore case when * expanding +shopt -s nocaseglob + +# Update $ROWS and $COLUMNS after each command +shopt -s checkwinsize + + + +# ======= +# History +# ======= + + +# Remember multi-line commands in history as one command +shopt -s cmdhist +# Do not overwrite .bash_history file +shopt -s histappend +# Allow re-editing a failed history substitution +shopt -s histreedit +# Store multi-line commands in history without semicolons +shopt -s lithist + +# Cannot be set in `~/.profile` due to conflict with `zsh` (same env variable) +export HISTFILE="$HOME/.bash_history" + +# Ignore commands prefixed with a space, and ones used identically just before +# (this mimics zsh's default behavior) +export HISTCONTROL=ignoreboth + + + +# ========================= +# Shell Utilities & Aliases +# ========================= + + +source "$HOME/.config/shell/utils.sh" +source "$HOME/.config/shell/aliases.sh" + + +# Add tab completion for all aliases to commands with completion functions +# Source: https://superuser.com/a/437508 +_alias_completion() { + local namespace="alias_completion" + # parse function based completion definitions, where capture group 2 => function and 3 => trigger + local compl_regex='complete( +[^ ]+)* -F ([^ ]+) ("[^"]+"|[^ ]+)' + # parse alias definitions, where capture group 1 => trigger, 2 => command, 3 => command arguments + local alias_regex="alias ([^=]+)='(\"[^\"]+\"|[^ ]+)(( +[^ ]+)*)'" + # create array of function completion triggers, keeping multi-word triggers together + eval "local completions=($(complete -p | sed -Ene "/$compl_regex/s//'\3'/p"))" + (( ${#completions[@]} == 0 )) && return 0 + # create temporary file for wrapper functions and completions + rm -f "/tmp/${namespace}-*.tmp" # preliminary cleanup + local tmp_file; tmp_file="$(mktemp "/tmp/${namespace}-${RANDOM}XXX.tmp")" || return 1 + local completion_loader; completion_loader="$(complete -p -D 2>/dev/null | sed -Ene 's/.* -F ([^ ]*).*/\1/p')" + # read in " '' ''" lines from defined aliases + local line; while read line; do + eval "local alias_tokens; alias_tokens=($line)" 2>/dev/null || continue # some alias arg patterns cause an eval parse error + local alias_name="${alias_tokens[0]}" alias_cmd="${alias_tokens[1]}" alias_args="${alias_tokens[2]# }" + # skip aliases to pipes, boolean control structures and other command lists + # (leveraging that eval errs out if $alias_args contains unquoted shell metacharacters) + eval "local alias_arg_words; alias_arg_words=($alias_args)" 2>/dev/null || continue + # avoid expanding wildcards + read -a alias_arg_words <<< "$alias_args" + # skip alias if there is no completion function triggered by the aliased command + if [[ ! " ${completions[*]} " =~ " $alias_cmd " ]]; then + if [[ -n "$completion_loader" ]]; then + # force loading of completions for the aliased command + eval "$completion_loader $alias_cmd" + # 124 means completion loader was successful + [[ $? -eq 124 ]] || continue + completions+=($alias_cmd) + else + continue + fi + fi + local new_completion="$(complete -p "$alias_cmd")" + # create a wrapper inserting the alias arguments if any + if [[ -n $alias_args ]]; then + local compl_func="${new_completion/#* -F /}"; compl_func="${compl_func%% *}" + # avoid recursive call loops by ignoring our own functions + if [[ "${compl_func#_$namespace::}" == $compl_func ]]; then + local compl_wrapper="_${namespace}::${alias_name}" + echo "function $compl_wrapper { + (( COMP_CWORD += ${#alias_arg_words[@]} )) + COMP_WORDS=($alias_cmd $alias_args \${COMP_WORDS[@]:1}) + (( COMP_POINT -= \${#COMP_LINE} )) + COMP_LINE=\${COMP_LINE/$alias_name/$alias_cmd $alias_args} + (( COMP_POINT += \${#COMP_LINE} )) + $compl_func + }" >> "$tmp_file" + new_completion="${new_completion/ -F $compl_func / -F $compl_wrapper }" + fi + fi + # replace completion trigger by alias + new_completion="${new_completion% *} $alias_name" + echo "$new_completion" >> "$tmp_file" + done < <(alias -p | sed -Ene "s/$alias_regex/\1 '\2' '\3'/p") + source "$tmp_file" && \rm -f "$tmp_file" +}; _alias_completion + +# Must come after `_alias_completion` +alias dotfiles='/usr/bin/git --git-dir=$HOME/.dotfiles/ --work-tree=$HOME' + + + +# ================ +# Bash Completions +# ================ + + +# Enable programmable completion features +if ! shopt -oq posix; then + if [ -f /usr/share/bash-completion/bash_completion ]; then + source /usr/share/bash-completion/bash_completion + elif [ -f /etc/bash_completion ]; then + source /etc/bash_completion + fi +fi + + + +# ============ +# Key Bindings +# ============ + + +# Allow easier clearing of the screen (like in zsh) +bind -x '"\C-l": clear;' + + + +# ====== +# Prompt +# ====== + + +# Set a variable identifying the chroot you work in +if [ -z "${debian_chroot:-}" ] && [ -r /etc/debian_chroot ]; then + _debian_chroot=$(cat /etc/debian_chroot) +fi + + +# Mimic PowerLevel10k's git prompt (only rough approximation) +_prompt_git() { + local out ref uncommited unstaged untracked ahead behind + # Check if the pwd contains a git repository and exit early if it does not + ref=$(git rev-parse --abbrev-ref --symbolic-full-name HEAD 2> /dev/null) + [ "$ref" == "" ] && return + # Check if the current HEAD is detached or reachable by a ref + echo -en "\033[0;37m " + if [ "$ref" == "HEAD" ]; then + ref=$(git rev-parse --short HEAD) + echo -en "@" + fi + echo -en "\033[0;32m$ref\033[0m" + # Indicate if local is ahead and/or behind upstream + ahead=0 + behind=0 + git status 2>/dev/null | ( + while read -r line ; do + case "$line" in + *'diverged'*) # For simplicity, a diverged local branch is + ahead=1 ; behind=1 ; break ; ;; # indicated as being + *'ahead'*) # both ahead and behind its upstream + ahead=1 ; ;; + *'behind'*) + behind=1 ; ;; + esac + done + + if [ $ahead -gt 0 ] && [ $behind -gt 0 ]; then + echo -en "\033[0;32m <>\033[0m" + elif [ $ahead -gt 0 ]; then + echo -en "\033[0;32m >\033[0m" + elif [ $behind -gt 0 ]; then + echo -en "\033[0;32m <\033[0m" + fi + ) + # Indicate stashed files with a * + [ "$(git stash list 2> /dev/null)" != "" ] && echo -en "\033[0;32m *\033[0m" + # Indicate uncommited/staged with a + + git diff-index --cached --exit-code --quiet HEAD -- 2> /dev/null + [ $? -gt 0 ] && echo -en "\033[0;33m +\033[0m" + # Indicate unstaged with a ! + git diff-files --exit-code --quiet 2> /dev/null + [ $? -gt 0 ] && echo -en "\033[0;33m !\033[0m" + # Indicate untracked files with a ? + if [ "$(git ls-files --exclude-standard --others 2> /dev/null)" != "" ]; then + echo -en "\033[0;34m ?\033[0m" + fi +} + +# Mimic zsh's "%" symbol indicating background jobs +_prompt_jobs() { + local running + (( $(jobs -rp | wc -l) )) && echo -e "\033[0;32m %\033[0m" +} + +PS1='${chroot:+($_debian_chroot)}\w$(_prompt_git)$(_prompt_jobs) > ' +PS2='... ' diff --git a/.config/git/commit_msg_template.txt b/.config/git/commit_msg_template.txt new file mode 100644 index 0000000..560907a --- /dev/null +++ b/.config/git/commit_msg_template.txt @@ -0,0 +1,39 @@ +#=================================================| +# SUBJECT ========================================| +#=================================================| +# - what does the commit do +# - capitalize the first word +# - use imperative mood (e.g., "Add" over "Adds") +# - do not end the line with a period +# - start with "Fix" for any fixes +#---------- 50 characters / 1 line ---------------| + +#-------------------------------------------------| + + + +#=======================================================================| +# BODY (optional) ======================================================| +#=======================================================================| +# - explain what the commit does, why it does it, and how +# - do not format the text (e.g., Markdown) +# - use multiple lines starting with "-" as bullet points +# + first sub-level +# * second sub-level +# - link to external resources for more context +#---------- 72 characters / multiple lines (and paragraphs) ------------| + + + + + +#=======================================================================| +# ISSUE TRACKER (optional) =============================================| +#=======================================================================| +# - uncomment and adapt one of the lines below +# - use the "closes" keyword if applicable +# (see https://help.github.com/articles/closing-issues-using-keywords) +#-----------------------------------------------------------------------| +# Closes #41 on the issue tracker +# Fixes #42 on the issue tracker +# Resolves #43 on the issue tracker diff --git a/.config/git/ignore b/.config/git/ignore new file mode 100644 index 0000000..189fb11 --- /dev/null +++ b/.config/git/ignore @@ -0,0 +1,4 @@ +# Vim +*~ +.*.swp +.env diff --git a/.config/shell/README.md b/.config/shell/README.md new file mode 100644 index 0000000..8927e8f --- /dev/null +++ b/.config/shell/README.md @@ -0,0 +1,3 @@ +# Shell-related Configs + +This folder contains further files that are sourced by `bash` and `zsh`. diff --git a/.config/shell/aliases.sh b/.config/shell/aliases.sh new file mode 100644 index 0000000..bec47d9 --- /dev/null +++ b/.config/shell/aliases.sh @@ -0,0 +1,135 @@ +# Shell aliases used for both bash and zsh + + +# Check if a command can be found on the $PATH. +command_exists() { + command -v "$1" 1>/dev/null 2>&1 +} + +# Check if we are running from within a zsh instance. +in_zsh() { + [ -n "$ZSH_VERSION" ] +} + + +# Re-run last command with sudo privileges +if in_zsh; then + alias ,,='sudo $(fc -ln -1)' +else + alias ,,='sudo $(history -p !!)' +fi + + +# Global aliases +if in_zsh; then + alias -g F='| fzf' + alias -g G='| grep' + alias -g H='| head' + alias -g L='| less' + alias -g T='| tail' + alias -g NE='2 > /dev/null' + alias -g NUL='> /dev/null 2>&1' +fi + + +alias cls='clear' +alias help='man' + + +# Avoid bad mistakes and show what happens +alias cp="cp --interactive --verbose" +alias ln='ln --interactive --verbose' +alias mv='mv --interactive --verbose' +alias rm='rm -I --preserve-root --verbose' + + +# Make working with files more convenient + +alias cd..='cd ..' +alias ..='cd ..' +alias ...='cd ../..' +alias ....='cd ../../..' +alias .....='cd ../../../..' + +alias mkdir='mkdir -p' +alias md='mkdir' +alias rmdir='rmdir --parents --verbose' +alias rd='rmdir' + +alias grep='grep --color=auto --exclude-dir={.cache,\*.egg-info,.git,.nox,.tox,.venv}' +alias egrep='egrep --color=auto --exclude-dir={.cache,\*.egg-info,.git,.nox,.tox,.venv}' +alias fgrep='fgrep --color=auto --exclude-dir={.cache,*.egg-info,.git,.nox,.tox,.venv}' + +alias fdir='find . -type d -name' +alias ffile='find . -type f -name' + +alias ls='ls --classify --color=auto --group-directories-first --human-readable --no-group --time-style=long-iso' +alias la='ls --almost-all' +alias lal='la -l' +alias ll='ls -l' +alias l.='ls --directory .*' +alias ll.='l. -l' + +alias df='df --human-readable' +alias du='du --human-readable' +alias diff='diff --color=auto --unified' +command_exists colordiff && alias diff='colordiff --unified' +alias free='free --human --total' +alias less='less --chop-long-lines --ignore-case --LONG-PROMPT --no-init --status-column --quit-if-one-screen' +alias more='less' +alias tree='tree -C --dirsfirst' + + +# Aliases for various utilities +alias datetime='date +"%Y-%m-%d %H:%M:%S %z (%Z)"' +alias datetime-iso='date --iso-8601=seconds' +alias external-ip="curl https://icanhazip.com" +alias external-ip-alt="curl https://ipinfo.io/ip\?token=cfd78a97e15ebf && echo" +alias external-ip-extended-infos="curl https://ipinfo.io/json\?token=cfd78a97e15ebf && echo" +alias speedtest="curl -s https://raw.githubusercontent.com/sivel/speedtest-cli/22210ca35228f0bbcef75a7c14587c4ecb875ab4/speedtest.py | python -" + + +# Fix common typos +command_exists ifconfig && alias ipconfig='ifconfig' +command_exists R && alias r='R' + + +# Use sane defaults +command_exists exa && alias exa='exa --group-directories-first --git --time-style=long-iso' +command_exists netstat && alias ports='netstat -tulanp' +command_exists screenfetch && alias screenfetch='screenfetch -n' +alias uptime='uptime --pretty' +alias wget='wget --continue' + + +# Create short aliases +command_exists batcat && alias bat='batcat' +command_exists fdfind && alias fd='fdfind' +command_exists ranger && alias rn='ranger' +command_exists screenfetch && alias sf='screenfetch' + + +# Integrate git +if command_exists git; then + alias g='git' + + # All git aliases are shell aliases with a 'g' prefix. + for al in $(git internal-aliases); do + # Only "real" (i.e., short) aliases are created. + [ ${#al} -lt 7 ] && eval "alias g$al='git $al'" + done + + # Check if a 'main' branch exists in place of a 'master' branch. + git_main_branch() { + if [[ -n "$(git branch --list main)" ]]; then + echo 'main' + else + echo 'master' + fi + } +fi + + +# (Un-)Encrypt vaults +alias open-documents-vault='gocryptfs -q -extpass "pass getraenkemarkt/vaults/documents" $HOME/nextcloud/vault/ $HOME/.vault/documents' +alias close-documents-vault='fusermount -q -u $HOME/.vault/documents' diff --git a/.config/shell/logout.sh b/.config/shell/logout.sh new file mode 100644 index 0000000..a274c9a --- /dev/null +++ b/.config/shell/logout.sh @@ -0,0 +1,7 @@ +# This file is sourced by a login shell upon logout + + +# Clear the screen to increase privacy +if [ "$SHLVL" = 1 ]; then + [ -x /usr/bin/clear ] && /usr/bin/clear || [ -x /usr/bin/clear_console ] && /usr/bin/clear_console -q +fi diff --git a/.config/shell/utils.sh b/.config/shell/utils.sh new file mode 100644 index 0000000..ab3ccd4 --- /dev/null +++ b/.config/shell/utils.sh @@ -0,0 +1,335 @@ +# This file is executed either by bash or zsh and holds all +# initializations and utility definitions used in both shells. + + +# Check if a command can be found on the $PATH. +command_exists() { + command -v "$1" 1>/dev/null 2>&1 +} + +# Check if we are running from within a zsh instance. +in_zsh() { + [ -n "$ZSH_VERSION" ] +} + + + +# ========================= +# Initialize some CLI tools +# ========================= + + +# Load custom $LS_COLORS if available +if command_exists dircolors; then + test -r ~/.dircolors && eval "$(dircolors -b ~/.dircolors)" || eval "$(dircolors -b)" +fi + + +# Make less understand some binary types (e.g., PDFs) +# Source: https://github.com/wofr06/lesspipe +command_exists lesspipe && eval "$(SHELL=/bin/sh lesspipe)" + + +# Configure the keyboard: +# - make right alt and menu keys the compose key, e.g., for umlauts +# - make caps lock a ctrl modifier and Esc key +setxkbmap us -option 'compose:menu,compose:ralt,caps:ctrl_modifier' +command_exists xcape && xcape -e "Caps_Lock=Escape" + + + +# ============================== +# Working with files and folders +# ============================== + + +# List the $PATH variable, one element per line +# If an argument is passed, grep for it +path() { + if [ -n "$1" ]; then + echo "$PATH" | perl -p -e 's/:/\n/g;' | grep -i "$1" + else + echo "$PATH" | perl -p -e 's/:/\n/g;' + fi +} + + +# Show folders by size. +disk_usage() { + local dest + if [ -n "$1" ]; then + dest="$1" + else + dest=. + fi + \du --human-readable --max-depth=1 $dest 2>/dev/null | sort --human-numeric-sort --reverse +} + + +# Search all files in a directory and its children. +lsgrep() { + ls --almost-all --directory . ./**/* | uniq | grep --color=auto -i "$*" +} + +# Make a directory and cd there. +mcd() { + test -n "$1" || return + mkdir -p "$1" && cd "$1" || return +} + + +# Extract a compressed archive or file. +extract() { + if [ -f "$1" ] ; then + case "$1" in + *.tar.bz2) tar xjvf "$1" ;; + *.tar.gz) tar xzvf "$1" ;; + *.tar.xz) tar xvf "$1" ;; + *.bz2) bzip2 -d "$1" ;; + *.rar) unrar2dir "$1" ;; + *.gz) gunzip "$1" ;; + *.tar) tar xf "$1" ;; + *.tbz2) tar xjf "$1" ;; + *.tgz) tar xzf "$1" ;; + *.zip) unzip2dir "$1" ;; + *.Z) uncompress "$1" ;; + *.7z) 7z x "$1" ;; + *.ace) unace x "$1" ;; + *) echo "'$1' cannot be extracted automatically" ;; + esac + else + echo "'$1' is not a file" + fi +} + +# Create a tar.gz archive from a given directory. +mktar() { + tar cvzf "${1%%/}.tar.gz" "${1%%/}/" +} + +# Create a zip archive from a given file or directory. +mkzip() { + zip -r "${1%%/}.zip" "$1" +} + + + +# ================================= +# Creating random login credentials +# ================================= + + +# Create random passwords for logins +genpw() { + PARSED=$(getopt --quiet --options=acn: --longoptions=alphanum,clip,chars: -- "$@") + eval set -- "$PARSED" + SYMBOLS='--symbols' + CHARS=30 + XCLIP=false + while true; do + case "$1" in + -a|--alphanum) + SYMBOLS='' + shift + ;; + -c|--clip) + XCLIP=true + shift + ;; + -n|--chars) + CHARS=$2 + shift 2 + ;; + --) + shift + break + ;; + *) + echo 'Programming error' + break + ;; + esac + done + PW=$(pwgen --ambiguous --capitalize --numerals --secure $SYMBOLS --remove-chars="|/\\\"\`\'()[]{}<>^~@§$\#" $CHARS 1) + if [[ $XCLIP == true ]]; then + echo $PW | xclip -selection c + else + echo $PW + fi +} + +# Short password that is accepted by most services +alias genpw-alphanum='pwgen --ambiguous --capitalize --numerals --secure 30 1' + +# Email addresses created with this utility look kind of "normal" but are totally random +genemail() { + PARSED=$(getopt --quiet --options=c --longoptions=clip -- "$@") + eval set -- "$PARSED" + XCLIP=false + while true; do + case "$1" in + -c|--clip) + XCLIP=true + shift + ;; + --) + shift + break + ;; + *) + echo 'Programming error' + break + ;; + esac + done + FIRST=$(shuf -i 4-5 -n 1) + LAST=$(shuf -i 8-10 -n 1) + USER="$(gpw 1 $FIRST).$(gpw 1 $LAST)@webartifex.biz" + if [[ $XCLIP == true ]]; then + echo $USER | xclip -selection c + else + echo $USER + fi +} + + + +# ============================= +# Automate the update machinery +# ============================= + + +# Pull down latest version of dot files +update-dotfiles() { + echo -e '\nUpdating dotfiles\n' + + # The `dotfiles` alias is defined in ~/.bashrc at the end of the "Shell Utilities & Aliases" section + git --git-dir=$HOME/.dotfiles/ --work-tree=$HOME stash + git --git-dir=$HOME/.dotfiles/ --work-tree=$HOME fetch --all --prune + git --git-dir=$HOME/.dotfiles/ --work-tree=$HOME pull --rebase + git --git-dir=$HOME/.dotfiles/ --work-tree=$HOME stash pop +} + + +# Run entire aptitude upgrade cycle (incl. removal of old packages). +update-apt() { + echo -e '\nUpdating apt packages\n' + + sudo apt update + echo + sudo apt upgrade + echo + sudo apt autoremove + echo + sudo apt autoclean +} + +remove-old-snaps() { + sudo snap list --all | awk "/disabled/{print $1, $3}" | + while read snapname revision; do + sudo snap remove "$snapname" --revision="$revision" + done +} + + +# Update all repositories in ~/repos without the ones related to zsh/zplug +update-repositories() { + echo -e '\nUpdating repositories unrelated to zsh/zplug\n' + + local cwd + cwd=$(pwd) + cd "$REPOS" + for dir in */; do + [ "$dir" = "zsh/" ] && continue + echo "$REPOS/$dir" + cd "$REPOS/$dir" + git stash + git fetch --all --prune + git pull --rebase + git stash pop + echo + done + cd "$cwd" +} + +# Update everything related to zsh +update-zsh() { + echo -e '\nUpdating zsh/zplug related repositories\n' + + if in_zsh; then + omz update + zplug update + zplug install + zplug load + else + local cwd + cwd=$(pwd) + # Pull down latest versions manually. + for dir in $HOME/.zplug/repos/*/*/; do + echo "$dir" && cd "$dir" + git fetch --all --prune + git pull --rebase + done + echo "$HOME/.oh-my-zsh" && cd "$HOME/.oh-my-zsh" + git fetch --all --prune + git pull --rebase + cd "$cwd" + fi +} + + +# Wrapper to run several update functions at once +update-machine() { + sudo --validate || return + + update-apt + + if command_exists flatpak; then + echo -e '\nUpdating flatpaks\n' + sudo flatpak update -y + fi + + if command_exists snap; then + echo -e '\nUpdating snaps\n' + sudo snap refresh + remove-old-snaps + fi + + update-dotfiles + update-zsh + + echo -e '\nUpdating password store\n' + pass git pull + echo + + sudo updatedb -U / + echo + + sudo --reset-timestamp +} + + + +# ======================= +# Various other Utilities +# ======================= + + +# List all internal IPs. +internal-ips() { + if command_exists ifconfig; then + ifconfig | awk '/inet /{ gsub(/addr:/, ""); print $2 }' + else + echo 'ifconfig not installed' + fi +} + + +# Obtain a weather report +weather() { + if [ -n "$1" ]; then + curl "v1.wttr.in/$1" + else + curl 'v1.wttr.in' + fi +} diff --git a/.gitconfig b/.gitconfig new file mode 100644 index 0000000..c79ba13 --- /dev/null +++ b/.gitconfig @@ -0,0 +1,205 @@ +[alias] +# Important: The accompanying ~/.bashrc file loads all git aliases with +# less than 7 characters into the global bash "namespace" with a "g" prefix +# Example: git add <=> git a <=> ga +a = add +ap = add --patch +bi = bisect +br = branch +bra = branch --all +brd = branch --delete +brdd = branch --delete --force +brm = branch --move +cf = cat-file +ci = commit +cim = commit --message +cl = clone +co = checkout +cob = checkout -b +cod = checkout develop +com = checkout master +cp = cherry-pick +de = describe --tags +df = diff +fe = fetch +lg = log +lga = log --all +mb = merge-base +me = merge +mea = merge --abort +mec = merge --continue +mefeat = "!f() { if [ $# -eq 0 ]; then echo "Must specify a branch to merge in"; exit 1; fi; git check-pull; if [ $? -gt 0 ]; then echo "$1 must be rebased first"; exit 1; fi; cb=$(git current-branch) && printf '# SUBJECT\n# =======\n# - what does the commit do\n# - capitalize the first word and use the\n# imperative mood (e.g. "Add" vs "Adds")\n# - do not end the line with a period\n# - start with "Fix" for any hotfixes\n# ========= 50 characters / 1 line ============= |\nMerge in \"%s\"\n# ============================================== |\n\n\n# BODY (optional)\n# ===============\n# - explain what the commit does, why it does it, and how\n# - do not format the text (e.g., Markdown or reStructuredText)\n# - use multiple lines starting with "-" as bullet points\n# - link to external resources for even more context where appropriate\n# ========= 72 characters / multiple lines (and paragraphs) ========== |\nMerge branch \"%s\" into \"%s\"\n\nSummary of the merged in commits:\n' $1 $1 $cb > .merge_msg.txt.tmp && git log --format=format:' * %h: %s' $cb..$1 >> .merge_msg.txt.tmp && printf '\n\n\n# ==================================================================== |\n\n\n# GITHUB ISSUE (optional)\n# =======================\n# - uncomment and adapt one of the lines below\n# - use the "closes" keyword if applicable\n# (see https://help.github.com/en/articles/closing-issues-using-keywords)\n#\n# Related GitHub issue: #21\n# This commit closes #42 on the GitHub issue tracker\n\n\n#\n# END\n#\n' >> .merge_msg.txt.tmp && git merge --no-ff --no-commit $1 && SKIP=no-commit-to-branch git commit --edit --file=.merge_msg.txt.tmp; rm -f .merge_msg.txt.tmp; }; f" +meff = merge --ff-only +menoff = merge --no-ff +pl = pull +plrb = pull --rebase +ps = push +psf = push --force +rb = rebase --committer-date-is-author-date +rba = rebase --abort +rbc = rebase --continue +rbi = rebase --interactive +rbq = rebase --quit +rbs = rebase --skip +rl = reflog +rm = rm # To make it available as the grm alias +rp = rev-parse +rs = reset +rv = revert +s = status +ss = status --short +sh = show +st = stash +sta = stash push --include-untracked # push does not go into the shortcut! +stam = stash push --include-untracked --message +stapp = stash apply +stl = stash list +stp = stash pop +stsh = stash show +# Provide an overview of all aliases. Second one is for use in ~/.bashrc +aliases = config --get-regexp 'alias.*' +internal-aliases = !git config --list | grep 'alias\\.' | sed 's/alias\\.\\([^=]*\\)=\\(.*\\)/\\1/' | sort +# Provide synonyms as "specified" in the git status header +discard = checkout -- +unstage = reset HEAD -- +# Common tasks with tedious or non-intuitive flags +amend-commit = !git log -n 1 --pretty=tformat:%B | git commit -F - --amend # Keep the commit message +check-pull = "!f() { git fetch; upstream=${1:-'@{u}'}; local=$(git rev-parse @); remote=$(git rev-parse "$upstream"); base=$(git merge-base @ "$upstream"); if [ $local = $remote ]; then echo "Up-to-date"; exit 0; elif [ $local = $base ]; then echo "Local branch is behind upstream"; elif [ $remote = $base ]; then echo "Local branch is ahead of upstream"; else echo "Local and remote branches diverged"; fi; exit 1; }; f" +current-branch = !git rev-parse --abbrev-ref HEAD +project-root = rev-parse --show-toplevel +uncommit = reset --soft HEAD~1 +# Sync the working directory into the index +rm-deleted = !git ls-files -z --deleted | xargs -r -0 git rm +sync-pwd-to-index = !git rm-deleted && git add . --all +sy = !git sync-pwd-to-index +# Make minimal diff the default +diff-minimal = diff --color-words=. --ws-error-highlight=all +d = diff --color-words=. --ws-error-highlight=all +dlc = diff --color-words=. --ws-error-highlight=all HEAD +ds = diff --color-words=. --ws-error-highlight=all --staged +# Clean the project folder with intuitive commands +# Always keep the .python-version file, which is also often in ~.gitignore +clean-all = !git reset --hard && git clean-ignored && git clean-untracked +clean-ignored = "!f() { if [ -f .python-version ]; then mv .python-version .python-version.tmp; fi; if [ -f .env ]; then mv .env .env.tmp; fi; git clean -X -d -f "$@"; if [ -f .python-version.tmp ]; then mv .python-version.tmp .python-version; fi; if [ -f .env.tmp ]; then mv .env.tmp .env; fi }; f" +clean-untracked = !git clean -x -d -e ".python-version" -e ".env" -f # The -e flag does not work with -X +# Delete everything not reachable from a branch from the repository +gc-everything = "!f() { git -c gc.reflogExpire=0 -c gc.reflogExpireUnreachable=0 -c gc.rerereresolved=0 -c gc.rerereunresolved=0 -c gc.pruneExpire=now gc "$@"; }; f" +# Make the logs look nice by default +last-commit = log --pretty='%C(auto)%h: %s%d%Creset%n%C(dim)%aN @ %ad => %ar%n%+b' --date=format:'%a %Y-%m-%d %H:%M:%S %z' -1 -p --stat +lc = log --pretty='%C(auto)%h: %s%d%Creset%n%C(dim)%aN @ %ad => %ar%n%+b' --date=format:'%a %Y-%m-%d %H:%M:%S %z' -1 -p --stat +history = log --pretty='%C(auto)%h: %s%d%Creset%n%C(dim)%aN @ %ad => %ar%n%+b' --date=format:'%a %Y-%m-%d %H:%M:%S %z' --graph +hi = log --pretty='%C(auto)%h: %s%d%Creset%n%C(dim)%aN @ %ad => %ar%n%+b' --date=format:'%a %Y-%m-%d %H:%M:%S %z' --graph +hia = log --pretty='%C(auto)%h: %s%d%Creset%n%C(dim)%aN @ %ad => %ar%n%+b' --date=format:'%a %Y-%m-%d %H:%M:%S %z' --graph --all +summary = log --pretty='%C(auto)%h: %s%d%Creset%n%C(dim)%an @ %ad => %ar%n' --date=format:'%a %Y-%m-%d %H:%M:%S %z' --graph +su = log --pretty='%C(auto)%h: %s%d%Creset%n%C(dim)%an @ %ad => %ar%n' --date=format:'%a %Y-%m-%d %H:%M:%S %z' --graph +sua = log --pretty='%C(auto)%h: %s%d%Creset%n%C(dim)%an @ %ad => %ar%n' --date=format:'%a %Y-%m-%d %H:%M:%S %z' --graph --all +oneline = log --pretty='%C(auto)%h: %s%d' --graph +ol = log --pretty='%C(auto)%h: %s%d' --graph +ola = log --pretty='%C(auto)%h: %s%d' --graph --all +# Search the repository +grep-code = grep --break --context 1 --full-name --heading --line-number --show-function +grepc = grep --break --context 1 --full-name --heading --line-number --show-function +grep-log = log --all --regexp-ignore-case --pretty='%C(auto)%h: %s%+D%Creset%n%C(reverse)%C(dim)%aN @ %ad = %ar%Creset%n%+b' --date=format:'%a %Y-%m-%d %H:%M:%S' --grep +grepl = log --all --regexp-ignore-case --pretty='%C(auto)%h: %s%+D%Creset%n%C(reverse)%C(dim)%aN @ %ad = %ar%Creset%n%+b' --date=format:'%a %Y-%m-%d %H:%M:%S' --grep +grep-text = grep --break --context 1 --full-name --heading --ignore-case --line-number +grept = grep --break --context 1 --full-name --heading --ignore-case --line-number +# Push current branch to origin +push-to-origin = "!f(){ git push --set-upstream origin $(git current-branch) "$@"; }; f" +pso = "!f(){ git push --set-upstream origin $(git current-branch) "$@"; }; f" + +[clean] +requireforce = true + +[color "branch"] +current = cyan dim bold reverse +local = green bold +remote = red bold + +[color "decorate"] +HEAD = cyan dim bold reverse +branch = green bold +remoteBranch = red bold +stash = magenta dim bold reverse +tag = magenta bold + +[color "diff"] +context = white +frag = blue dim bold reverse +meta = yellow dim bold reverse +new = green bold +old = red bold +whitespace = red dim bold reverse + +[color "grep"] +context = white +filename = yellow dim bold reverse +function = white bold +linenumber = blue dim bold reverse +match = red bold +selected = white +separator = blue dim bold reverse + +[color "interactive"] +error = red dim bold reverse +header = white +help = yellow bold +prompt = white dim bold reverse + +[color "status"] +added = green bold +branch = cyan dim bold reverse +changed = yellow bold +header = white +localBranch = green bold +nobranch = red dim bold reverse +remoteBranch = red bold +unmerged = yellow dim bold reverse +untracked = red bold + +[commit] +cleanup = strip +gpgSign = true +template = ~/.config/git/commit_msg_template.txt +verbose = true + +[core] +editor = vim +excludesfile = ~/.config/git/ignore +pager = less --chop-long-lines --ignore-case --LONG-PROMPT --status-column --quit-if-one-screen +whitespace = -space-before-tab,tab-in-indent + +[diff] +renames = true +submodule = log + +[help] +autocorrect = 50 + +[merge] +conflictstyle = diff3 +ff = only + +[pull] +ff = only +rebase = true + +[push] +default = upstream +recursesubmodules = check + +[rerere] +enabled = true + +[url "https://bitbucket.org/"] +insteadOf = bb: + +[url "https://github.com/"] +insteadOf = gh: + +[url "https://gitlab.com/"] +insteadOf = gl: + +[user] +name = Alexander Hess +email = alexander@webartifex.biz +signingKey = AB5C0E319D77350FBA6CF143344EA5AB10D868E0 diff --git a/.p10k.zsh b/.p10k.zsh new file mode 100644 index 0000000..eaeadc1 --- /dev/null +++ b/.p10k.zsh @@ -0,0 +1,1622 @@ +# Generated by Powerlevel10k configuration wizard on 2022-07-11 at 02:12 CEST. +# Based on romkatv/powerlevel10k/config/p10k-lean.zsh, checksum 28996. +# Wizard options: awesome-fontconfig, large icons, ascii, lean, 1 line, compact, +# concise, transient_prompt, instant_prompt=verbose. +# Type `p10k configure` to generate another config. +# +# Config for Powerlevel10k with lean prompt style. Type `p10k configure` to generate +# your own config based on it. +# +# Tip: Looking for a nice color? Here's a one-liner to print colormap. +# +# for i in {0..255}; do print -Pn "%K{$i} %k%F{$i}${(l:3::0:)i}%f " ${${(M)$((i%6)):#3}:+$'\n'}; done + +# Temporarily change options. +'builtin' 'local' '-a' 'p10k_config_opts' +[[ ! -o 'aliases' ]] || p10k_config_opts+=('aliases') +[[ ! -o 'sh_glob' ]] || p10k_config_opts+=('sh_glob') +[[ ! -o 'no_brace_expand' ]] || p10k_config_opts+=('no_brace_expand') +'builtin' 'setopt' 'no_aliases' 'no_sh_glob' 'brace_expand' + +() { + emulate -L zsh -o extended_glob + + # Unset all configuration options. This allows you to apply configuration changes without + # restarting zsh. Edit ~/.p10k.zsh and type `source ~/.p10k.zsh`. + unset -m '(POWERLEVEL9K_*|DEFAULT_USER)~POWERLEVEL9K_GITSTATUS_DIR' + + # Zsh >= 5.1 is required. + autoload -Uz is-at-least && is-at-least 5.1 || return + + # The list of segments shown on the left. Fill it with the most important segments. + typeset -g POWERLEVEL9K_LEFT_PROMPT_ELEMENTS=( + # os_icon # os identifier + dir # current directory + vcs # git status + prompt_char # prompt symbol + ) + + # The list of segments shown on the right. Fill it with less important segments. + # Right prompt on the last prompt line (where you are typing your commands) gets + # automatically hidden when the input line reaches it. Right prompt above the + # last prompt line gets hidden if it would overlap with left prompt. + typeset -g POWERLEVEL9K_RIGHT_PROMPT_ELEMENTS=( + status # exit code of the last command + command_execution_time # duration of the last command + background_jobs # presence of background jobs + direnv # direnv status (https://direnv.net/) + asdf # asdf version manager (https://github.com/asdf-vm/asdf) + virtualenv # python virtual environment (https://docs.python.org/3/library/venv.html) + anaconda # conda environment (https://conda.io/) + pyenv # python environment (https://github.com/pyenv/pyenv) + goenv # go environment (https://github.com/syndbg/goenv) + nodenv # node.js version from nodenv (https://github.com/nodenv/nodenv) + nvm # node.js version from nvm (https://github.com/nvm-sh/nvm) + nodeenv # node.js environment (https://github.com/ekalinin/nodeenv) + # node_version # node.js version + # go_version # go version (https://golang.org) + # rust_version # rustc version (https://www.rust-lang.org) + # dotnet_version # .NET version (https://dotnet.microsoft.com) + # php_version # php version (https://www.php.net/) + # laravel_version # laravel php framework version (https://laravel.com/) + # java_version # java version (https://www.java.com/) + # package # name@version from package.json (https://docs.npmjs.com/files/package.json) + rbenv # ruby version from rbenv (https://github.com/rbenv/rbenv) + rvm # ruby version from rvm (https://rvm.io) + fvm # flutter version management (https://github.com/leoafarias/fvm) + luaenv # lua version from luaenv (https://github.com/cehoffman/luaenv) + jenv # java version from jenv (https://github.com/jenv/jenv) + plenv # perl version from plenv (https://github.com/tokuhirom/plenv) + perlbrew # perl version from perlbrew (https://github.com/gugod/App-perlbrew) + phpenv # php version from phpenv (https://github.com/phpenv/phpenv) + scalaenv # scala version from scalaenv (https://github.com/scalaenv/scalaenv) + haskell_stack # haskell version from stack (https://haskellstack.org/) + kubecontext # current kubernetes context (https://kubernetes.io/) + terraform # terraform workspace (https://www.terraform.io) + # terraform_version # terraform version (https://www.terraform.io) + aws # aws profile (https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-profiles.html) + aws_eb_env # aws elastic beanstalk environment (https://aws.amazon.com/elasticbeanstalk/) + azure # azure account name (https://docs.microsoft.com/en-us/cli/azure) + gcloud # google cloud cli account and project (https://cloud.google.com/) + google_app_cred # google application credentials (https://cloud.google.com/docs/authentication/production) + toolbox # toolbox name (https://github.com/containers/toolbox) + context # user@hostname + nordvpn # nordvpn connection status, linux only (https://nordvpn.com/) + ranger # ranger shell (https://github.com/ranger/ranger) + nnn # nnn shell (https://github.com/jarun/nnn) + xplr # xplr shell (https://github.com/sayanarijit/xplr) + vim_shell # vim shell indicator (:sh) + midnight_commander # midnight commander shell (https://midnight-commander.org/) + nix_shell # nix shell (https://nixos.org/nixos/nix-pills/developing-with-nix-shell.html) + # vpn_ip # virtual private network indicator + # load # CPU load + # disk_usage # disk usage + # ram # free RAM + # swap # used swap + todo # todo items (https://github.com/todotxt/todo.txt-cli) + timewarrior # timewarrior tracking status (https://timewarrior.net/) + taskwarrior # taskwarrior task count (https://taskwarrior.org/) + # time # current time + # ip # ip address and bandwidth usage for a specified network interface + # public_ip # public IP address + # proxy # system-wide http/https/ftp proxy + # battery # internal battery + # wifi # wifi speed + # example # example user-defined segment (see prompt_example function below) + ) + + # Defines character set used by powerlevel10k. It's best to let `p10k configure` set it for you. + typeset -g POWERLEVEL9K_MODE=ascii + # When set to `moderate`, some icons will have an extra space after them. This is meant to avoid + # icon overlap when using non-monospace fonts. When set to `none`, spaces are not added. + typeset -g POWERLEVEL9K_ICON_PADDING=none + + # Basic style options that define the overall look of your prompt. You probably don't want to + # change them. + typeset -g POWERLEVEL9K_BACKGROUND= # transparent background + typeset -g POWERLEVEL9K_{LEFT,RIGHT}_{LEFT,RIGHT}_WHITESPACE= # no surrounding whitespace + typeset -g POWERLEVEL9K_{LEFT,RIGHT}_SUBSEGMENT_SEPARATOR=' ' # separate segments with a space + typeset -g POWERLEVEL9K_{LEFT,RIGHT}_SEGMENT_SEPARATOR= # no end-of-line symbol + + # When set to true, icons appear before content on both sides of the prompt. When set + # to false, icons go after content. If empty or not set, icons go before content in the left + # prompt and after content in the right prompt. + # + # You can also override it for a specific segment: + # + # POWERLEVEL9K_STATUS_ICON_BEFORE_CONTENT=false + # + # Or for a specific segment in specific state: + # + # POWERLEVEL9K_DIR_NOT_WRITABLE_ICON_BEFORE_CONTENT=false + typeset -g POWERLEVEL9K_ICON_BEFORE_CONTENT=true + + # Add an empty line before each prompt. + typeset -g POWERLEVEL9K_PROMPT_ADD_NEWLINE=false + + # Connect left prompt lines with these symbols. + typeset -g POWERLEVEL9K_MULTILINE_FIRST_PROMPT_PREFIX= + typeset -g POWERLEVEL9K_MULTILINE_NEWLINE_PROMPT_PREFIX= + typeset -g POWERLEVEL9K_MULTILINE_LAST_PROMPT_PREFIX= + # Connect right prompt lines with these symbols. + typeset -g POWERLEVEL9K_MULTILINE_FIRST_PROMPT_SUFFIX= + typeset -g POWERLEVEL9K_MULTILINE_NEWLINE_PROMPT_SUFFIX= + typeset -g POWERLEVEL9K_MULTILINE_LAST_PROMPT_SUFFIX= + + # The left end of left prompt. + typeset -g POWERLEVEL9K_LEFT_PROMPT_FIRST_SEGMENT_START_SYMBOL= + # The right end of right prompt. + typeset -g POWERLEVEL9K_RIGHT_PROMPT_LAST_SEGMENT_END_SYMBOL= + + # Ruler, a.k.a. the horizontal line before each prompt. If you set it to true, you'll + # probably want to set POWERLEVEL9K_PROMPT_ADD_NEWLINE=false above and + # POWERLEVEL9K_MULTILINE_FIRST_PROMPT_GAP_CHAR=' ' below. + typeset -g POWERLEVEL9K_SHOW_RULER=false + typeset -g POWERLEVEL9K_RULER_CHAR='-' # reasonable alternative: '·' + typeset -g POWERLEVEL9K_RULER_FOREGROUND=242 + + # Filler between left and right prompt on the first prompt line. You can set it to '·' or '-' + # to make it easier to see the alignment between left and right prompt and to separate prompt + # from command output. It serves the same purpose as ruler (see above) without increasing + # the number of prompt lines. You'll probably want to set POWERLEVEL9K_SHOW_RULER=false + # if using this. You might also like POWERLEVEL9K_PROMPT_ADD_NEWLINE=false for more compact + # prompt. + typeset -g POWERLEVEL9K_MULTILINE_FIRST_PROMPT_GAP_CHAR=' ' + if [[ $POWERLEVEL9K_MULTILINE_FIRST_PROMPT_GAP_CHAR != ' ' ]]; then + # The color of the filler. + typeset -g POWERLEVEL9K_MULTILINE_FIRST_PROMPT_GAP_FOREGROUND=242 + # Add a space between the end of left prompt and the filler. + typeset -g POWERLEVEL9K_LEFT_PROMPT_LAST_SEGMENT_END_SYMBOL=' ' + # Add a space between the filler and the start of right prompt. + typeset -g POWERLEVEL9K_RIGHT_PROMPT_FIRST_SEGMENT_START_SYMBOL=' ' + # Start filler from the edge of the screen if there are no left segments on the first line. + typeset -g POWERLEVEL9K_EMPTY_LINE_LEFT_PROMPT_FIRST_SEGMENT_END_SYMBOL='%{%}' + # End filler on the edge of the screen if there are no right segments on the first line. + typeset -g POWERLEVEL9K_EMPTY_LINE_RIGHT_PROMPT_FIRST_SEGMENT_START_SYMBOL='%{%}' + fi + + #################################[ os_icon: os identifier ]################################## + # OS identifier color. + typeset -g POWERLEVEL9K_OS_ICON_FOREGROUND= + # Custom icon. + # typeset -g POWERLEVEL9K_OS_ICON_CONTENT_EXPANSION='⭐' + + ################################[ prompt_char: prompt symbol ]################################ + # Green prompt symbol if the last command succeeded. + typeset -g POWERLEVEL9K_PROMPT_CHAR_OK_{VIINS,VICMD,VIVIS,VIOWR}_FOREGROUND=76 + # Red prompt symbol if the last command failed. + typeset -g POWERLEVEL9K_PROMPT_CHAR_ERROR_{VIINS,VICMD,VIVIS,VIOWR}_FOREGROUND=196 + # Default prompt symbol. + typeset -g POWERLEVEL9K_PROMPT_CHAR_{OK,ERROR}_VIINS_CONTENT_EXPANSION='>' + # Prompt symbol in command vi mode. + typeset -g POWERLEVEL9K_PROMPT_CHAR_{OK,ERROR}_VICMD_CONTENT_EXPANSION='<' + # Prompt symbol in visual vi mode. + typeset -g POWERLEVEL9K_PROMPT_CHAR_{OK,ERROR}_VIVIS_CONTENT_EXPANSION='V' + # Prompt symbol in overwrite vi mode. + typeset -g POWERLEVEL9K_PROMPT_CHAR_{OK,ERROR}_VIOWR_CONTENT_EXPANSION='^' + typeset -g POWERLEVEL9K_PROMPT_CHAR_OVERWRITE_STATE=true + # No line terminator if prompt_char is the last segment. + typeset -g POWERLEVEL9K_PROMPT_CHAR_LEFT_PROMPT_LAST_SEGMENT_END_SYMBOL='' + # No line introducer if prompt_char is the first segment. + typeset -g POWERLEVEL9K_PROMPT_CHAR_LEFT_PROMPT_FIRST_SEGMENT_START_SYMBOL= + + ##################################[ dir: current directory ]################################## + # Default current directory color. + typeset -g POWERLEVEL9K_DIR_FOREGROUND=31 + # If directory is too long, shorten some of its segments to the shortest possible unique + # prefix. The shortened directory can be tab-completed to the original. + typeset -g POWERLEVEL9K_SHORTEN_STRATEGY=truncate_to_unique + # Replace removed segment suffixes with this symbol. + typeset -g POWERLEVEL9K_SHORTEN_DELIMITER= + # Color of the shortened directory segments. + typeset -g POWERLEVEL9K_DIR_SHORTENED_FOREGROUND=103 + # Color of the anchor directory segments. Anchor segments are never shortened. The first + # segment is always an anchor. + typeset -g POWERLEVEL9K_DIR_ANCHOR_FOREGROUND=39 + # Display anchor directory segments in bold. + typeset -g POWERLEVEL9K_DIR_ANCHOR_BOLD=true + # Don't shorten directories that contain any of these files. They are anchors. + local anchor_files=( + .bzr + .citc + .git + .hg + .node-version + .python-version + .go-version + .ruby-version + .lua-version + .java-version + .perl-version + .php-version + .tool-version + .shorten_folder_marker + .svn + .terraform + CVS + Cargo.toml + composer.json + go.mod + package.json + stack.yaml + ) + typeset -g POWERLEVEL9K_SHORTEN_FOLDER_MARKER="(${(j:|:)anchor_files})" + # If set to "first" ("last"), remove everything before the first (last) subdirectory that contains + # files matching $POWERLEVEL9K_SHORTEN_FOLDER_MARKER. For example, when the current directory is + # /foo/bar/git_repo/nested_git_repo/baz, prompt will display git_repo/nested_git_repo/baz (first) + # or nested_git_repo/baz (last). This assumes that git_repo and nested_git_repo contain markers + # and other directories don't. + # + # Optionally, "first" and "last" can be followed by ":" where is an integer. + # This moves the truncation point to the right (positive offset) or to the left (negative offset) + # relative to the marker. Plain "first" and "last" are equivalent to "first:0" and "last:0" + # respectively. + typeset -g POWERLEVEL9K_DIR_TRUNCATE_BEFORE_MARKER=false + # Don't shorten this many last directory segments. They are anchors. + typeset -g POWERLEVEL9K_SHORTEN_DIR_LENGTH=1 + # Shorten directory if it's longer than this even if there is space for it. The value can + # be either absolute (e.g., '80') or a percentage of terminal width (e.g, '50%'). If empty, + # directory will be shortened only when prompt doesn't fit or when other parameters demand it + # (see POWERLEVEL9K_DIR_MIN_COMMAND_COLUMNS and POWERLEVEL9K_DIR_MIN_COMMAND_COLUMNS_PCT below). + # If set to `0`, directory will always be shortened to its minimum length. + typeset -g POWERLEVEL9K_DIR_MAX_LENGTH=80 + # When `dir` segment is on the last prompt line, try to shorten it enough to leave at least this + # many columns for typing commands. + typeset -g POWERLEVEL9K_DIR_MIN_COMMAND_COLUMNS=40 + # When `dir` segment is on the last prompt line, try to shorten it enough to leave at least + # COLUMNS * POWERLEVEL9K_DIR_MIN_COMMAND_COLUMNS_PCT * 0.01 columns for typing commands. + typeset -g POWERLEVEL9K_DIR_MIN_COMMAND_COLUMNS_PCT=50 + # If set to true, embed a hyperlink into the directory. Useful for quickly + # opening a directory in the file manager simply by clicking the link. + # Can also be handy when the directory is shortened, as it allows you to see + # the full directory that was used in previous commands. + typeset -g POWERLEVEL9K_DIR_HYPERLINK=false + + # Enable special styling for non-writable and non-existent directories. See POWERLEVEL9K_LOCK_ICON + # and POWERLEVEL9K_DIR_CLASSES below. + typeset -g POWERLEVEL9K_DIR_SHOW_WRITABLE=v3 + + # The default icon shown next to non-writable and non-existent directories when + # POWERLEVEL9K_DIR_SHOW_WRITABLE is set to v3. + # typeset -g POWERLEVEL9K_LOCK_ICON='⭐' + + # POWERLEVEL9K_DIR_CLASSES allows you to specify custom icons and colors for different + # directories. It must be an array with 3 * N elements. Each triplet consists of: + # + # 1. A pattern against which the current directory ($PWD) is matched. Matching is done with + # extended_glob option enabled. + # 2. Directory class for the purpose of styling. + # 3. An empty string. + # + # Triplets are tried in order. The first triplet whose pattern matches $PWD wins. + # + # If POWERLEVEL9K_DIR_SHOW_WRITABLE is set to v3, non-writable and non-existent directories + # acquire class suffix _NOT_WRITABLE and NON_EXISTENT respectively. + # + # For example, given these settings: + # + # typeset -g POWERLEVEL9K_DIR_CLASSES=( + # '~/work(|/*)' WORK '' + # '~(|/*)' HOME '' + # '*' DEFAULT '') + # + # Whenever the current directory is ~/work or a subdirectory of ~/work, it gets styled with one + # of the following classes depending on its writability and existence: WORK, WORK_NOT_WRITABLE or + # WORK_NON_EXISTENT. + # + # Simply assigning classes to directories doesn't have any visible effects. It merely gives you an + # option to define custom colors and icons for different directory classes. + # + # # Styling for WORK. + # typeset -g POWERLEVEL9K_DIR_WORK_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_DIR_WORK_FOREGROUND=31 + # typeset -g POWERLEVEL9K_DIR_WORK_SHORTENED_FOREGROUND=103 + # typeset -g POWERLEVEL9K_DIR_WORK_ANCHOR_FOREGROUND=39 + # + # # Styling for WORK_NOT_WRITABLE. + # typeset -g POWERLEVEL9K_DIR_WORK_NOT_WRITABLE_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_DIR_WORK_NOT_WRITABLE_FOREGROUND=31 + # typeset -g POWERLEVEL9K_DIR_WORK_NOT_WRITABLE_SHORTENED_FOREGROUND=103 + # typeset -g POWERLEVEL9K_DIR_WORK_NOT_WRITABLE_ANCHOR_FOREGROUND=39 + # + # # Styling for WORK_NON_EXISTENT. + # typeset -g POWERLEVEL9K_DIR_WORK_NON_EXISTENT_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_DIR_WORK_NON_EXISTENT_FOREGROUND=31 + # typeset -g POWERLEVEL9K_DIR_WORK_NON_EXISTENT_SHORTENED_FOREGROUND=103 + # typeset -g POWERLEVEL9K_DIR_WORK_NON_EXISTENT_ANCHOR_FOREGROUND=39 + # + # If a styling parameter isn't explicitly defined for some class, it falls back to the classless + # parameter. For example, if POWERLEVEL9K_DIR_WORK_NOT_WRITABLE_FOREGROUND is not set, it falls + # back to POWERLEVEL9K_DIR_FOREGROUND. + # + typeset -g POWERLEVEL9K_DIR_CLASSES=() + + # Custom prefix. + # typeset -g POWERLEVEL9K_DIR_PREFIX='%fin ' + + #####################################[ vcs: git status ]###################################### + # Branch icon. Set this parameter to '\UE0A0 ' for the popular Powerline branch icon. + typeset -g POWERLEVEL9K_VCS_BRANCH_ICON= + + # Untracked files icon. It's really a question mark, your font isn't broken. + # Change the value of this parameter to show a different icon. + typeset -g POWERLEVEL9K_VCS_UNTRACKED_ICON='?' + + # Formatter for Git status. + # + # Example output: master wip <42>42 *42 merge ~42 +42 !42 ?42. + # + # You can edit the function to customize how Git status looks. + # + # VCS_STATUS_* parameters are set by gitstatus plugin. See reference: + # https://github.com/romkatv/gitstatus/blob/master/gitstatus.plugin.zsh. + function my_git_formatter() { + emulate -L zsh + + if [[ -n $P9K_CONTENT ]]; then + # If P9K_CONTENT is not empty, use it. It's either "loading" or from vcs_info (not from + # gitstatus plugin). VCS_STATUS_* parameters are not available in this case. + typeset -g my_git_format=$P9K_CONTENT + return + fi + + if (( $1 )); then + # Styling for up-to-date Git status. + local meta='%f' # default foreground + local clean='%76F' # green foreground + local modified='%178F' # yellow foreground + local untracked='%39F' # blue foreground + local conflicted='%196F' # red foreground + else + # Styling for incomplete and stale Git status. + local meta='%244F' # grey foreground + local clean='%244F' # grey foreground + local modified='%244F' # grey foreground + local untracked='%244F' # grey foreground + local conflicted='%244F' # grey foreground + fi + + local res + + if [[ -n $VCS_STATUS_LOCAL_BRANCH ]]; then + local branch=${(V)VCS_STATUS_LOCAL_BRANCH} + # If local branch name is at most 32 characters long, show it in full. + # Otherwise show the first 12 .. the last 12. + # Tip: To always show local branch name in full without truncation, delete the next line. + (( $#branch > 32 )) && branch[13,-13]=".." # <-- this line + res+="${clean}${(g::)POWERLEVEL9K_VCS_BRANCH_ICON}${branch//\%/%%}" + fi + + if [[ -n $VCS_STATUS_TAG + # Show tag only if not on a branch. + # Tip: To always show tag, delete the next line. + && -z $VCS_STATUS_LOCAL_BRANCH # <-- this line + ]]; then + local tag=${(V)VCS_STATUS_TAG} + # If tag name is at most 32 characters long, show it in full. + # Otherwise show the first 12 .. the last 12. + # Tip: To always show tag name in full without truncation, delete the next line. + (( $#tag > 32 )) && tag[13,-13]=".." # <-- this line + res+="${meta}#${clean}${tag//\%/%%}" + fi + + # Display the current Git commit if there is no branch and no tag. + # Tip: To always display the current Git commit, delete the next line. + [[ -z $VCS_STATUS_LOCAL_BRANCH && -z $VCS_STATUS_TAG ]] && # <-- this line + res+="${meta}@${clean}${VCS_STATUS_COMMIT[1,8]}" + + # Show tracking branch name if it differs from local branch. + if [[ -n ${VCS_STATUS_REMOTE_BRANCH:#$VCS_STATUS_LOCAL_BRANCH} ]]; then + res+="${meta}:${clean}${(V)VCS_STATUS_REMOTE_BRANCH//\%/%%}" + fi + + # Display "wip" if the latest commit's summary contains "wip" or "WIP". + if [[ $VCS_STATUS_COMMIT_SUMMARY == (|*[^[:alnum:]])(wip|WIP)(|[^[:alnum:]]*) ]]; then + res+=" ${modified}wip" + fi + + # <42 if behind the remote. + (( VCS_STATUS_COMMITS_BEHIND )) && res+=" ${clean}<${VCS_STATUS_COMMITS_BEHIND}" + # >42 if ahead of the remote; no leading space if also behind the remote: <42>42. + (( VCS_STATUS_COMMITS_AHEAD && !VCS_STATUS_COMMITS_BEHIND )) && res+=" " + (( VCS_STATUS_COMMITS_AHEAD )) && res+="${clean}>${VCS_STATUS_COMMITS_AHEAD}" + # <-42 if behind the push remote. + (( VCS_STATUS_PUSH_COMMITS_BEHIND )) && res+=" ${clean}<-${VCS_STATUS_PUSH_COMMITS_BEHIND}" + (( VCS_STATUS_PUSH_COMMITS_AHEAD && !VCS_STATUS_PUSH_COMMITS_BEHIND )) && res+=" " + # ->42 if ahead of the push remote; no leading space if also behind: <-42->42. + (( VCS_STATUS_PUSH_COMMITS_AHEAD )) && res+="${clean}->${VCS_STATUS_PUSH_COMMITS_AHEAD}" + # *42 if have stashes. + (( VCS_STATUS_STASHES )) && res+=" ${clean}*${VCS_STATUS_STASHES}" + # 'merge' if the repo is in an unusual state. + [[ -n $VCS_STATUS_ACTION ]] && res+=" ${conflicted}${VCS_STATUS_ACTION}" + # ~42 if have merge conflicts. + (( VCS_STATUS_NUM_CONFLICTED )) && res+=" ${conflicted}~${VCS_STATUS_NUM_CONFLICTED}" + # +42 if have staged changes. + (( VCS_STATUS_NUM_STAGED )) && res+=" ${modified}+${VCS_STATUS_NUM_STAGED}" + # !42 if have unstaged changes. + (( VCS_STATUS_NUM_UNSTAGED )) && res+=" ${modified}!${VCS_STATUS_NUM_UNSTAGED}" + # ?42 if have untracked files. It's really a question mark, your font isn't broken. + # See POWERLEVEL9K_VCS_UNTRACKED_ICON above if you want to use a different icon. + # Remove the next line if you don't want to see untracked files at all. + (( VCS_STATUS_NUM_UNTRACKED )) && res+=" ${untracked}${(g::)POWERLEVEL9K_VCS_UNTRACKED_ICON}${VCS_STATUS_NUM_UNTRACKED}" + # "-" if the number of unstaged files is unknown. This can happen due to + # POWERLEVEL9K_VCS_MAX_INDEX_SIZE_DIRTY (see below) being set to a non-negative number lower + # than the number of files in the Git index, or due to bash.showDirtyState being set to false + # in the repository config. The number of staged and untracked files may also be unknown + # in this case. + (( VCS_STATUS_HAS_UNSTAGED == -1 )) && res+=" ${modified}-" + + typeset -g my_git_format=$res + } + functions -M my_git_formatter 2>/dev/null + + # Don't count the number of unstaged, untracked and conflicted files in Git repositories with + # more than this many files in the index. Negative value means infinity. + # + # If you are working in Git repositories with tens of millions of files and seeing performance + # sagging, try setting POWERLEVEL9K_VCS_MAX_INDEX_SIZE_DIRTY to a number lower than the output + # of `git ls-files | wc -l`. Alternatively, add `bash.showDirtyState = false` to the repository's + # config: `git config bash.showDirtyState false`. + typeset -g POWERLEVEL9K_VCS_MAX_INDEX_SIZE_DIRTY=-1 + + # Don't show Git status in prompt for repositories whose workdir matches this pattern. + # For example, if set to '~', the Git repository at $HOME/.git will be ignored. + # Multiple patterns can be combined with '|': '~(|/foo)|/bar/baz/*'. + typeset -g POWERLEVEL9K_VCS_DISABLED_WORKDIR_PATTERN='~' + + # Disable the default Git status formatting. + typeset -g POWERLEVEL9K_VCS_DISABLE_GITSTATUS_FORMATTING=true + # Install our own Git status formatter. + typeset -g POWERLEVEL9K_VCS_CONTENT_EXPANSION='${$((my_git_formatter(1)))+${my_git_format}}' + typeset -g POWERLEVEL9K_VCS_LOADING_CONTENT_EXPANSION='${$((my_git_formatter(0)))+${my_git_format}}' + # Enable counters for staged, unstaged, etc. + typeset -g POWERLEVEL9K_VCS_{STAGED,UNSTAGED,UNTRACKED,CONFLICTED,COMMITS_AHEAD,COMMITS_BEHIND}_MAX_NUM=-1 + + # Icon color. + typeset -g POWERLEVEL9K_VCS_VISUAL_IDENTIFIER_COLOR=76 + typeset -g POWERLEVEL9K_VCS_LOADING_VISUAL_IDENTIFIER_COLOR=244 + # Custom icon. + typeset -g POWERLEVEL9K_VCS_VISUAL_IDENTIFIER_EXPANSION= + # Custom prefix. + # typeset -g POWERLEVEL9K_VCS_PREFIX='%fon ' + + # Show status of repositories of these types. You can add svn and/or hg if you are + # using them. If you do, your prompt may become slow even when your current directory + # isn't in an svn or hg repository. + typeset -g POWERLEVEL9K_VCS_BACKENDS=(git) + + # These settings are used for repositories other than Git or when gitstatusd fails and + # Powerlevel10k has to fall back to using vcs_info. + typeset -g POWERLEVEL9K_VCS_CLEAN_FOREGROUND=76 + typeset -g POWERLEVEL9K_VCS_UNTRACKED_FOREGROUND=76 + typeset -g POWERLEVEL9K_VCS_MODIFIED_FOREGROUND=178 + + ##########################[ status: exit code of the last command ]########################### + # Enable OK_PIPE, ERROR_PIPE and ERROR_SIGNAL status states to allow us to enable, disable and + # style them independently from the regular OK and ERROR state. + typeset -g POWERLEVEL9K_STATUS_EXTENDED_STATES=true + + # Status on success. No content, just an icon. No need to show it if prompt_char is enabled as + # it will signify success by turning green. + typeset -g POWERLEVEL9K_STATUS_OK=false + typeset -g POWERLEVEL9K_STATUS_OK_FOREGROUND=70 + typeset -g POWERLEVEL9K_STATUS_OK_VISUAL_IDENTIFIER_EXPANSION='ok' + + # Status when some part of a pipe command fails but the overall exit status is zero. It may look + # like this: 1|0. + typeset -g POWERLEVEL9K_STATUS_OK_PIPE=true + typeset -g POWERLEVEL9K_STATUS_OK_PIPE_FOREGROUND=70 + typeset -g POWERLEVEL9K_STATUS_OK_PIPE_VISUAL_IDENTIFIER_EXPANSION='ok' + + # Status when it's just an error code (e.g., '1'). No need to show it if prompt_char is enabled as + # it will signify error by turning red. + typeset -g POWERLEVEL9K_STATUS_ERROR=false + typeset -g POWERLEVEL9K_STATUS_ERROR_FOREGROUND=160 + typeset -g POWERLEVEL9K_STATUS_ERROR_VISUAL_IDENTIFIER_EXPANSION='err' + + # Status when the last command was terminated by a signal. + typeset -g POWERLEVEL9K_STATUS_ERROR_SIGNAL=true + typeset -g POWERLEVEL9K_STATUS_ERROR_SIGNAL_FOREGROUND=160 + # Use terse signal names: "INT" instead of "SIGINT(2)". + typeset -g POWERLEVEL9K_STATUS_VERBOSE_SIGNAME=false + typeset -g POWERLEVEL9K_STATUS_ERROR_SIGNAL_VISUAL_IDENTIFIER_EXPANSION= + + # Status when some part of a pipe command fails and the overall exit status is also non-zero. + # It may look like this: 1|0. + typeset -g POWERLEVEL9K_STATUS_ERROR_PIPE=true + typeset -g POWERLEVEL9K_STATUS_ERROR_PIPE_FOREGROUND=160 + typeset -g POWERLEVEL9K_STATUS_ERROR_PIPE_VISUAL_IDENTIFIER_EXPANSION='err' + + ###################[ command_execution_time: duration of the last command ]################### + # Show duration of the last command if takes at least this many seconds. + typeset -g POWERLEVEL9K_COMMAND_EXECUTION_TIME_THRESHOLD=3 + # Show this many fractional digits. Zero means round to seconds. + typeset -g POWERLEVEL9K_COMMAND_EXECUTION_TIME_PRECISION=0 + # Execution time color. + typeset -g POWERLEVEL9K_COMMAND_EXECUTION_TIME_FOREGROUND=101 + # Duration format: 1d 2h 3m 4s. + typeset -g POWERLEVEL9K_COMMAND_EXECUTION_TIME_FORMAT='d h m s' + # Custom icon. + typeset -g POWERLEVEL9K_COMMAND_EXECUTION_TIME_VISUAL_IDENTIFIER_EXPANSION= + # Custom prefix. + # typeset -g POWERLEVEL9K_COMMAND_EXECUTION_TIME_PREFIX='%ftook ' + + #######################[ background_jobs: presence of background jobs ]####################### + # Don't show the number of background jobs. + typeset -g POWERLEVEL9K_BACKGROUND_JOBS_VERBOSE=false + # Background jobs color. + typeset -g POWERLEVEL9K_BACKGROUND_JOBS_FOREGROUND=70 + # Custom icon. + # typeset -g POWERLEVEL9K_BACKGROUND_JOBS_VISUAL_IDENTIFIER_EXPANSION='⭐' + + #######################[ direnv: direnv status (https://direnv.net/) ]######################## + # Direnv color. + typeset -g POWERLEVEL9K_DIRENV_FOREGROUND=178 + # Custom icon. + # typeset -g POWERLEVEL9K_DIRENV_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ###############[ asdf: asdf version manager (https://github.com/asdf-vm/asdf) ]############### + # Default asdf color. Only used to display tools for which there is no color override (see below). + # Tip: Override this parameter for ${TOOL} with POWERLEVEL9K_ASDF_${TOOL}_FOREGROUND. + typeset -g POWERLEVEL9K_ASDF_FOREGROUND=66 + + # There are four parameters that can be used to hide asdf tools. Each parameter describes + # conditions under which a tool gets hidden. Parameters can hide tools but not unhide them. If at + # least one parameter decides to hide a tool, that tool gets hidden. If no parameter decides to + # hide a tool, it gets shown. + # + # Special note on the difference between POWERLEVEL9K_ASDF_SOURCES and + # POWERLEVEL9K_ASDF_PROMPT_ALWAYS_SHOW. Consider the effect of the following commands: + # + # asdf local python 3.8.1 + # asdf global python 3.8.1 + # + # After running both commands the current python version is 3.8.1 and its source is "local" as + # it takes precedence over "global". If POWERLEVEL9K_ASDF_PROMPT_ALWAYS_SHOW is set to false, + # it'll hide python version in this case because 3.8.1 is the same as the global version. + # POWERLEVEL9K_ASDF_SOURCES will hide python version only if the value of this parameter doesn't + # contain "local". + + # Hide tool versions that don't come from one of these sources. + # + # Available sources: + # + # - shell `asdf current` says "set by ASDF_${TOOL}_VERSION environment variable" + # - local `asdf current` says "set by /some/not/home/directory/file" + # - global `asdf current` says "set by /home/username/file" + # + # Note: If this parameter is set to (shell local global), it won't hide tools. + # Tip: Override this parameter for ${TOOL} with POWERLEVEL9K_ASDF_${TOOL}_SOURCES. + typeset -g POWERLEVEL9K_ASDF_SOURCES=(shell local global) + + # If set to false, hide tool versions that are the same as global. + # + # Note: The name of this parameter doesn't reflect its meaning at all. + # Note: If this parameter is set to true, it won't hide tools. + # Tip: Override this parameter for ${TOOL} with POWERLEVEL9K_ASDF_${TOOL}_PROMPT_ALWAYS_SHOW. + typeset -g POWERLEVEL9K_ASDF_PROMPT_ALWAYS_SHOW=false + + # If set to false, hide tool versions that are equal to "system". + # + # Note: If this parameter is set to true, it won't hide tools. + # Tip: Override this parameter for ${TOOL} with POWERLEVEL9K_ASDF_${TOOL}_SHOW_SYSTEM. + typeset -g POWERLEVEL9K_ASDF_SHOW_SYSTEM=true + + # If set to non-empty value, hide tools unless there is a file matching the specified file pattern + # in the current directory, or its parent directory, or its grandparent directory, and so on. + # + # Note: If this parameter is set to empty value, it won't hide tools. + # Note: SHOW_ON_UPGLOB isn't specific to asdf. It works with all prompt segments. + # Tip: Override this parameter for ${TOOL} with POWERLEVEL9K_ASDF_${TOOL}_SHOW_ON_UPGLOB. + # + # Example: Hide nodejs version when there is no package.json and no *.js files in the current + # directory, in `..`, in `../..` and so on. + # + # typeset -g POWERLEVEL9K_ASDF_NODEJS_SHOW_ON_UPGLOB='*.js|package.json' + typeset -g POWERLEVEL9K_ASDF_SHOW_ON_UPGLOB= + + # Ruby version from asdf. + typeset -g POWERLEVEL9K_ASDF_RUBY_FOREGROUND=168 + # typeset -g POWERLEVEL9K_ASDF_RUBY_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_ASDF_RUBY_SHOW_ON_UPGLOB='*.foo|*.bar' + + # Python version from asdf. + typeset -g POWERLEVEL9K_ASDF_PYTHON_FOREGROUND=37 + # typeset -g POWERLEVEL9K_ASDF_PYTHON_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_ASDF_PYTHON_SHOW_ON_UPGLOB='*.foo|*.bar' + + # Go version from asdf. + typeset -g POWERLEVEL9K_ASDF_GOLANG_FOREGROUND=37 + # typeset -g POWERLEVEL9K_ASDF_GOLANG_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_ASDF_GOLANG_SHOW_ON_UPGLOB='*.foo|*.bar' + + # Node.js version from asdf. + typeset -g POWERLEVEL9K_ASDF_NODEJS_FOREGROUND=70 + # typeset -g POWERLEVEL9K_ASDF_NODEJS_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_ASDF_NODEJS_SHOW_ON_UPGLOB='*.foo|*.bar' + + # Rust version from asdf. + typeset -g POWERLEVEL9K_ASDF_RUST_FOREGROUND=37 + # typeset -g POWERLEVEL9K_ASDF_RUST_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_ASDF_RUST_SHOW_ON_UPGLOB='*.foo|*.bar' + + # .NET Core version from asdf. + typeset -g POWERLEVEL9K_ASDF_DOTNET_CORE_FOREGROUND=134 + # typeset -g POWERLEVEL9K_ASDF_DOTNET_CORE_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_ASDF_DOTNET_SHOW_ON_UPGLOB='*.foo|*.bar' + + # Flutter version from asdf. + typeset -g POWERLEVEL9K_ASDF_FLUTTER_FOREGROUND=38 + # typeset -g POWERLEVEL9K_ASDF_FLUTTER_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_ASDF_FLUTTER_SHOW_ON_UPGLOB='*.foo|*.bar' + + # Lua version from asdf. + typeset -g POWERLEVEL9K_ASDF_LUA_FOREGROUND=32 + # typeset -g POWERLEVEL9K_ASDF_LUA_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_ASDF_LUA_SHOW_ON_UPGLOB='*.foo|*.bar' + + # Java version from asdf. + typeset -g POWERLEVEL9K_ASDF_JAVA_FOREGROUND=32 + # typeset -g POWERLEVEL9K_ASDF_JAVA_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_ASDF_JAVA_SHOW_ON_UPGLOB='*.foo|*.bar' + + # Perl version from asdf. + typeset -g POWERLEVEL9K_ASDF_PERL_FOREGROUND=67 + # typeset -g POWERLEVEL9K_ASDF_PERL_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_ASDF_PERL_SHOW_ON_UPGLOB='*.foo|*.bar' + + # Erlang version from asdf. + typeset -g POWERLEVEL9K_ASDF_ERLANG_FOREGROUND=125 + # typeset -g POWERLEVEL9K_ASDF_ERLANG_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_ASDF_ERLANG_SHOW_ON_UPGLOB='*.foo|*.bar' + + # Elixir version from asdf. + typeset -g POWERLEVEL9K_ASDF_ELIXIR_FOREGROUND=129 + # typeset -g POWERLEVEL9K_ASDF_ELIXIR_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_ASDF_ELIXIR_SHOW_ON_UPGLOB='*.foo|*.bar' + + # Postgres version from asdf. + typeset -g POWERLEVEL9K_ASDF_POSTGRES_FOREGROUND=31 + # typeset -g POWERLEVEL9K_ASDF_POSTGRES_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_ASDF_POSTGRES_SHOW_ON_UPGLOB='*.foo|*.bar' + + # PHP version from asdf. + typeset -g POWERLEVEL9K_ASDF_PHP_FOREGROUND=99 + # typeset -g POWERLEVEL9K_ASDF_PHP_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_ASDF_PHP_SHOW_ON_UPGLOB='*.foo|*.bar' + + # Haskell version from asdf. + typeset -g POWERLEVEL9K_ASDF_HASKELL_FOREGROUND=172 + # typeset -g POWERLEVEL9K_ASDF_HASKELL_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_ASDF_HASKELL_SHOW_ON_UPGLOB='*.foo|*.bar' + + # Julia version from asdf. + typeset -g POWERLEVEL9K_ASDF_JULIA_FOREGROUND=70 + # typeset -g POWERLEVEL9K_ASDF_JULIA_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_ASDF_JULIA_SHOW_ON_UPGLOB='*.foo|*.bar' + + ##########[ nordvpn: nordvpn connection status, linux only (https://nordvpn.com/) ]########### + # NordVPN connection indicator color. + typeset -g POWERLEVEL9K_NORDVPN_FOREGROUND=39 + # Hide NordVPN connection indicator when not connected. + typeset -g POWERLEVEL9K_NORDVPN_{DISCONNECTED,CONNECTING,DISCONNECTING}_CONTENT_EXPANSION= + typeset -g POWERLEVEL9K_NORDVPN_{DISCONNECTED,CONNECTING,DISCONNECTING}_VISUAL_IDENTIFIER_EXPANSION= + # Custom icon. + # typeset -g POWERLEVEL9K_NORDVPN_VISUAL_IDENTIFIER_EXPANSION='⭐' + + #################[ ranger: ranger shell (https://github.com/ranger/ranger) ]################## + # Ranger shell color. + typeset -g POWERLEVEL9K_RANGER_FOREGROUND=178 + # Custom icon. + # typeset -g POWERLEVEL9K_RANGER_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ######################[ nnn: nnn shell (https://github.com/jarun/nnn) ]####################### + # Nnn shell color. + typeset -g POWERLEVEL9K_NNN_FOREGROUND=72 + # Custom icon. + # typeset -g POWERLEVEL9K_NNN_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ##################[ xplr: xplr shell (https://github.com/sayanarijit/xplr) ]################## + # xplr shell color. + typeset -g POWERLEVEL9K_XPLR_FOREGROUND=72 + # Custom icon. + # typeset -g POWERLEVEL9K_XPLR_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ###########################[ vim_shell: vim shell indicator (:sh) ]########################### + # Vim shell indicator color. + typeset -g POWERLEVEL9K_VIM_SHELL_FOREGROUND=34 + # Custom icon. + # typeset -g POWERLEVEL9K_VIM_SHELL_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ######[ midnight_commander: midnight commander shell (https://midnight-commander.org/) ]###### + # Midnight Commander shell color. + typeset -g POWERLEVEL9K_MIDNIGHT_COMMANDER_FOREGROUND=178 + # Custom icon. + # typeset -g POWERLEVEL9K_MIDNIGHT_COMMANDER_VISUAL_IDENTIFIER_EXPANSION='⭐' + + #[ nix_shell: nix shell (https://nixos.org/nixos/nix-pills/developing-with-nix-shell.html) ]## + # Nix shell color. + typeset -g POWERLEVEL9K_NIX_SHELL_FOREGROUND=74 + + # Tip: If you want to see just the icon without "pure" and "impure", uncomment the next line. + # typeset -g POWERLEVEL9K_NIX_SHELL_CONTENT_EXPANSION= + + # Custom icon. + # typeset -g POWERLEVEL9K_NIX_SHELL_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ##################################[ disk_usage: disk usage ]################################## + # Colors for different levels of disk usage. + typeset -g POWERLEVEL9K_DISK_USAGE_NORMAL_FOREGROUND=35 + typeset -g POWERLEVEL9K_DISK_USAGE_WARNING_FOREGROUND=220 + typeset -g POWERLEVEL9K_DISK_USAGE_CRITICAL_FOREGROUND=160 + # Thresholds for different levels of disk usage (percentage points). + typeset -g POWERLEVEL9K_DISK_USAGE_WARNING_LEVEL=90 + typeset -g POWERLEVEL9K_DISK_USAGE_CRITICAL_LEVEL=95 + # If set to true, hide disk usage when below $POWERLEVEL9K_DISK_USAGE_WARNING_LEVEL percent. + typeset -g POWERLEVEL9K_DISK_USAGE_ONLY_WARNING=false + # Custom icon. + # typeset -g POWERLEVEL9K_DISK_USAGE_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ######################################[ ram: free RAM ]####################################### + # RAM color. + typeset -g POWERLEVEL9K_RAM_FOREGROUND=66 + # Custom icon. + # typeset -g POWERLEVEL9K_RAM_VISUAL_IDENTIFIER_EXPANSION='⭐' + + #####################################[ swap: used swap ]###################################### + # Swap color. + typeset -g POWERLEVEL9K_SWAP_FOREGROUND=96 + # Custom icon. + # typeset -g POWERLEVEL9K_SWAP_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ######################################[ load: CPU load ]###################################### + # Show average CPU load over this many last minutes. Valid values are 1, 5 and 15. + typeset -g POWERLEVEL9K_LOAD_WHICH=5 + # Load color when load is under 50%. + typeset -g POWERLEVEL9K_LOAD_NORMAL_FOREGROUND=66 + # Load color when load is between 50% and 70%. + typeset -g POWERLEVEL9K_LOAD_WARNING_FOREGROUND=178 + # Load color when load is over 70%. + typeset -g POWERLEVEL9K_LOAD_CRITICAL_FOREGROUND=166 + # Custom icon. + # typeset -g POWERLEVEL9K_LOAD_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ################[ todo: todo items (https://github.com/todotxt/todo.txt-cli) ]################ + # Todo color. + typeset -g POWERLEVEL9K_TODO_FOREGROUND=110 + # Hide todo when the total number of tasks is zero. + typeset -g POWERLEVEL9K_TODO_HIDE_ZERO_TOTAL=true + # Hide todo when the number of tasks after filtering is zero. + typeset -g POWERLEVEL9K_TODO_HIDE_ZERO_FILTERED=false + + # Todo format. The following parameters are available within the expansion. + # + # - P9K_TODO_TOTAL_TASK_COUNT The total number of tasks. + # - P9K_TODO_FILTERED_TASK_COUNT The number of tasks after filtering. + # + # These variables correspond to the last line of the output of `todo.sh -p ls`: + # + # TODO: 24 of 42 tasks shown + # + # Here 24 is P9K_TODO_FILTERED_TASK_COUNT and 42 is P9K_TODO_TOTAL_TASK_COUNT. + # + # typeset -g POWERLEVEL9K_TODO_CONTENT_EXPANSION='$P9K_TODO_FILTERED_TASK_COUNT' + + # Custom icon. + # typeset -g POWERLEVEL9K_TODO_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ###########[ timewarrior: timewarrior tracking status (https://timewarrior.net/) ]############ + # Timewarrior color. + typeset -g POWERLEVEL9K_TIMEWARRIOR_FOREGROUND=110 + # If the tracked task is longer than 24 characters, truncate and append "..". + # Tip: To always display tasks without truncation, delete the following parameter. + # Tip: To hide task names and display just the icon when time tracking is enabled, set the + # value of the following parameter to "". + typeset -g POWERLEVEL9K_TIMEWARRIOR_CONTENT_EXPANSION='${P9K_CONTENT:0:24}${${P9K_CONTENT:24}:+..}' + + # Custom icon. + # typeset -g POWERLEVEL9K_TIMEWARRIOR_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ##############[ taskwarrior: taskwarrior task count (https://taskwarrior.org/) ]############## + # Taskwarrior color. + typeset -g POWERLEVEL9K_TASKWARRIOR_FOREGROUND=74 + + # Taskwarrior segment format. The following parameters are available within the expansion. + # + # - P9K_TASKWARRIOR_PENDING_COUNT The number of pending tasks: `task +PENDING count`. + # - P9K_TASKWARRIOR_OVERDUE_COUNT The number of overdue tasks: `task +OVERDUE count`. + # + # Zero values are represented as empty parameters. + # + # The default format: + # + # '${P9K_TASKWARRIOR_OVERDUE_COUNT:+"!$P9K_TASKWARRIOR_OVERDUE_COUNT/"}$P9K_TASKWARRIOR_PENDING_COUNT' + # + # typeset -g POWERLEVEL9K_TASKWARRIOR_CONTENT_EXPANSION='$P9K_TASKWARRIOR_PENDING_COUNT' + + # Custom icon. + # typeset -g POWERLEVEL9K_TASKWARRIOR_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ##################################[ context: user@hostname ]################################## + # Context color when running with privileges. + typeset -g POWERLEVEL9K_CONTEXT_ROOT_FOREGROUND=178 + # Context color in SSH without privileges. + typeset -g POWERLEVEL9K_CONTEXT_{REMOTE,REMOTE_SUDO}_FOREGROUND=180 + # Default context color (no privileges, no SSH). + typeset -g POWERLEVEL9K_CONTEXT_FOREGROUND=180 + + # Context format when running with privileges: bold user@hostname. + typeset -g POWERLEVEL9K_CONTEXT_ROOT_TEMPLATE='%B%n@%m' + # Context format when in SSH without privileges: user@hostname. + typeset -g POWERLEVEL9K_CONTEXT_{REMOTE,REMOTE_SUDO}_TEMPLATE='%n@%m' + # Default context format (no privileges, no SSH): user@hostname. + typeset -g POWERLEVEL9K_CONTEXT_TEMPLATE='%n@%m' + + # Don't show context unless running with privileges or in SSH. + # Tip: Remove the next line to always show context. + typeset -g POWERLEVEL9K_CONTEXT_{DEFAULT,SUDO}_{CONTENT,VISUAL_IDENTIFIER}_EXPANSION= + + # Custom icon. + # typeset -g POWERLEVEL9K_CONTEXT_VISUAL_IDENTIFIER_EXPANSION='⭐' + # Custom prefix. + # typeset -g POWERLEVEL9K_CONTEXT_PREFIX='%fwith ' + + ###[ virtualenv: python virtual environment (https://docs.python.org/3/library/venv.html) ]### + # Python virtual environment color. + typeset -g POWERLEVEL9K_VIRTUALENV_FOREGROUND=37 + # Don't show Python version next to the virtual environment name. + typeset -g POWERLEVEL9K_VIRTUALENV_SHOW_PYTHON_VERSION=false + # If set to "false", won't show virtualenv if pyenv is already shown. + # If set to "if-different", won't show virtualenv if it's the same as pyenv. + typeset -g POWERLEVEL9K_VIRTUALENV_SHOW_WITH_PYENV=false + # Separate environment name from Python version only with a space. + typeset -g POWERLEVEL9K_VIRTUALENV_{LEFT,RIGHT}_DELIMITER= + # Custom icon. + # typeset -g POWERLEVEL9K_VIRTUALENV_VISUAL_IDENTIFIER_EXPANSION='⭐' + + #####################[ anaconda: conda environment (https://conda.io/) ]###################### + # Anaconda environment color. + typeset -g POWERLEVEL9K_ANACONDA_FOREGROUND=37 + + # Anaconda segment format. The following parameters are available within the expansion. + # + # - CONDA_PREFIX Absolute path to the active Anaconda/Miniconda environment. + # - CONDA_DEFAULT_ENV Name of the active Anaconda/Miniconda environment. + # - CONDA_PROMPT_MODIFIER Configurable prompt modifier (see below). + # - P9K_ANACONDA_PYTHON_VERSION Current python version (python --version). + # + # CONDA_PROMPT_MODIFIER can be configured with the following command: + # + # conda config --set env_prompt '({default_env}) ' + # + # The last argument is a Python format string that can use the following variables: + # + # - prefix The same as CONDA_PREFIX. + # - default_env The same as CONDA_DEFAULT_ENV. + # - name The last segment of CONDA_PREFIX. + # - stacked_env Comma-separated list of names in the environment stack. The first element is + # always the same as default_env. + # + # Note: '({default_env}) ' is the default value of env_prompt. + # + # The default value of POWERLEVEL9K_ANACONDA_CONTENT_EXPANSION expands to $CONDA_PROMPT_MODIFIER + # without the surrounding parentheses, or to the last path component of CONDA_PREFIX if the former + # is empty. + typeset -g POWERLEVEL9K_ANACONDA_CONTENT_EXPANSION='${${${${CONDA_PROMPT_MODIFIER#\(}% }%\)}:-${CONDA_PREFIX:t}}' + + # Custom icon. + # typeset -g POWERLEVEL9K_ANACONDA_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ################[ pyenv: python environment (https://github.com/pyenv/pyenv) ]################ + # Pyenv color. + typeset -g POWERLEVEL9K_PYENV_FOREGROUND=37 + # Hide python version if it doesn't come from one of these sources. + typeset -g POWERLEVEL9K_PYENV_SOURCES=(shell local global) + # If set to false, hide python version if it's the same as global: + # $(pyenv version-name) == $(pyenv global). + typeset -g POWERLEVEL9K_PYENV_PROMPT_ALWAYS_SHOW=false + # If set to false, hide python version if it's equal to "system". + typeset -g POWERLEVEL9K_PYENV_SHOW_SYSTEM=true + + # Pyenv segment format. The following parameters are available within the expansion. + # + # - P9K_CONTENT Current pyenv environment (pyenv version-name). + # - P9K_PYENV_PYTHON_VERSION Current python version (python --version). + # + # The default format has the following logic: + # + # 1. Display just "$P9K_CONTENT" if it's equal to "$P9K_PYENV_PYTHON_VERSION" or + # starts with "$P9K_PYENV_PYTHON_VERSION/". + # 2. Otherwise display "$P9K_CONTENT $P9K_PYENV_PYTHON_VERSION". + typeset -g POWERLEVEL9K_PYENV_CONTENT_EXPANSION='${P9K_CONTENT}${${P9K_CONTENT:#$P9K_PYENV_PYTHON_VERSION(|/*)}:+ $P9K_PYENV_PYTHON_VERSION}' + + # Custom icon. + # typeset -g POWERLEVEL9K_PYENV_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ################[ goenv: go environment (https://github.com/syndbg/goenv) ]################ + # Goenv color. + typeset -g POWERLEVEL9K_GOENV_FOREGROUND=37 + # Hide go version if it doesn't come from one of these sources. + typeset -g POWERLEVEL9K_GOENV_SOURCES=(shell local global) + # If set to false, hide go version if it's the same as global: + # $(goenv version-name) == $(goenv global). + typeset -g POWERLEVEL9K_GOENV_PROMPT_ALWAYS_SHOW=false + # If set to false, hide go version if it's equal to "system". + typeset -g POWERLEVEL9K_GOENV_SHOW_SYSTEM=true + # Custom icon. + # typeset -g POWERLEVEL9K_GOENV_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ##########[ nodenv: node.js version from nodenv (https://github.com/nodenv/nodenv) ]########## + # Nodenv color. + typeset -g POWERLEVEL9K_NODENV_FOREGROUND=70 + # Hide node version if it doesn't come from one of these sources. + typeset -g POWERLEVEL9K_NODENV_SOURCES=(shell local global) + # If set to false, hide node version if it's the same as global: + # $(nodenv version-name) == $(nodenv global). + typeset -g POWERLEVEL9K_NODENV_PROMPT_ALWAYS_SHOW=false + # If set to false, hide node version if it's equal to "system". + typeset -g POWERLEVEL9K_NODENV_SHOW_SYSTEM=true + # Custom icon. + # typeset -g POWERLEVEL9K_NODENV_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ##############[ nvm: node.js version from nvm (https://github.com/nvm-sh/nvm) ]############### + # Nvm color. + typeset -g POWERLEVEL9K_NVM_FOREGROUND=70 + # Custom icon. + # typeset -g POWERLEVEL9K_NVM_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ############[ nodeenv: node.js environment (https://github.com/ekalinin/nodeenv) ]############ + # Nodeenv color. + typeset -g POWERLEVEL9K_NODEENV_FOREGROUND=70 + # Don't show Node version next to the environment name. + typeset -g POWERLEVEL9K_NODEENV_SHOW_NODE_VERSION=false + # Separate environment name from Node version only with a space. + typeset -g POWERLEVEL9K_NODEENV_{LEFT,RIGHT}_DELIMITER= + # Custom icon. + # typeset -g POWERLEVEL9K_NODEENV_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ##############################[ node_version: node.js version ]############################### + # Node version color. + typeset -g POWERLEVEL9K_NODE_VERSION_FOREGROUND=70 + # Show node version only when in a directory tree containing package.json. + typeset -g POWERLEVEL9K_NODE_VERSION_PROJECT_ONLY=true + # Custom icon. + # typeset -g POWERLEVEL9K_NODE_VERSION_VISUAL_IDENTIFIER_EXPANSION='⭐' + + #######################[ go_version: go version (https://golang.org) ]######################## + # Go version color. + typeset -g POWERLEVEL9K_GO_VERSION_FOREGROUND=37 + # Show go version only when in a go project subdirectory. + typeset -g POWERLEVEL9K_GO_VERSION_PROJECT_ONLY=true + # Custom icon. + # typeset -g POWERLEVEL9K_GO_VERSION_VISUAL_IDENTIFIER_EXPANSION='⭐' + + #################[ rust_version: rustc version (https://www.rust-lang.org) ]################## + # Rust version color. + typeset -g POWERLEVEL9K_RUST_VERSION_FOREGROUND=37 + # Show rust version only when in a rust project subdirectory. + typeset -g POWERLEVEL9K_RUST_VERSION_PROJECT_ONLY=true + # Custom icon. + # typeset -g POWERLEVEL9K_RUST_VERSION_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ###############[ dotnet_version: .NET version (https://dotnet.microsoft.com) ]################ + # .NET version color. + typeset -g POWERLEVEL9K_DOTNET_VERSION_FOREGROUND=134 + # Show .NET version only when in a .NET project subdirectory. + typeset -g POWERLEVEL9K_DOTNET_VERSION_PROJECT_ONLY=true + # Custom icon. + # typeset -g POWERLEVEL9K_DOTNET_VERSION_VISUAL_IDENTIFIER_EXPANSION='⭐' + + #####################[ php_version: php version (https://www.php.net/) ]###################### + # PHP version color. + typeset -g POWERLEVEL9K_PHP_VERSION_FOREGROUND=99 + # Show PHP version only when in a PHP project subdirectory. + typeset -g POWERLEVEL9K_PHP_VERSION_PROJECT_ONLY=true + # Custom icon. + # typeset -g POWERLEVEL9K_PHP_VERSION_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ##########[ laravel_version: laravel php framework version (https://laravel.com/) ]########### + # Laravel version color. + typeset -g POWERLEVEL9K_LARAVEL_VERSION_FOREGROUND=161 + # Custom icon. + # typeset -g POWERLEVEL9K_LARAVEL_VERSION_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ####################[ java_version: java version (https://www.java.com/) ]#################### + # Java version color. + typeset -g POWERLEVEL9K_JAVA_VERSION_FOREGROUND=32 + # Show java version only when in a java project subdirectory. + typeset -g POWERLEVEL9K_JAVA_VERSION_PROJECT_ONLY=true + # Show brief version. + typeset -g POWERLEVEL9K_JAVA_VERSION_FULL=false + # Custom icon. + # typeset -g POWERLEVEL9K_JAVA_VERSION_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ###[ package: name@version from package.json (https://docs.npmjs.com/files/package.json) ]#### + # Package color. + typeset -g POWERLEVEL9K_PACKAGE_FOREGROUND=117 + # Package format. The following parameters are available within the expansion. + # + # - P9K_PACKAGE_NAME The value of `name` field in package.json. + # - P9K_PACKAGE_VERSION The value of `version` field in package.json. + # + # typeset -g POWERLEVEL9K_PACKAGE_CONTENT_EXPANSION='${P9K_PACKAGE_NAME//\%/%%}@${P9K_PACKAGE_VERSION//\%/%%}' + # Custom icon. + # typeset -g POWERLEVEL9K_PACKAGE_VISUAL_IDENTIFIER_EXPANSION='⭐' + + #############[ rbenv: ruby version from rbenv (https://github.com/rbenv/rbenv) ]############## + # Rbenv color. + typeset -g POWERLEVEL9K_RBENV_FOREGROUND=168 + # Hide ruby version if it doesn't come from one of these sources. + typeset -g POWERLEVEL9K_RBENV_SOURCES=(shell local global) + # If set to false, hide ruby version if it's the same as global: + # $(rbenv version-name) == $(rbenv global). + typeset -g POWERLEVEL9K_RBENV_PROMPT_ALWAYS_SHOW=false + # If set to false, hide ruby version if it's equal to "system". + typeset -g POWERLEVEL9K_RBENV_SHOW_SYSTEM=true + # Custom icon. + # typeset -g POWERLEVEL9K_RBENV_VISUAL_IDENTIFIER_EXPANSION='⭐' + + #######################[ rvm: ruby version from rvm (https://rvm.io) ]######################## + # Rvm color. + typeset -g POWERLEVEL9K_RVM_FOREGROUND=168 + # Don't show @gemset at the end. + typeset -g POWERLEVEL9K_RVM_SHOW_GEMSET=false + # Don't show ruby- at the front. + typeset -g POWERLEVEL9K_RVM_SHOW_PREFIX=false + # Custom icon. + # typeset -g POWERLEVEL9K_RVM_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ###########[ fvm: flutter version management (https://github.com/leoafarias/fvm) ]############ + # Fvm color. + typeset -g POWERLEVEL9K_FVM_FOREGROUND=38 + # Custom icon. + # typeset -g POWERLEVEL9K_FVM_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ##########[ luaenv: lua version from luaenv (https://github.com/cehoffman/luaenv) ]########### + # Lua color. + typeset -g POWERLEVEL9K_LUAENV_FOREGROUND=32 + # Hide lua version if it doesn't come from one of these sources. + typeset -g POWERLEVEL9K_LUAENV_SOURCES=(shell local global) + # If set to false, hide lua version if it's the same as global: + # $(luaenv version-name) == $(luaenv global). + typeset -g POWERLEVEL9K_LUAENV_PROMPT_ALWAYS_SHOW=false + # If set to false, hide lua version if it's equal to "system". + typeset -g POWERLEVEL9K_LUAENV_SHOW_SYSTEM=true + # Custom icon. + # typeset -g POWERLEVEL9K_LUAENV_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ###############[ jenv: java version from jenv (https://github.com/jenv/jenv) ]################ + # Java color. + typeset -g POWERLEVEL9K_JENV_FOREGROUND=32 + # Hide java version if it doesn't come from one of these sources. + typeset -g POWERLEVEL9K_JENV_SOURCES=(shell local global) + # If set to false, hide java version if it's the same as global: + # $(jenv version-name) == $(jenv global). + typeset -g POWERLEVEL9K_JENV_PROMPT_ALWAYS_SHOW=false + # If set to false, hide java version if it's equal to "system". + typeset -g POWERLEVEL9K_JENV_SHOW_SYSTEM=true + # Custom icon. + # typeset -g POWERLEVEL9K_JENV_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ###########[ plenv: perl version from plenv (https://github.com/tokuhirom/plenv) ]############ + # Perl color. + typeset -g POWERLEVEL9K_PLENV_FOREGROUND=67 + # Hide perl version if it doesn't come from one of these sources. + typeset -g POWERLEVEL9K_PLENV_SOURCES=(shell local global) + # If set to false, hide perl version if it's the same as global: + # $(plenv version-name) == $(plenv global). + typeset -g POWERLEVEL9K_PLENV_PROMPT_ALWAYS_SHOW=false + # If set to false, hide perl version if it's equal to "system". + typeset -g POWERLEVEL9K_PLENV_SHOW_SYSTEM=true + # Custom icon. + # typeset -g POWERLEVEL9K_PLENV_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ###########[ perlbrew: perl version from perlbrew (https://github.com/gugod/App-perlbrew) ]############ + # Perlbrew color. + typeset -g POWERLEVEL9K_PERLBREW_FOREGROUND=67 + # Show perlbrew version only when in a perl project subdirectory. + typeset -g POWERLEVEL9K_PERLBREW_PROJECT_ONLY=true + # Don't show "perl-" at the front. + typeset -g POWERLEVEL9K_PERLBREW_SHOW_PREFIX=false + # Custom icon. + # typeset -g POWERLEVEL9K_PERLBREW_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ############[ phpenv: php version from phpenv (https://github.com/phpenv/phpenv) ]############ + # PHP color. + typeset -g POWERLEVEL9K_PHPENV_FOREGROUND=99 + # Hide php version if it doesn't come from one of these sources. + typeset -g POWERLEVEL9K_PHPENV_SOURCES=(shell local global) + # If set to false, hide php version if it's the same as global: + # $(phpenv version-name) == $(phpenv global). + typeset -g POWERLEVEL9K_PHPENV_PROMPT_ALWAYS_SHOW=false + # If set to false, hide php version if it's equal to "system". + typeset -g POWERLEVEL9K_PHPENV_SHOW_SYSTEM=true + # Custom icon. + # typeset -g POWERLEVEL9K_PHPENV_VISUAL_IDENTIFIER_EXPANSION='⭐' + + #######[ scalaenv: scala version from scalaenv (https://github.com/scalaenv/scalaenv) ]####### + # Scala color. + typeset -g POWERLEVEL9K_SCALAENV_FOREGROUND=160 + # Hide scala version if it doesn't come from one of these sources. + typeset -g POWERLEVEL9K_SCALAENV_SOURCES=(shell local global) + # If set to false, hide scala version if it's the same as global: + # $(scalaenv version-name) == $(scalaenv global). + typeset -g POWERLEVEL9K_SCALAENV_PROMPT_ALWAYS_SHOW=false + # If set to false, hide scala version if it's equal to "system". + typeset -g POWERLEVEL9K_SCALAENV_SHOW_SYSTEM=true + # Custom icon. + # typeset -g POWERLEVEL9K_SCALAENV_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ##########[ haskell_stack: haskell version from stack (https://haskellstack.org/) ]########### + # Haskell color. + typeset -g POWERLEVEL9K_HASKELL_STACK_FOREGROUND=172 + # Hide haskell version if it doesn't come from one of these sources. + # + # shell: version is set by STACK_YAML + # local: version is set by stack.yaml up the directory tree + # global: version is set by the implicit global project (~/.stack/global-project/stack.yaml) + typeset -g POWERLEVEL9K_HASKELL_STACK_SOURCES=(shell local) + # If set to false, hide haskell version if it's the same as in the implicit global project. + typeset -g POWERLEVEL9K_HASKELL_STACK_ALWAYS_SHOW=true + # Custom icon. + # typeset -g POWERLEVEL9K_HASKELL_STACK_VISUAL_IDENTIFIER_EXPANSION='⭐' + + #############[ kubecontext: current kubernetes context (https://kubernetes.io/) ]############# + # Show kubecontext only when the command you are typing invokes one of these tools. + # Tip: Remove the next line to always show kubecontext. + typeset -g POWERLEVEL9K_KUBECONTEXT_SHOW_ON_COMMAND='kubectl|helm|kubens|kubectx|oc|istioctl|kogito|k9s|helmfile|flux|fluxctl|stern|kubeseal|skaffold' + + # Kubernetes context classes for the purpose of using different colors, icons and expansions with + # different contexts. + # + # POWERLEVEL9K_KUBECONTEXT_CLASSES is an array with even number of elements. The first element + # in each pair defines a pattern against which the current kubernetes context gets matched. + # More specifically, it's P9K_CONTENT prior to the application of context expansion (see below) + # that gets matched. If you unset all POWERLEVEL9K_KUBECONTEXT_*CONTENT_EXPANSION parameters, + # you'll see this value in your prompt. The second element of each pair in + # POWERLEVEL9K_KUBECONTEXT_CLASSES defines the context class. Patterns are tried in order. The + # first match wins. + # + # For example, given these settings: + # + # typeset -g POWERLEVEL9K_KUBECONTEXT_CLASSES=( + # '*prod*' PROD + # '*test*' TEST + # '*' DEFAULT) + # + # If your current kubernetes context is "deathray-testing/default", its class is TEST + # because "deathray-testing/default" doesn't match the pattern '*prod*' but does match '*test*'. + # + # You can define different colors, icons and content expansions for different classes: + # + # typeset -g POWERLEVEL9K_KUBECONTEXT_TEST_FOREGROUND=28 + # typeset -g POWERLEVEL9K_KUBECONTEXT_TEST_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_KUBECONTEXT_TEST_CONTENT_EXPANSION='> ${P9K_CONTENT} <' + typeset -g POWERLEVEL9K_KUBECONTEXT_CLASSES=( + # '*prod*' PROD # These values are examples that are unlikely + # '*test*' TEST # to match your needs. Customize them as needed. + '*' DEFAULT) + typeset -g POWERLEVEL9K_KUBECONTEXT_DEFAULT_FOREGROUND=134 + # typeset -g POWERLEVEL9K_KUBECONTEXT_DEFAULT_VISUAL_IDENTIFIER_EXPANSION='⭐' + + # Use POWERLEVEL9K_KUBECONTEXT_CONTENT_EXPANSION to specify the content displayed by kubecontext + # segment. Parameter expansions are very flexible and fast, too. See reference: + # http://zsh.sourceforge.net/Doc/Release/Expansion.html#Parameter-Expansion. + # + # Within the expansion the following parameters are always available: + # + # - P9K_CONTENT The content that would've been displayed if there was no content + # expansion defined. + # - P9K_KUBECONTEXT_NAME The current context's name. Corresponds to column NAME in the + # output of `kubectl config get-contexts`. + # - P9K_KUBECONTEXT_CLUSTER The current context's cluster. Corresponds to column CLUSTER in the + # output of `kubectl config get-contexts`. + # - P9K_KUBECONTEXT_NAMESPACE The current context's namespace. Corresponds to column NAMESPACE + # in the output of `kubectl config get-contexts`. If there is no + # namespace, the parameter is set to "default". + # - P9K_KUBECONTEXT_USER The current context's user. Corresponds to column AUTHINFO in the + # output of `kubectl config get-contexts`. + # + # If the context points to Google Kubernetes Engine (GKE) or Elastic Kubernetes Service (EKS), + # the following extra parameters are available: + # + # - P9K_KUBECONTEXT_CLOUD_NAME Either "gke" or "eks". + # - P9K_KUBECONTEXT_CLOUD_ACCOUNT Account/project ID. + # - P9K_KUBECONTEXT_CLOUD_ZONE Availability zone. + # - P9K_KUBECONTEXT_CLOUD_CLUSTER Cluster. + # + # P9K_KUBECONTEXT_CLOUD_* parameters are derived from P9K_KUBECONTEXT_CLUSTER. For example, + # if P9K_KUBECONTEXT_CLUSTER is "gke_my-account_us-east1-a_my-cluster-01": + # + # - P9K_KUBECONTEXT_CLOUD_NAME=gke + # - P9K_KUBECONTEXT_CLOUD_ACCOUNT=my-account + # - P9K_KUBECONTEXT_CLOUD_ZONE=us-east1-a + # - P9K_KUBECONTEXT_CLOUD_CLUSTER=my-cluster-01 + # + # If P9K_KUBECONTEXT_CLUSTER is "arn:aws:eks:us-east-1:123456789012:cluster/my-cluster-01": + # + # - P9K_KUBECONTEXT_CLOUD_NAME=eks + # - P9K_KUBECONTEXT_CLOUD_ACCOUNT=123456789012 + # - P9K_KUBECONTEXT_CLOUD_ZONE=us-east-1 + # - P9K_KUBECONTEXT_CLOUD_CLUSTER=my-cluster-01 + typeset -g POWERLEVEL9K_KUBECONTEXT_DEFAULT_CONTENT_EXPANSION= + # Show P9K_KUBECONTEXT_CLOUD_CLUSTER if it's not empty and fall back to P9K_KUBECONTEXT_NAME. + POWERLEVEL9K_KUBECONTEXT_DEFAULT_CONTENT_EXPANSION+='${P9K_KUBECONTEXT_CLOUD_CLUSTER:-${P9K_KUBECONTEXT_NAME}}' + # Append the current context's namespace if it's not "default". + POWERLEVEL9K_KUBECONTEXT_DEFAULT_CONTENT_EXPANSION+='${${:-/$P9K_KUBECONTEXT_NAMESPACE}:#/default}' + + # Custom prefix. + # typeset -g POWERLEVEL9K_KUBECONTEXT_PREFIX='%fat ' + + ################[ terraform: terraform workspace (https://www.terraform.io) ]################# + # Don't show terraform workspace if it's literally "default". + typeset -g POWERLEVEL9K_TERRAFORM_SHOW_DEFAULT=false + # POWERLEVEL9K_TERRAFORM_CLASSES is an array with even number of elements. The first element + # in each pair defines a pattern against which the current terraform workspace gets matched. + # More specifically, it's P9K_CONTENT prior to the application of context expansion (see below) + # that gets matched. If you unset all POWERLEVEL9K_TERRAFORM_*CONTENT_EXPANSION parameters, + # you'll see this value in your prompt. The second element of each pair in + # POWERLEVEL9K_TERRAFORM_CLASSES defines the workspace class. Patterns are tried in order. The + # first match wins. + # + # For example, given these settings: + # + # typeset -g POWERLEVEL9K_TERRAFORM_CLASSES=( + # '*prod*' PROD + # '*test*' TEST + # '*' OTHER) + # + # If your current terraform workspace is "project_test", its class is TEST because "project_test" + # doesn't match the pattern '*prod*' but does match '*test*'. + # + # You can define different colors, icons and content expansions for different classes: + # + # typeset -g POWERLEVEL9K_TERRAFORM_TEST_FOREGROUND=28 + # typeset -g POWERLEVEL9K_TERRAFORM_TEST_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_TERRAFORM_TEST_CONTENT_EXPANSION='> ${P9K_CONTENT} <' + typeset -g POWERLEVEL9K_TERRAFORM_CLASSES=( + # '*prod*' PROD # These values are examples that are unlikely + # '*test*' TEST # to match your needs. Customize them as needed. + '*' OTHER) + typeset -g POWERLEVEL9K_TERRAFORM_OTHER_FOREGROUND=38 + # typeset -g POWERLEVEL9K_TERRAFORM_OTHER_VISUAL_IDENTIFIER_EXPANSION='⭐' + + #############[ terraform_version: terraform version (https://www.terraform.io) ]############## + # Terraform version color. + typeset -g POWERLEVEL9K_TERRAFORM_VERSION_FOREGROUND=38 + # Custom icon. + # typeset -g POWERLEVEL9K_TERRAFORM_VERSION_VISUAL_IDENTIFIER_EXPANSION='⭐' + + #[ aws: aws profile (https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-profiles.html) ]# + # Show aws only when the command you are typing invokes one of these tools. + # Tip: Remove the next line to always show aws. + typeset -g POWERLEVEL9K_AWS_SHOW_ON_COMMAND='aws|awless|terraform|pulumi|terragrunt' + + # POWERLEVEL9K_AWS_CLASSES is an array with even number of elements. The first element + # in each pair defines a pattern against which the current AWS profile gets matched. + # More specifically, it's P9K_CONTENT prior to the application of context expansion (see below) + # that gets matched. If you unset all POWERLEVEL9K_AWS_*CONTENT_EXPANSION parameters, + # you'll see this value in your prompt. The second element of each pair in + # POWERLEVEL9K_AWS_CLASSES defines the profile class. Patterns are tried in order. The + # first match wins. + # + # For example, given these settings: + # + # typeset -g POWERLEVEL9K_AWS_CLASSES=( + # '*prod*' PROD + # '*test*' TEST + # '*' DEFAULT) + # + # If your current AWS profile is "company_test", its class is TEST + # because "company_test" doesn't match the pattern '*prod*' but does match '*test*'. + # + # You can define different colors, icons and content expansions for different classes: + # + # typeset -g POWERLEVEL9K_AWS_TEST_FOREGROUND=28 + # typeset -g POWERLEVEL9K_AWS_TEST_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_AWS_TEST_CONTENT_EXPANSION='> ${P9K_CONTENT} <' + typeset -g POWERLEVEL9K_AWS_CLASSES=( + # '*prod*' PROD # These values are examples that are unlikely + # '*test*' TEST # to match your needs. Customize them as needed. + '*' DEFAULT) + typeset -g POWERLEVEL9K_AWS_DEFAULT_FOREGROUND=208 + # typeset -g POWERLEVEL9K_AWS_DEFAULT_VISUAL_IDENTIFIER_EXPANSION='⭐' + + # AWS segment format. The following parameters are available within the expansion. + # + # - P9K_AWS_PROFILE The name of the current AWS profile. + # - P9K_AWS_REGION The region associated with the current AWS profile. + typeset -g POWERLEVEL9K_AWS_CONTENT_EXPANSION='${P9K_AWS_PROFILE//\%/%%}${P9K_AWS_REGION:+ ${P9K_AWS_REGION//\%/%%}}' + + #[ aws_eb_env: aws elastic beanstalk environment (https://aws.amazon.com/elasticbeanstalk/) ]# + # AWS Elastic Beanstalk environment color. + typeset -g POWERLEVEL9K_AWS_EB_ENV_FOREGROUND=70 + # Custom icon. + # typeset -g POWERLEVEL9K_AWS_EB_ENV_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ##########[ azure: azure account name (https://docs.microsoft.com/en-us/cli/azure) ]########## + # Show azure only when the command you are typing invokes one of these tools. + # Tip: Remove the next line to always show azure. + typeset -g POWERLEVEL9K_AZURE_SHOW_ON_COMMAND='az|terraform|pulumi|terragrunt' + # Azure account name color. + typeset -g POWERLEVEL9K_AZURE_FOREGROUND=32 + # Custom icon. + # typeset -g POWERLEVEL9K_AZURE_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ##########[ gcloud: google cloud account and project (https://cloud.google.com/) ]########### + # Show gcloud only when the command you are typing invokes one of these tools. + # Tip: Remove the next line to always show gcloud. + typeset -g POWERLEVEL9K_GCLOUD_SHOW_ON_COMMAND='gcloud|gcs|gsutil' + # Google cloud color. + typeset -g POWERLEVEL9K_GCLOUD_FOREGROUND=32 + + # Google cloud format. Change the value of POWERLEVEL9K_GCLOUD_PARTIAL_CONTENT_EXPANSION and/or + # POWERLEVEL9K_GCLOUD_COMPLETE_CONTENT_EXPANSION if the default is too verbose or not informative + # enough. You can use the following parameters in the expansions. Each of them corresponds to the + # output of `gcloud` tool. + # + # Parameter | Source + # -------------------------|-------------------------------------------------------------------- + # P9K_GCLOUD_CONFIGURATION | gcloud config configurations list --format='value(name)' + # P9K_GCLOUD_ACCOUNT | gcloud config get-value account + # P9K_GCLOUD_PROJECT_ID | gcloud config get-value project + # P9K_GCLOUD_PROJECT_NAME | gcloud projects describe $P9K_GCLOUD_PROJECT_ID --format='value(name)' + # + # Note: ${VARIABLE//\%/%%} expands to ${VARIABLE} with all occurrences of '%' replaced with '%%'. + # + # Obtaining project name requires sending a request to Google servers. This can take a long time + # and even fail. When project name is unknown, P9K_GCLOUD_PROJECT_NAME is not set and gcloud + # prompt segment is in state PARTIAL. When project name gets known, P9K_GCLOUD_PROJECT_NAME gets + # set and gcloud prompt segment transitions to state COMPLETE. + # + # You can customize the format, icon and colors of gcloud segment separately for states PARTIAL + # and COMPLETE. You can also hide gcloud in state PARTIAL by setting + # POWERLEVEL9K_GCLOUD_PARTIAL_VISUAL_IDENTIFIER_EXPANSION and + # POWERLEVEL9K_GCLOUD_PARTIAL_CONTENT_EXPANSION to empty. + typeset -g POWERLEVEL9K_GCLOUD_PARTIAL_CONTENT_EXPANSION='${P9K_GCLOUD_PROJECT_ID//\%/%%}' + typeset -g POWERLEVEL9K_GCLOUD_COMPLETE_CONTENT_EXPANSION='${P9K_GCLOUD_PROJECT_NAME//\%/%%}' + + # Send a request to Google (by means of `gcloud projects describe ...`) to obtain project name + # this often. Negative value disables periodic polling. In this mode project name is retrieved + # only when the current configuration, account or project id changes. + typeset -g POWERLEVEL9K_GCLOUD_REFRESH_PROJECT_NAME_SECONDS=60 + + # Custom icon. + # typeset -g POWERLEVEL9K_GCLOUD_VISUAL_IDENTIFIER_EXPANSION='⭐' + + #[ google_app_cred: google application credentials (https://cloud.google.com/docs/authentication/production) ]# + # Show google_app_cred only when the command you are typing invokes one of these tools. + # Tip: Remove the next line to always show google_app_cred. + typeset -g POWERLEVEL9K_GOOGLE_APP_CRED_SHOW_ON_COMMAND='terraform|pulumi|terragrunt' + + # Google application credentials classes for the purpose of using different colors, icons and + # expansions with different credentials. + # + # POWERLEVEL9K_GOOGLE_APP_CRED_CLASSES is an array with even number of elements. The first + # element in each pair defines a pattern against which the current kubernetes context gets + # matched. More specifically, it's P9K_CONTENT prior to the application of context expansion + # (see below) that gets matched. If you unset all POWERLEVEL9K_GOOGLE_APP_CRED_*CONTENT_EXPANSION + # parameters, you'll see this value in your prompt. The second element of each pair in + # POWERLEVEL9K_GOOGLE_APP_CRED_CLASSES defines the context class. Patterns are tried in order. + # The first match wins. + # + # For example, given these settings: + # + # typeset -g POWERLEVEL9K_GOOGLE_APP_CRED_CLASSES=( + # '*:*prod*:*' PROD + # '*:*test*:*' TEST + # '*' DEFAULT) + # + # If your current Google application credentials is "service_account deathray-testing x@y.com", + # its class is TEST because it doesn't match the pattern '* *prod* *' but does match '* *test* *'. + # + # You can define different colors, icons and content expansions for different classes: + # + # typeset -g POWERLEVEL9K_GOOGLE_APP_CRED_TEST_FOREGROUND=28 + # typeset -g POWERLEVEL9K_GOOGLE_APP_CRED_TEST_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_GOOGLE_APP_CRED_TEST_CONTENT_EXPANSION='$P9K_GOOGLE_APP_CRED_PROJECT_ID' + typeset -g POWERLEVEL9K_GOOGLE_APP_CRED_CLASSES=( + # '*:*prod*:*' PROD # These values are examples that are unlikely + # '*:*test*:*' TEST # to match your needs. Customize them as needed. + '*' DEFAULT) + typeset -g POWERLEVEL9K_GOOGLE_APP_CRED_DEFAULT_FOREGROUND=32 + # typeset -g POWERLEVEL9K_GOOGLE_APP_CRED_DEFAULT_VISUAL_IDENTIFIER_EXPANSION='⭐' + + # Use POWERLEVEL9K_GOOGLE_APP_CRED_CONTENT_EXPANSION to specify the content displayed by + # google_app_cred segment. Parameter expansions are very flexible and fast, too. See reference: + # http://zsh.sourceforge.net/Doc/Release/Expansion.html#Parameter-Expansion. + # + # You can use the following parameters in the expansion. Each of them corresponds to one of the + # fields in the JSON file pointed to by GOOGLE_APPLICATION_CREDENTIALS. + # + # Parameter | JSON key file field + # ---------------------------------+--------------- + # P9K_GOOGLE_APP_CRED_TYPE | type + # P9K_GOOGLE_APP_CRED_PROJECT_ID | project_id + # P9K_GOOGLE_APP_CRED_CLIENT_EMAIL | client_email + # + # Note: ${VARIABLE//\%/%%} expands to ${VARIABLE} with all occurrences of '%' replaced by '%%'. + typeset -g POWERLEVEL9K_GOOGLE_APP_CRED_DEFAULT_CONTENT_EXPANSION='${P9K_GOOGLE_APP_CRED_PROJECT_ID//\%/%%}' + + ##############[ toolbox: toolbox name (https://github.com/containers/toolbox) ]############### + # Toolbox color. + typeset -g POWERLEVEL9K_TOOLBOX_FOREGROUND=178 + # Don't display the name of the toolbox if it matches fedora-toolbox-*. + typeset -g POWERLEVEL9K_TOOLBOX_CONTENT_EXPANSION='${P9K_TOOLBOX_NAME:#fedora-toolbox-*}' + # Custom icon. + # typeset -g POWERLEVEL9K_TOOLBOX_VISUAL_IDENTIFIER_EXPANSION='⭐' + # Custom prefix. + # typeset -g POWERLEVEL9K_TOOLBOX_PREFIX='%fin ' + + ###############################[ public_ip: public IP address ]############################### + # Public IP color. + typeset -g POWERLEVEL9K_PUBLIC_IP_FOREGROUND=94 + # Custom icon. + # typeset -g POWERLEVEL9K_PUBLIC_IP_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ########################[ vpn_ip: virtual private network indicator ]######################### + # VPN IP color. + typeset -g POWERLEVEL9K_VPN_IP_FOREGROUND=81 + # When on VPN, show just an icon without the IP address. + # Tip: To display the private IP address when on VPN, remove the next line. + typeset -g POWERLEVEL9K_VPN_IP_CONTENT_EXPANSION= + # Regular expression for the VPN network interface. Run `ifconfig` or `ip -4 a show` while on VPN + # to see the name of the interface. + typeset -g POWERLEVEL9K_VPN_IP_INTERFACE='(gpd|wg|(.*tun)|tailscale)[0-9]*' + # If set to true, show one segment per matching network interface. If set to false, show only + # one segment corresponding to the first matching network interface. + # Tip: If you set it to true, you'll probably want to unset POWERLEVEL9K_VPN_IP_CONTENT_EXPANSION. + typeset -g POWERLEVEL9K_VPN_IP_SHOW_ALL=false + # Custom icon. + # typeset -g POWERLEVEL9K_VPN_IP_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ###########[ ip: ip address and bandwidth usage for a specified network interface ]########### + # IP color. + typeset -g POWERLEVEL9K_IP_FOREGROUND=38 + # The following parameters are accessible within the expansion: + # + # Parameter | Meaning + # ----------------------+------------------------------------------- + # P9K_IP_IP | IP address + # P9K_IP_INTERFACE | network interface + # P9K_IP_RX_BYTES | total number of bytes received + # P9K_IP_TX_BYTES | total number of bytes sent + # P9K_IP_RX_BYTES_DELTA | number of bytes received since last prompt + # P9K_IP_TX_BYTES_DELTA | number of bytes sent since last prompt + # P9K_IP_RX_RATE | receive rate (since last prompt) + # P9K_IP_TX_RATE | send rate (since last prompt) + typeset -g POWERLEVEL9K_IP_CONTENT_EXPANSION='$P9K_IP_IP${P9K_IP_RX_RATE:+ %70F<$P9K_IP_RX_RATE}${P9K_IP_TX_RATE:+ %215F>$P9K_IP_TX_RATE}' + # Show information for the first network interface whose name matches this regular expression. + # Run `ifconfig` or `ip -4 a show` to see the names of all network interfaces. + typeset -g POWERLEVEL9K_IP_INTERFACE='[ew].*' + # Custom icon. + # typeset -g POWERLEVEL9K_IP_VISUAL_IDENTIFIER_EXPANSION='⭐' + + #########################[ proxy: system-wide http/https/ftp proxy ]########################## + # Proxy color. + typeset -g POWERLEVEL9K_PROXY_FOREGROUND=68 + # Custom icon. + # typeset -g POWERLEVEL9K_PROXY_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ################################[ battery: internal battery ]################################# + # Show battery in red when it's below this level and not connected to power supply. + typeset -g POWERLEVEL9K_BATTERY_LOW_THRESHOLD=20 + typeset -g POWERLEVEL9K_BATTERY_LOW_FOREGROUND=160 + # Show battery in green when it's charging or fully charged. + typeset -g POWERLEVEL9K_BATTERY_{CHARGING,CHARGED}_FOREGROUND=70 + # Show battery in yellow when it's discharging. + typeset -g POWERLEVEL9K_BATTERY_DISCONNECTED_FOREGROUND=178 + # Battery pictograms going from low to high level of charge. + typeset -g POWERLEVEL9K_BATTERY_STAGES=('battery') + # Don't show the remaining time to charge/discharge. + typeset -g POWERLEVEL9K_BATTERY_VERBOSE=false + + #####################################[ wifi: wifi speed ]##################################### + # WiFi color. + typeset -g POWERLEVEL9K_WIFI_FOREGROUND=68 + # Custom icon. + # typeset -g POWERLEVEL9K_WIFI_VISUAL_IDENTIFIER_EXPANSION='⭐' + + # Use different colors and icons depending on signal strength ($P9K_WIFI_BARS). + # + # # Wifi colors and icons for different signal strength levels (low to high). + # typeset -g my_wifi_fg=(68 68 68 68 68) # <-- change these values + # typeset -g my_wifi_icon=('WiFi' 'WiFi' 'WiFi' 'WiFi' 'WiFi') # <-- change these values + # + # typeset -g POWERLEVEL9K_WIFI_CONTENT_EXPANSION='%F{${my_wifi_fg[P9K_WIFI_BARS+1]}}$P9K_WIFI_LAST_TX_RATE Mbps' + # typeset -g POWERLEVEL9K_WIFI_VISUAL_IDENTIFIER_EXPANSION='%F{${my_wifi_fg[P9K_WIFI_BARS+1]}}${my_wifi_icon[P9K_WIFI_BARS+1]}' + # + # The following parameters are accessible within the expansions: + # + # Parameter | Meaning + # ----------------------+--------------- + # P9K_WIFI_SSID | service set identifier, a.k.a. network name + # P9K_WIFI_LINK_AUTH | authentication protocol such as "wpa2-psk" or "none"; empty if unknown + # P9K_WIFI_LAST_TX_RATE | wireless transmit rate in megabits per second + # P9K_WIFI_RSSI | signal strength in dBm, from -120 to 0 + # P9K_WIFI_NOISE | noise in dBm, from -120 to 0 + # P9K_WIFI_BARS | signal strength in bars, from 0 to 4 (derived from P9K_WIFI_RSSI and P9K_WIFI_NOISE) + + ####################################[ time: current time ]#################################### + # Current time color. + typeset -g POWERLEVEL9K_TIME_FOREGROUND=66 + # Format for the current time: 09:51:02. See `man 3 strftime`. + typeset -g POWERLEVEL9K_TIME_FORMAT='%D{%H:%M:%S}' + # If set to true, time will update when you hit enter. This way prompts for the past + # commands will contain the start times of their commands as opposed to the default + # behavior where they contain the end times of their preceding commands. + typeset -g POWERLEVEL9K_TIME_UPDATE_ON_COMMAND=false + # Custom icon. + typeset -g POWERLEVEL9K_TIME_VISUAL_IDENTIFIER_EXPANSION= + # Custom prefix. + # typeset -g POWERLEVEL9K_TIME_PREFIX='%fat ' + + # Example of a user-defined prompt segment. Function prompt_example will be called on every + # prompt if `example` prompt segment is added to POWERLEVEL9K_LEFT_PROMPT_ELEMENTS or + # POWERLEVEL9K_RIGHT_PROMPT_ELEMENTS. It displays an icon and orange text greeting the user. + # + # Type `p10k help segment` for documentation and a more sophisticated example. + function prompt_example() { + p10k segment -f 208 -i '*' -t 'hello, %n' + } + + # User-defined prompt segments may optionally provide an instant_prompt_* function. Its job + # is to generate the prompt segment for display in instant prompt. See + # https://github.com/romkatv/powerlevel10k/blob/master/README.md#instant-prompt. + # + # Powerlevel10k will call instant_prompt_* at the same time as the regular prompt_* function + # and will record all `p10k segment` calls it makes. When displaying instant prompt, Powerlevel10k + # will replay these calls without actually calling instant_prompt_*. It is imperative that + # instant_prompt_* always makes the same `p10k segment` calls regardless of environment. If this + # rule is not observed, the content of instant prompt will be incorrect. + # + # Usually, you should either not define instant_prompt_* or simply call prompt_* from it. If + # instant_prompt_* is not defined for a segment, the segment won't be shown in instant prompt. + function instant_prompt_example() { + # Since prompt_example always makes the same `p10k segment` calls, we can call it from + # instant_prompt_example. This will give us the same `example` prompt segment in the instant + # and regular prompts. + prompt_example + } + + # User-defined prompt segments can be customized the same way as built-in segments. + # typeset -g POWERLEVEL9K_EXAMPLE_FOREGROUND=208 + # typeset -g POWERLEVEL9K_EXAMPLE_VISUAL_IDENTIFIER_EXPANSION='⭐' + + # Transient prompt works similarly to the builtin transient_rprompt option. It trims down prompt + # when accepting a command line. Supported values: + # + # - off: Don't change prompt when accepting a command line. + # - always: Trim down prompt when accepting a command line. + # - same-dir: Trim down prompt when accepting a command line unless this is the first command + # typed after changing current working directory. + typeset -g POWERLEVEL9K_TRANSIENT_PROMPT=always + + # Instant prompt mode. + # + # - off: Disable instant prompt. Choose this if you've tried instant prompt and found + # it incompatible with your zsh configuration files. + # - quiet: Enable instant prompt and don't print warnings when detecting console output + # during zsh initialization. Choose this if you've read and understood + # https://github.com/romkatv/powerlevel10k/blob/master/README.md#instant-prompt. + # - verbose: Enable instant prompt and print a warning when detecting console output during + # zsh initialization. Choose this if you've never tried instant prompt, haven't + # seen the warning, or if you are unsure what this all means. + typeset -g POWERLEVEL9K_INSTANT_PROMPT=verbose + + # Hot reload allows you to change POWERLEVEL9K options after Powerlevel10k has been initialized. + # For example, you can type POWERLEVEL9K_BACKGROUND=red and see your prompt turn red. Hot reload + # can slow down prompt by 1-2 milliseconds, so it's better to keep it turned off unless you + # really need it. + typeset -g POWERLEVEL9K_DISABLE_HOT_RELOAD=true + + # If p10k is already loaded, reload configuration. + # This works even with POWERLEVEL9K_DISABLE_HOT_RELOAD=true. + (( ! $+functions[p10k] )) || p10k reload +} + +# Tell `p10k configure` which file it should overwrite. +typeset -g POWERLEVEL9K_CONFIG_FILE=${${(%):-%x}:a} + +(( ${#p10k_config_opts} )) && setopt ${p10k_config_opts[@]} +'builtin' 'unset' 'p10k_config_opts' diff --git a/.profile b/.profile new file mode 100644 index 0000000..d0030d7 --- /dev/null +++ b/.profile @@ -0,0 +1,46 @@ +# Executed by a login shell (e.g., bash or sh) during start + + +# Prepend a folder to $PATH if it is not already there +_prepend_to_path () { + if [ -d "$1" ] ; then + case :$PATH: in + *:$1:*) ;; + *) PATH=$1:$PATH ;; + esac + fi +} + +# Put some private bin directories on the $PATH +_prepend_to_path "$HOME/bin" +_prepend_to_path "$HOME/.local/bin" + + +# Generic environment variables +export EDITOR=vim +export HISTFILESIZE=999999 +export PAGER='less --chop-long-lines --ignore-case --LONG-PROMPT --no-init --status-column --quit-if-one-screen' +export TERM=xterm-256color +export TZ='Europe/Berlin' +export VISUAL=$EDITOR + +# Machine-specific directories +export REPOS="$HOME/repos" + + +# Configurations for various utilities + +export LESSHISTFILE="${XDG_CACHE_HOME:-$HOME/.cache}/.lesshst" + + +# Shell-specific stuff + +# zsh-specific stuff is automatically sourced from `~/.zshenv`, `~/.zprofile`, `~/.zlogin`, and `~/.zshrc` + +# Source `~/.bashrc` if we are running inside a BASH shell +if [ -n "$BASH_VERSION" ]; then + if [ -f "$HOME/.bashrc" ]; then + # `~/.bashrc` is NOT automatically sourced by bash + source "$HOME/.bashrc" + fi +fi diff --git a/.zlogout b/.zlogout new file mode 100644 index 0000000..1b3cac8 --- /dev/null +++ b/.zlogout @@ -0,0 +1,3 @@ +# Executed by zsh when a login shell exits + +source "$HOME/.config/shell/logout.sh" diff --git a/.zprofile b/.zprofile new file mode 100644 index 0000000..5d4a1e1 --- /dev/null +++ b/.zprofile @@ -0,0 +1,5 @@ +# Executed by zsh when a login shell starts + +# Mimic bash's default behavior (as an analogy) and source `~/.profile` +# (`~/.zlogin` is skipped as it comes after `~/.zshrc`) +source "$HOME/.profile" diff --git a/.zshenv b/.zshenv new file mode 100644 index 0000000..a518bad --- /dev/null +++ b/.zshenv @@ -0,0 +1,20 @@ +# This file is sourced by zsh before `~/.zprofile` and `~/.zshrc` +# (it's kind of a zsh-only `~/.profile` file) + + +# TODO: As of now, this coloring does not work when zsh-syntax-highlighting is loaded simultaniously +# Source: https://github.com/zsh-users/zsh-history-substring-search/issues/131 +export HISTORY_SUBSTRING_SEARCH_HIGHLIGHT_FOUND="fg=#ffffff,bg=#38761d,bold" +export HISTORY_SUBSTRING_SEARCH_HIGHLIGHT_NOT_FOUND="fg=#ffffff,bg=#990000,bold" + +export YSU_MESSAGE_POSITION="after" +export YSU_MODE="BESTMATCH" + +export ZSH="$HOME/.oh-my-zsh" + +export ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE="fg=#666666,bg=bold" +export ZSH_AUTOSUGGEST_STRATEGY=(history completion) + +export ZSH_COMPDUMP="${XDG_CACHE_HOME:-$HOME/.cache}/.zcompdump-$HOST-$ZSH_VERSION" + +export ZPLUG_HOME="$HOME/.zplug" diff --git a/.zshrc b/.zshrc new file mode 100644 index 0000000..0e5b910 --- /dev/null +++ b/.zshrc @@ -0,0 +1,177 @@ +# Executed by zsg when a non-login shell starts + + +# Ensure zsh is running interactively +[[ $- != *i* ]] && return + + +# Check if a command can be found on the $PATH +command_exists() { + command -v "$1" 1>/dev/null 2>&1 +} + + + +# ================== +# Base Configuration +# ================== + + +# Enable Powerlevel10k instant prompt +if [ -r "${XDG_CACHE_HOME:-$HOME/.cache}/zsh/p10k-instant-prompt-${(%):-%n}.zsh" ]; then + source "${XDG_CACHE_HOME:-$HOME/.cache}/zsh/p10k-instant-prompt-${(%):-%n}.zsh" +fi + + +# Enable colors and change prompt +autoload -Uz colors +colors + +# Enable VI mode +bindkey -v + +# If an entered command does not exist per se +# but is the name of a folder instead, go there. +setopt AUTO_CD + +# Treat "#", "~", and "^" as part of patterns for filename generation +setopt EXTENDEDGLOB +# Warn if there are no matches +setopt NOMATCH + +# Silence the shell +setopt NO_BEEP + +# Report status of background jobs immediately +setopt NOTIFY + +# Remove all "built-in" aliases +unalias -a + + + +# ======= +# History +# ======= + + +# Cannot be set in `~/.profile` due to conflict with `bash` (same env variable) +export HISTFILE="$HOME/.zsh_history" + + + +# ========================= +# Shell Utilities & Aliases +# ========================= + + +source "$HOME/.config/shell/utils.sh" +source "$HOME/.config/shell/aliases.sh" + + +# Defined here as it cannot be in `aliases.sh` due to a dependency with `~/.bashrc` +alias dotfiles='/usr/bin/git --git-dir=$HOME/.dotfiles/ --work-tree=$HOME' + + + +# =============== +# zplug & Plugins +# =============== + + +source "$ZSH/oh-my-zsh.sh" +source "$HOME/.zplug/init.zsh" # config in `~/.zshenv` + + +# Load all zsh plugins with `zplug` + +# Must use double quotes in this section +# Source: https://github.com/zplug/zplug#example + +# Make zplug manage itself like a plugin +# Source: https://github.com/zplug/zplug#let-zplug-manage-zplug +zplug "zplug/zplug", hook-build:"zplug --self-manage" + +zplug "MichaelAquilina/zsh-you-should-use" # config in `~/.zshenv` + +zplug "zsh-users/zsh-autosuggestions" # config in `~/.zshenv` +zplug "zsh-users/zsh-history-substring-search" # config in `~/.zshenv`; there are key bindings below +zplug "zsh-users/zsh-syntax-highlighting" + +zplug "plugins/command-not-found", from:oh-my-zsh +zplug "plugins/dotenv", from:oh-my-zsh +zplug "plugins/dirhistory", from:oh-my-zsh +zplug "plugins/git-escape-magic", from:oh-my-zsh +zplug "plugins/jsontools", from:oh-my-zsh +zplug "plugins/z", from:oh-my-zsh + +zplug "romkatv/powerlevel10k", as:theme, depth:1 + +zplug load + + + +# =============== +# Zsh Completions +# =============== + + +# Initialize zsh's completions +# NOTE: This is already done with `~/.oh-my-zsh.sh` above +# autoload -Uz compinit +# compinit -u -d "$ZSH_COMPDUMP" + +# Enable match highlighting and scrolling through long lists, +# and provide a different style of menu completion +zmodload zsh/complist + +# Include hidden files in tab completion +_comp_options+=(GLOB_DOTS) + +# Enable arrow-key driven interface +zstyle ':completion:*' menu select + +# Make compinit find new executables right away +zstyle ':completion:*' rehash true + +# Enable grouping and group headers +zstyle ':completion:*:descriptions' format '%B%d%b' +zstyle ':completion:*:messages' format '%d' +zstyle ':completion:*:warnings' format 'No matches for: %d' +zstyle ':completion:*' group-name '' + + + +# ============ +# Key Bindings +# ============ + +# zsh-autosuggestions plugin +bindkey "^ " autosuggest-accept + +# Enable Ctrl-R +bindkey "^R" history-incremental-search-backward + +# Use VI keys to navigate the completions in the menu +bindkey -M menuselect 'h' vi-backward-char +bindkey -M menuselect 'k' vi-up-line-or-history +bindkey -M menuselect 'l' vi-forward-char +bindkey -M menuselect 'j' vi-down-line-or-history + +# history-substring-search plugin +# Source: https://github.com/zsh-users/zsh-history-substring-search#usage +# Normal mode +bindkey "$terminfo[kcuu1]" history-substring-search-up +bindkey "$terminfo[kcud1]" history-substring-search-down +# VI mode +bindkey -M vicmd 'k' history-substring-search-up +bindkey -M vicmd 'j' history-substring-search-down + + + +# ===== +# Other +# ===== + +# Enable Powerlevel10k "full" prompt +[[ ! -f ~/.p10k.zsh ]] || source ~/.p10k.zsh From bca227ff27bb77a1dd8e27362b2ead584cdad9d9 Mon Sep 17 00:00:00 2001 From: Alexander Hess Date: Tue, 12 Jul 2022 01:38:47 +0200 Subject: [PATCH 05/27] Add installation script for the ~/.dotfiles bare repo --- .config/shell/init_dotfiles.sh | 57 ++++++++++++++++++++++++++++++++++ README.md | 22 +++++++++++++ 2 files changed, 79 insertions(+) create mode 100755 .config/shell/init_dotfiles.sh diff --git a/.config/shell/init_dotfiles.sh b/.config/shell/init_dotfiles.sh new file mode 100755 index 0000000..9cb7c40 --- /dev/null +++ b/.config/shell/init_dotfiles.sh @@ -0,0 +1,57 @@ +# This file initializes the `~/.dotfiles` bare repo +# Source it from either zsh or bash + + +# Check if a command can be found on the $PATH. +command_exists() { + command -v "$1" 1>/dev/null 2>&1 +} + + +cd $HOME + + +# This is only here for documentation purposes +alias dotfiles='/usr/bin/git --git-dir=$HOME/.dotfiles/ --work-tree=$HOME' + +# Remove a previous version of a `~/.dotfiles` bare repository +rm -rf "$HOME/.dotfiles" >/dev/null +git clone --bare git@git.webartifex.biz:alexander/dotfiles.git "$HOME/.dotfiles" + +# Backup old dotfiles +rm -rf "$HOME/.dotfiles.bak" >/dev/null +mkdir -p $HOME/.dotfiles.bak/.config/{git,shell} && \ +/usr/bin/git --git-dir=$HOME/.dotfiles/ --work-tree=$HOME checkout 2>&1 | egrep "\s+\." | awk {'print $1'} | \ +xargs -I{} mv {} "$HOME/.dotfiles.bak"/{} + +# Put new dotfiles in $HOME +/usr/bin/git --git-dir=$HOME/.dotfiles/ --work-tree=$HOME checkout --force +/usr/bin/git --git-dir=$HOME/.dotfiles/ --work-tree=$HOME config --local status.showUntrackedFiles no +/usr/bin/git --git-dir=$HOME/.dotfiles/ --work-tree=$HOME status + + +# Set up `zsh` only if it is available +# Note: on many servers I use these dotfiles, `zsh` is not installed +if command_exists zsh; then + + # Install oh-my-zsh + export ZSH="$HOME/.oh-my-zsh" + rm -rf $ZSH >/dev/null + git clone https://github.com/ohmyzsh/ohmyzsh.git $ZSH + + # Install zplug + export ZPLUG_HOME="$HOME/.zplug" + rm -rf $ZPLUG_HOME >/dev/null + git clone https://github.com/zplug/zplug $ZPLUG_HOME + + # Set up all the zplug plugins (must be run interacticely + # so that `~/.zshrc` & friends are sourced again) + zsh -i -c "zplug install" + +fi + + +echo +echo "Probably it's a good idea to restart the shell" +echo "Make sure to start bash or zsh as a login shell the next time" +echo diff --git a/README.md b/README.md index 7c57cc5..3625b50 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,25 @@ # Dotfiles This repository contains useful (config) files that I use on my machines. + + +## Initialization + +On a freshly set up machine, run: + +```bash +curl https://gitlab.webartifex.biz/alexander/dotfiles/-/raw/main/.config/shell/init_dotfiles.sh \ + > /tmp/init_dotfiles.sh \ + && source /tmp/init_dotfiles.sh \ + && rm /tmp/init_dotfiles.sh +``` + +This gives you a local copy of the latest version of this repository + (located in `~/.dotfiles`) + and initializes all the dotfiles provided here on your system. +Furthermore, `zsh` is set up with [`oh-my-zsh`](https://ohmyz.sh/) and `zplug`. + +**Note**: Log out and in again so that `bash` and `zsh` run as *login* shells. +Otherwise, `~/.profile` is probably *not* sourced. + +Don't worry: Your current dotfiles are backed up in the `~/.dotfiles.bak` folder! From b66256f83a108ee69c62a2efc74bd53e0909982c Mon Sep 17 00:00:00 2001 From: Alexander Hess Date: Tue, 12 Jul 2022 02:18:10 +0200 Subject: [PATCH 06/27] Add config for batcat, the nicer cat --- .config/bat/config | 6 ++++++ .config/shell/init_dotfiles.sh | 2 +- .profile | 2 ++ 3 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 .config/bat/config diff --git a/.config/bat/config b/.config/bat/config new file mode 100644 index 0000000..c14fa05 --- /dev/null +++ b/.config/bat/config @@ -0,0 +1,6 @@ +--theme="TwoDark" + +--style="numbers,changes,header" + +--map-syntax ".flake8:ini" +--map-syntax "poetry.lock:toml" diff --git a/.config/shell/init_dotfiles.sh b/.config/shell/init_dotfiles.sh index 9cb7c40..14dba68 100755 --- a/.config/shell/init_dotfiles.sh +++ b/.config/shell/init_dotfiles.sh @@ -20,7 +20,7 @@ git clone --bare git@git.webartifex.biz:alexander/dotfiles.git "$HOME/.dotfiles" # Backup old dotfiles rm -rf "$HOME/.dotfiles.bak" >/dev/null -mkdir -p $HOME/.dotfiles.bak/.config/{git,shell} && \ +mkdir -p $HOME/.dotfiles.bak/.config/{bat,git,shell} && \ /usr/bin/git --git-dir=$HOME/.dotfiles/ --work-tree=$HOME checkout 2>&1 | egrep "\s+\." | awk {'print $1'} | \ xargs -I{} mv {} "$HOME/.dotfiles.bak"/{} diff --git a/.profile b/.profile index d0030d7..677310a 100644 --- a/.profile +++ b/.profile @@ -30,6 +30,8 @@ export REPOS="$HOME/repos" # Configurations for various utilities +export BAT_CONFIG_PATH="$HOME/.config/bat/config" + export LESSHISTFILE="${XDG_CACHE_HOME:-$HOME/.cache}/.lesshst" From c87bed3a6a0b7c3123fd89143f3b8a309bf26ad3 Mon Sep 17 00:00:00 2001 From: Alexander Hess Date: Tue, 12 Jul 2022 02:21:19 +0200 Subject: [PATCH 07/27] Add config for flameshot --- .config/flameshot/flameshot.ini | 11 +++++++++++ .config/shell/init_dotfiles.sh | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 .config/flameshot/flameshot.ini diff --git a/.config/flameshot/flameshot.ini b/.config/flameshot/flameshot.ini new file mode 100644 index 0000000..7b33abc --- /dev/null +++ b/.config/flameshot/flameshot.ini @@ -0,0 +1,11 @@ +[General] +contrastOpacity=188 +disabledTrayIcon=true +drawColor=#ff0000 +drawThickness=3 +filenamePattern=%F_%H-%M-%S +saveAsFileExtension=png +savePath=/home/alexander/nextcloud/uploads/screenshots +showHelp=false +startupLaunch=false +uiColor=#ff3a00 diff --git a/.config/shell/init_dotfiles.sh b/.config/shell/init_dotfiles.sh index 14dba68..07804a4 100755 --- a/.config/shell/init_dotfiles.sh +++ b/.config/shell/init_dotfiles.sh @@ -20,7 +20,7 @@ git clone --bare git@git.webartifex.biz:alexander/dotfiles.git "$HOME/.dotfiles" # Backup old dotfiles rm -rf "$HOME/.dotfiles.bak" >/dev/null -mkdir -p $HOME/.dotfiles.bak/.config/{bat,git,shell} && \ +mkdir -p $HOME/.dotfiles.bak/.config/{bat,flameshot,git,shell} && \ /usr/bin/git --git-dir=$HOME/.dotfiles/ --work-tree=$HOME checkout 2>&1 | egrep "\s+\." | awk {'print $1'} | \ xargs -I{} mv {} "$HOME/.dotfiles.bak"/{} From 0a800cac88c20408743f1f718657d6fbb0578897 Mon Sep 17 00:00:00 2001 From: Alexander Hess Date: Tue, 12 Jul 2022 02:23:02 +0200 Subject: [PATCH 08/27] Disable Pop! OS's updater notification --- .config/pop-system-updater/config.ron | 1 + .config/shell/init_dotfiles.sh | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 .config/pop-system-updater/config.ron diff --git a/.config/pop-system-updater/config.ron b/.config/pop-system-updater/config.ron new file mode 100644 index 0000000..c380454 --- /dev/null +++ b/.config/pop-system-updater/config.ron @@ -0,0 +1 @@ +(enabled:false,notification_frequency:Weekly) diff --git a/.config/shell/init_dotfiles.sh b/.config/shell/init_dotfiles.sh index 07804a4..e9f752d 100755 --- a/.config/shell/init_dotfiles.sh +++ b/.config/shell/init_dotfiles.sh @@ -20,7 +20,7 @@ git clone --bare git@git.webartifex.biz:alexander/dotfiles.git "$HOME/.dotfiles" # Backup old dotfiles rm -rf "$HOME/.dotfiles.bak" >/dev/null -mkdir -p $HOME/.dotfiles.bak/.config/{bat,flameshot,git,shell} && \ +mkdir -p $HOME/.dotfiles.bak/.config/{bat,flameshot,git,pop-system-updater,shell} && \ /usr/bin/git --git-dir=$HOME/.dotfiles/ --work-tree=$HOME checkout 2>&1 | egrep "\s+\." | awk {'print $1'} | \ xargs -I{} mv {} "$HOME/.dotfiles.bak"/{} From e56e5b6ba0b4f961ce6e456abbe3c826f5310a7a Mon Sep 17 00:00:00 2001 From: Alexander Hess Date: Tue, 12 Jul 2022 02:25:52 +0200 Subject: [PATCH 09/27] Integrate Nextcloud in XDG user directories --- .config/user-dirs.dirs | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 .config/user-dirs.dirs diff --git a/.config/user-dirs.dirs b/.config/user-dirs.dirs new file mode 100644 index 0000000..0cfbaf5 --- /dev/null +++ b/.config/user-dirs.dirs @@ -0,0 +1,10 @@ +# Configure the XDG user directories to integrate Nextcloud + +XDG_DESKTOP_DIR="$HOME/desktop" +XDG_DOCUMENTS_DIR="$HOME/nextcloud" +XDG_DOWNLOAD_DIR="$HOME/downloads" +XDG_MUSIC_DIR="$HOME/nextcloud" +XDG_PICTURES_DIR="$HOME/nextcloud/photos" +XDG_PUBLICSHARE_DIR="$HOME/nextcloud/shares" +XDG_TEMPLATES_DIR="$HOME/nextcloud/templates" +XDG_VIDEOS_DIR="$HOME/nextcloud/photos" From c5cf44f72e874d0255fdd9dcde5d495b8ddba0ac Mon Sep 17 00:00:00 2001 From: Alexander Hess Date: Tue, 12 Jul 2022 02:32:31 +0200 Subject: [PATCH 10/27] Add base config for Nextcloud Some of the config keys are set by the machine automatically and are machine-specific or provide info about the Nextcloud --- .config/Nextcloud/nextcloud.cfg | 22 ++++++++++++++++++ .config/Nextcloud/sync-exclude.lst | 37 ++++++++++++++++++++++++++++++ .config/shell/init_dotfiles.sh | 2 +- 3 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 .config/Nextcloud/nextcloud.cfg create mode 100644 .config/Nextcloud/sync-exclude.lst diff --git a/.config/Nextcloud/nextcloud.cfg b/.config/Nextcloud/nextcloud.cfg new file mode 100644 index 0000000..1c6c178 --- /dev/null +++ b/.config/Nextcloud/nextcloud.cfg @@ -0,0 +1,22 @@ +[General] +confirmExternalStorage=false +crashReporter=false +monoIcons=true +newBigFolderSizeLimit=99999 +optionalServerNotifications=false +useNewBigFolderSizeLimit=false + +[Accounts] +0\Folders\1\ignoreHiddenFiles=false +0\Folders\1\localPath=/home/alexander/nextcloud/ +0\Folders\1\paused=false +0\Folders\1\targetPath=/ +0\Folders\1\version=2 +0\Folders\1\virtualFilesMode=off +0\authType=webflow +0\dav_user=alexander +0\url=https://nextcloud.webartifex.biz +0\user=@Invalid() +0\version=1 +0\webflow_user=alexander +version=2 diff --git a/.config/Nextcloud/sync-exclude.lst b/.config/Nextcloud/sync-exclude.lst new file mode 100644 index 0000000..d71323f --- /dev/null +++ b/.config/Nextcloud/sync-exclude.lst @@ -0,0 +1,37 @@ +]*~ +]~$* +].~lock.* +]~*.tmp +]*.~* +]Icon\r* +].DS_Store +].ds_store +]*.textClipping +]._* +]Thumbs.db +]photothumb.db +]System Volume Information +].*.sw? +].*.*sw? +].TemporaryItems +].Trashes +].DocumentRevisions-V100 +].Trash-* +].fseventd +].apdisk +].Spotlight-V100 +].directory +]*.part +]*.filepart +]*.crdownload +]*.kate-swp +]*.gnucash.tmp-* +].synkron.* +].sync.ffs_db +].symform +].symform-store +].fuse_hidden* +]*.unison +].nfs* +]My Saved Places. +]\#*# diff --git a/.config/shell/init_dotfiles.sh b/.config/shell/init_dotfiles.sh index e9f752d..e42fd97 100755 --- a/.config/shell/init_dotfiles.sh +++ b/.config/shell/init_dotfiles.sh @@ -20,7 +20,7 @@ git clone --bare git@git.webartifex.biz:alexander/dotfiles.git "$HOME/.dotfiles" # Backup old dotfiles rm -rf "$HOME/.dotfiles.bak" >/dev/null -mkdir -p $HOME/.dotfiles.bak/.config/{bat,flameshot,git,pop-system-updater,shell} && \ +mkdir -p $HOME/.dotfiles.bak/.config/{bat,flameshot,git,Nextcloud,pop-system-updater,shell} && \ /usr/bin/git --git-dir=$HOME/.dotfiles/ --work-tree=$HOME checkout 2>&1 | egrep "\s+\." | awk {'print $1'} | \ xargs -I{} mv {} "$HOME/.dotfiles.bak"/{} From c1393d0756d6a180814c888733fe4250886af88c Mon Sep 17 00:00:00 2001 From: Alexander Hess Date: Tue, 12 Jul 2022 02:37:04 +0200 Subject: [PATCH 11/27] Add config for psql --- .config/shell/init_dotfiles.sh | 2 +- .profile | 2 ++ .psqlrc | 30 ++++++++++++++++++++++++++++++ 3 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 .psqlrc diff --git a/.config/shell/init_dotfiles.sh b/.config/shell/init_dotfiles.sh index e42fd97..073f108 100755 --- a/.config/shell/init_dotfiles.sh +++ b/.config/shell/init_dotfiles.sh @@ -20,7 +20,7 @@ git clone --bare git@git.webartifex.biz:alexander/dotfiles.git "$HOME/.dotfiles" # Backup old dotfiles rm -rf "$HOME/.dotfiles.bak" >/dev/null -mkdir -p $HOME/.dotfiles.bak/.config/{bat,flameshot,git,Nextcloud,pop-system-updater,shell} && \ +mkdir -p $HOME/.dotfiles.bak/.config/{bat,flameshot,git,Nextcloud,pop-system-updater,psql,shell} && \ /usr/bin/git --git-dir=$HOME/.dotfiles/ --work-tree=$HOME checkout 2>&1 | egrep "\s+\." | awk {'print $1'} | \ xargs -I{} mv {} "$HOME/.dotfiles.bak"/{} diff --git a/.profile b/.profile index 677310a..2681a9a 100644 --- a/.profile +++ b/.profile @@ -34,6 +34,8 @@ export BAT_CONFIG_PATH="$HOME/.config/bat/config" export LESSHISTFILE="${XDG_CACHE_HOME:-$HOME/.cache}/.lesshst" +export PSQLRC="$HOME/.psqlrc" + # Shell-specific stuff diff --git a/.psqlrc b/.psqlrc new file mode 100644 index 0000000..af0d26d --- /dev/null +++ b/.psqlrc @@ -0,0 +1,30 @@ +-- `psql` executes the commands in this `~/.psqlrc` creating output +-- (this flag hides that and is unset again at the bottom) +\set QUIET 1 + +-- Show verbose error messages +\set VERBOSITY verbose + +-- Use normal "table" format by default and "expanded table" with lots of columns +\x auto + +-- By default, NULLs show up as empty spaces, which looks like empty strings +\pset null 'NULL' + +-- Ignore errors in interactive sessions but not when executing scripts +\set ON_ERROR_ROLLBACK interactive + +-- Upper case SQL keywords +\set COMP_KEYWORD_CASE upper + +-- Use the best text editor in the world +\set EDITOR vi + +-- Don't store the same SQL statement repeatedly +\set HISTCONTROL ignoredups + +-- Make all queries display query times +\timing + +-- Unset the flag set at the top of this file +\unset QUIET From 5c3a91465880c7c069555c29ae98e67d009149be Mon Sep 17 00:00:00 2001 From: Alexander Hess Date: Tue, 12 Jul 2022 14:55:49 +0200 Subject: [PATCH 12/27] Add config for vim --- .config/shell/init_dotfiles.sh | 1 + .vim/after/ftplugin/python.vim | 65 +++++++ .vim/backup/.gitkeep | 0 .vim/swap/.gitkeep | 0 .vim/undo/.gitkeep | 0 .vim/vimrc | 303 +++++++++++++++++++++++++++++++++ 6 files changed, 369 insertions(+) create mode 100644 .vim/after/ftplugin/python.vim create mode 100644 .vim/backup/.gitkeep create mode 100644 .vim/swap/.gitkeep create mode 100644 .vim/undo/.gitkeep create mode 100644 .vim/vimrc diff --git a/.config/shell/init_dotfiles.sh b/.config/shell/init_dotfiles.sh index 073f108..c7a1749 100755 --- a/.config/shell/init_dotfiles.sh +++ b/.config/shell/init_dotfiles.sh @@ -21,6 +21,7 @@ git clone --bare git@git.webartifex.biz:alexander/dotfiles.git "$HOME/.dotfiles" # Backup old dotfiles rm -rf "$HOME/.dotfiles.bak" >/dev/null mkdir -p $HOME/.dotfiles.bak/.config/{bat,flameshot,git,Nextcloud,pop-system-updater,psql,shell} && \ +mkdir -p $HOME/.dotfiles.bak/.vim/{after/ftplugin,backup,swap,undo} && \ /usr/bin/git --git-dir=$HOME/.dotfiles/ --work-tree=$HOME checkout 2>&1 | egrep "\s+\." | awk {'print $1'} | \ xargs -I{} mv {} "$HOME/.dotfiles.bak"/{} diff --git a/.vim/after/ftplugin/python.vim b/.vim/after/ftplugin/python.vim new file mode 100644 index 0000000..0bf9971 --- /dev/null +++ b/.vim/after/ftplugin/python.vim @@ -0,0 +1,65 @@ +" Set the search path to the folder of the current file and its sub-folders +setlocal path=.,** +" Exclude Python's compiled files from searches +setlocal wildignore=*/__pycache__/*,*.pyc + + +" TODO: This does not work, maybe because we spell out imports +" as project-local imports (e.g. from lalib.fields import base)? +" Include *.py files imported as modules when searching. +" Source: https://www.youtube.com/watch?v=Gs1VDYnS-Ac +set include=^\\s*\\(from\\\|import\\)\\s*\\zs\\(\\S\\+\\s\\{-}\\)*\\ze\\($\\\|\ as\\) +" 1) import foo.bar -> foo/bar.py +" 2) from foo import bar as var -> foo/bar.py or foo.py +function! PyInclude(fname) + let parts = split(a:fname, ' import ') " 1) [foo.bar] or 2) [foo, bar] + let left = parts[0] " 1) foo.bar or 2) foo + if len(parts) > 1 + let right = parts[1] " only 2) bar + let joined = join([left, right], '.') + let fpath = substitute(joined, '\.', '/', 'g') . '.py' + let found = glob(fpath, 1) + if len(found) + return found + endif + endif + return substitute(left, '\.', '/', 'g') . '.py' +endfunction +setlocal includeexpr=PyInclude(v:fname) +setlocal define=^\\s*\\<\\(def\\|class\\)\\> + + +" Number of spaces used for each step of auto-indent +set shiftwidth=4 + +" Number of spaces a counts for in the file +set tabstop=4 + +" Number of spaces a counts for in editing mode +set softtabstop=4 + +" Change s into spaces +set expandtab + +" Copy indent from previous line when starting a new line +set autoindent + +" Use indent according to the syntax of the open file +set smartindent + +" Auto-wrap lines after 88 characters, which is PEP8's limit plus 10%, +" a more relaxed boundary which occasionally may be used +set textwidth=88 + + +" Make column 80 red to indicate PEP8's maximum allowed line length +set colorcolumn=80 + +" Additionally, give every character beyond 80 columns a red background +highlight ColorColumn ctermbg=DarkRed +call matchadd('ColorColumn', '\%80v', 100) +match ErrorMsg '\%>80v.\+' + + +" Show line numbers by default for .py files +let g:show_numbers=1 diff --git a/.vim/backup/.gitkeep b/.vim/backup/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/.vim/swap/.gitkeep b/.vim/swap/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/.vim/undo/.gitkeep b/.vim/undo/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/.vim/vimrc b/.vim/vimrc new file mode 100644 index 0000000..1363efd --- /dev/null +++ b/.vim/vimrc @@ -0,0 +1,303 @@ +" Good sources on vimrc files: +" - https://www.youtube.com/watch?v=Gs1VDYnS-Ac + + +" Use VIM improved mode +set nocompatible + +" Set environment variables for convenient usage +let $RC="$HOME/.vim/vimrc" +let $RTP=split(&runtimepath, ',')[0] + +" Disable VIM's startup message +set shortmess+=I + +" Number of remembered undo steps +set undolevels=1000 + + +" Detect the file's type and load the corresponding plugin and indent files +filetype plugin indent on + +" Enable syntax highlighting +syntax on + + +" Allow backspace to delete characters in insert mode +" beyond the start of the insertion and end of lines +set backspace=start,eol,indent + + +" Hide buffers instead of closing them, wich means we can have +" unwritten changes to a file and open a new one with :e, +" without having to write the changes first +set hidden + + +" Set to the folder of the current file and its sub-folders +" (this may need to be adapted for large project folders) +set path=.,** + + +" Store all vim-related working files in ~/.vim +set viminfo+=n~/.vim/viminfo +" Use dedicated folders to store temporary backup, swap, and undo files +" (the // means that VIM adapts names automatically to avoid duplicates) +set backupdir=~/.vim/backup// +set directory=~/.vim/swap// +set undodir=~/.vim/undo// + +" To disable any of the temporary files, uncomment one of the following +" set nobackup +" set nowritebackup +" set noswapfile +" set noundofile + + +" Show the filename in the terminal window's title bar +set title + + +" Do not wrap lines when showing text +set nowrap + +" This avoids a problem of loosing data upon insertion in old VIMs +set wrapmargin=0 + + +" Show spelling mistakes (in English) in italics +set spelllang=en_us,de_de +set spell +hi clear SpellBad +hi clear SpellCap +hi clear SpellRare +hi clear SpellLocal +hi SpellBad cterm=italic + + +" Show whitespace characters +set listchars=tab:»»,extends:›,precedes:‹,nbsp:·,trail:· +set list + + +" Highlight matching brackets +set showmatch +set matchpairs+=<:> + + +" Always show the status bar at the bottom +set laststatus=2 + +" Show current position in status bar +set ruler +set rulerformat=%=%l/%L\ %c\ (%P) + +" Show commands in status bar +set showcmd + +" If in non-normal mode, show the mode in the status bar +set showmode + +" Show a dialog to save changes instead of an error message +set confirm + +" Auto-clear messages from the status bar +autocmd CursorHold * :echo + + +" Better copy and paste behavior +set pastetoggle= +set clipboard=unnamed + + +" Make : and ; synonyms +nnoremap ; : + + +" Use \ and as the keys and lower time to enter key sequences +let mapleader='\' +set timeoutlen=750 +" Make the in visual mode as well +nmap \ +vmap \ + + +" Q normally goes into Ex mode +nmap Q + + +" Get sudo rights when writing a buffer with w!! +cnoremap w!! w !sudo tee % >/dev/null + + +" Enable the mouse for selections, including a toggle for this mode +set mouse=a +let g:mouse_enabled=1 +function ToggleMouse() + if g:mouse_enabled == 1 + echo "Mouse OFF" + set mouse= + let g:mouse_enabled=0 + else + echo "Mouse ON" + set mouse=a + let g:mouse_enabled=1 + endif +endfunction +noremap m :call ToggleMouse() + + +" Enable toggling between +" - showing and hiding line numbers (l) +" - absolute and relative numbers (a) in normal mode +" (default: relative line numbering) +let g:show_numbers=0 +let g:show_absolute_numbers=0 +function! ShowLineNumbers() + if g:show_numbers == 1 + set number + if g:show_absolute_numbers + set norelativenumber + else + set relativenumber + endif + else + set nonumber + set norelativenumber + endif +endfunction +function! ToggleLineNumbers() + if g:show_numbers == 1 + let g:show_numbers=0 + else + let g:show_numbers=1 + endif + call ShowLineNumbers() +endfunction +function! ToggleAbsoluteAndRelativeLineNumbers() + if g:show_absolute_numbers == 1 + let g:show_absolute_numbers=0 + else + let g:show_absolute_numbers=1 + endif + call ShowLineNumbers() +endfunction +" Auto-switch between absolute and relative numbering when switching modes +" (insert mode always shows absolute numbers when numbers are shown) +augroup numbertoggle + autocmd! + autocmd BufEnter,FocusGained,InsertLeave * call ShowLineNumbers() + autocmd BufLeave,FocusLost,InsertEnter * if g:show_numbers == 1 | set number | set norelativenumber | endif +augroup END +" Key bindings +nnoremap l :call ToggleLineNumbers() +nnoremap a :call ToggleAbsoluteAndRelativeLineNumbers() + + +" Show all possible matches above command-line when tab completing +set wildmenu +set wildmode=longest:full,full + + +" Highlight search results +set hlsearch + +" Shortcut to remove current highlighting +nnoremap h :nohlsearch + +" Move cursor to result while typing immediately +set incsearch + +" Ignore case when searching +set ignorecase + +" Upper case search term => case sensitive search +set smartcase + +" Highlight the next match in red for 0.25 seconds +function! HighlightNext() + let [bufnum, lnum, col, off] = getpos('.') + let matchlen = strlen(matchstr(strpart(getline('.'),col-1),@/)) + let target_pat = '\c\%#\%('.@/.'\)' + let ring = matchadd('ErrorMsg', target_pat, 101) + redraw + exec 'sleep ' . float2nr(250) . 'm' + call matchdelete(ring) + redraw +endfunction +nnoremap n n:call HighlightNext() +nnoremap N N:call HighlightNext() + + +" Make w safe the buffer in normal mode +" and save the buffer in all modes +" (the latter disables making VIM a background job; +" is useful to have as w does not work in INSERT mode) +nnoremap w :update +nnoremap :update +vnoremap :update +inoremap :update + +" q quits VIM +nnoremap q :quit + +" Easier switching between tabs +noremap , :tabprevious +noremap . :tabnext + +" Arrow keys and either (un)indent lines or move them up or down +" (same for blocks of lines in visual mode) +nnoremap << +nnoremap >> +nnoremap :m-2 +nnoremap :m+ +nmap +nmap +nmap +nmap +vnoremap >gv +vnoremap :m'<-2gv=gv +vnoremap :m'>+1gv=gv +vmap +vmap +vmap +vmap + +" Make (un)indent lines +nnoremap >> +nnoremap << +inoremap >> +inoremap << +vnoremap >gv +vnoremap s :sort + +" Switch two words, just like xp switches two characters +noremap xp dwElp + + +" Auto-reload a file that was changed by some other process +" if the buffer has not yet been changed in the meantime +set autoread +augroup checktime + autocmd! + autocmd BufEnter * silent! checktime + autocmd CursorHold * silent! checktime + autocmd CursorHoldI * silent! checktime + autocmd CursorMoved * silent! checktime + autocmd CursorMovedI * silent! checktime +augroup END + + +" Auto-reload ~/.vim/vimrc +augroup vimrc + autocmd! BufWritePost $RC source % | redraw +augroup END +" Key binding to reload ~/.vim/vimrc manually +nnoremap rc :so $RC From dcdb32585a5ca7ff6d05e3f39893b74074e55a91 Mon Sep 17 00:00:00 2001 From: Alexander Hess Date: Mon, 18 Jul 2022 21:54:29 +0200 Subject: [PATCH 13/27] Set up Python develop environments - use `pyenv` to manage the various develop environments + install several Python binaries + each environment receives its own `poetry` install - add two virtual environments: + "interactive" => default environment with no library, which receives accidental `pip install`s + "utils" => hosts various globally available tools/apps (e.g., `mackup`) - add installation and update scripts --- .bashrc | 26 +++++- .config/pypoetry/config.toml | 3 + .config/shell/aliases.sh | 17 ++++ .config/shell/init_dotfiles.sh | 2 +- .config/shell/utils.sh | 153 +++++++++++++++++++++++++++++++++ .profile | 5 ++ .zshrc | 18 ++++ README.md | 18 ++++ 8 files changed, 240 insertions(+), 2 deletions(-) create mode 100644 .config/pypoetry/config.toml diff --git a/.bashrc b/.bashrc index 0549e39..24a1498 100644 --- a/.bashrc +++ b/.bashrc @@ -156,6 +156,13 @@ if ! shopt -oq posix; then fi +# Enable completions for various tools +command_exists invoke && eval "$(invoke --print-completion-script=bash)" +command_exists nox && eval "$(register-python-argcomplete nox)" +command_exists pip && eval "$(pip completion --bash)" +command_exists pipx && eval "$(register-python-argcomplete pipx)" +command_exists poetry && eval "$(poetry completions bash)" + # ============ # Key Bindings @@ -234,5 +241,22 @@ _prompt_jobs() { (( $(jobs -rp | wc -l) )) && echo -e "\033[0;32m %\033[0m" } -PS1='${chroot:+($_debian_chroot)}\w$(_prompt_git)$(_prompt_jobs) > ' +# Mimic zsh's pyenv/venv integration +_prompt_pyenv() { + if [ -n "$VIRTUAL_ENV" ]; then + echo -e "\033[0;36m py $(python -c "import os, sys; (hasattr(sys, 'real_prefix') or (hasattr(sys, 'base_prefix') and sys.base_prefix != sys.prefix)) and print(os.path.basename(sys.prefix))")\033[0m" + elif [ -n "$PYENV_VERSION" ]; then + if [ "$PYENV_VERSION" != "system" ]; then + echo -e "\033[0;36m py $PYENV_VERSION\033[0m" + fi + elif [ -f "$(pwd)/.python-version" ]; then + echo -e "\033[0;36m py $(cat .python-version | sed ':a;N;$!ba;s/\n/:/g')\033[0m" + fi +} + +# Disable the default prompts set by pyenv and venv +export PYENV_VIRTUALENV_DISABLE_PROMPT=1 +export VIRTUAL_ENV_DISABLE_PROMPT=1 + +PS1='${chroot:+($_debian_chroot)}\w$(_prompt_git)$(_prompt_jobs)$(_prompt_pyenv) > ' PS2='... ' diff --git a/.config/pypoetry/config.toml b/.config/pypoetry/config.toml new file mode 100644 index 0000000..53b35d3 --- /dev/null +++ b/.config/pypoetry/config.toml @@ -0,0 +1,3 @@ +[virtualenvs] +create = true +in-project = true diff --git a/.config/shell/aliases.sh b/.config/shell/aliases.sh index bec47d9..7dafcb1 100644 --- a/.config/shell/aliases.sh +++ b/.config/shell/aliases.sh @@ -80,6 +80,23 @@ alias more='less' alias tree='tree -C --dirsfirst' +# Make working with Python more convenient + +alias py='python' +alias ipy='ipython' + +if command_exists poetry; then + alias pr='poetry run' +fi + +if command_exists pyenv; then + alias pyvenvs='pyenv virtualenvs --bare --skip-aliases' + alias pyver='pyenv version' + alias pyvers='pyenv versions --skip-aliases' + alias pywhich='pyenv which' +fi + + # Aliases for various utilities alias datetime='date +"%Y-%m-%d %H:%M:%S %z (%Z)"' alias datetime-iso='date --iso-8601=seconds' diff --git a/.config/shell/init_dotfiles.sh b/.config/shell/init_dotfiles.sh index c7a1749..18d84fc 100755 --- a/.config/shell/init_dotfiles.sh +++ b/.config/shell/init_dotfiles.sh @@ -20,7 +20,7 @@ git clone --bare git@git.webartifex.biz:alexander/dotfiles.git "$HOME/.dotfiles" # Backup old dotfiles rm -rf "$HOME/.dotfiles.bak" >/dev/null -mkdir -p $HOME/.dotfiles.bak/.config/{bat,flameshot,git,Nextcloud,pop-system-updater,psql,shell} && \ +mkdir -p $HOME/.dotfiles.bak/.config/{bat,flameshot,git,Nextcloud,pop-system-updater,psql,pypoetry,shell} && \ mkdir -p $HOME/.dotfiles.bak/.vim/{after/ftplugin,backup,swap,undo} && \ /usr/bin/git --git-dir=$HOME/.dotfiles/ --work-tree=$HOME checkout 2>&1 | egrep "\s+\." | awk {'print $1'} | \ xargs -I{} mv {} "$HOME/.dotfiles.bak"/{} diff --git a/.config/shell/utils.sh b/.config/shell/utils.sh index ab3ccd4..92f22b1 100644 --- a/.config/shell/utils.sh +++ b/.config/shell/utils.sh @@ -12,6 +12,16 @@ in_zsh() { [ -n "$ZSH_VERSION" ] } +# Prepend a folder to $PATH if it is not already there +_prepend_to_path () { + if [ -d "$1" ] ; then + case :$PATH: in + *:$1:*) ;; + *) PATH=$1:$PATH ;; + esac + fi +} + # ========================= @@ -30,6 +40,13 @@ fi command_exists lesspipe && eval "$(SHELL=/bin/sh lesspipe)" +# Initialize pyenv if it is installed +if command_exists pyenv; then + eval "$(pyenv init -)" + eval "$(pyenv virtualenv-init -)" +fi + + # Configure the keyboard: # - make right alt and menu keys the compose key, e.g., for umlauts # - make caps lock a ctrl modifier and Esc key @@ -38,6 +55,32 @@ command_exists xcape && xcape -e "Caps_Lock=Escape" +# ========================== +# Command not found handlers +# ========================== + + +# Check if an unknown command is in a local Python venv +command_not_found_handle() { + if [ -x ".venv/bin/$1" ]; then + echo 'You forgot to activate the virtualenv' 1>&2 + exe=".venv/bin/$1" + shift + "$exe" "$@" + return $? + else + echo "$1: command not found" 1>&2 + return 127 + fi +} + +# zsh uses another name for the handler +command_not_found_handler() { + command_not_found_handle "$@" +} + + + # ============================== # Working with files and folders # ============================== @@ -194,6 +237,89 @@ genemail() { +# =================================================== +# Set up & maintain the Python (develop) environments +# =================================================== + + +# TODO: This needs to be updated regularly (or find an automated solution) +# The Python versions `pyenv` creates (in descending order) +_py3_versions=('3.10.5' '3.9.13' '3.8.13' '3.7.13') +_py2_version='2.7.18' + +# Each Python environment uses its own `poetry` installation to avoid +# integration problems between `pyenv` and `poetry` +# Source: https://github.com/python-poetry/poetry/issues/5252#issuecomment-1055697424 +_py3_site_packages=('poetry') + +# The pyenv virtualenv "utils" contains some globally available tools (e.g., `mackup`) +_py3_utils=('mackup') + +install-pyenv() { + echo -e "\nInstalling pyenv\n" + + # The official installer does a bit more than the `git clone`s below + # `curl https://pyenv.run | bash` + git clone https://github.com/pyenv/pyenv.git "$HOME/.pyenv" + git clone https://github.com/pyenv/pyenv-doctor.git "$HOME/.pyenv/plugins/pyenv-doctor" + git clone https://github.com/pyenv/pyenv-update.git "$HOME/.pyenv/plugins/pyenv-update" + git clone https://github.com/pyenv/pyenv-virtualenv.git "$HOME/.pyenv/plugins/pyenv-virtualenv" + git clone https://github.com/pyenv/pyenv-which-ext.git "$HOME/.pyenv/plugins/pyenv-which-ext" + + # On a first install, "$PYENV_ROOT/bin" is NOT on the $PATH + _prepend_to_path "$PYENV_ROOT/bin" +} + +re-install-pyenv() { + echo -e "\nRemoving pyenv\n" + rm -rf "$HOME/.pyenv" >/dev/null + install-pyenv +} + +create-or-update-python-envs() { + command_exists pyenv || install-pyenv + + eval "$(pyenv init --path)" + + # Keep a legacy Python 2.7, just in case + echo -e "\nInstalling/updating Python $_py2_version\n" + pyenv install --skip-existing $_py2_version + PYENV_VERSION=$_py2_version pip install --upgrade pip setuptools + PYENV_VERSION=$_py2_version python -c "import sys; print sys.version" + + for version in ${_py3_versions[@]}; do + echo -e "\nInstalling/updating Python $version\n" + pyenv install --skip-existing $version + + # Start the new environment with the latest `pip` and `setuptools` versions + PYENV_VERSION=$version pip install --upgrade pip setuptools + + # Put the specified utilities in the fresh environments (or update them) + for lib in ${_py3_site_packages[@]}; do + PYENV_VERSION=$version pip install --upgrade $lib + done + done + + # Create a virtualenv based off the latest Python version to host global utilities + echo -e "\nInstalling/updating global Python utilities\n" + pyenv virtualenv $_py3_versions[1] 'utils' + PYENV_VERSION='utils' pip install --upgrade pip setuptools + for util in ${_py3_utils[@]}; do + PYENV_VERSION='utils' pip install --upgrade $util + done + + # Create a virtualenv based off the latest Python version for interactive usage + # (This virtualenv is empty and is the target of accidental `pip install`s) + echo -e "\nInstalling/updating the default/interactive Python environment\n" + pyenv virtualenv $_py3_versions[1] 'interactive' + PYENV_VERSION='interactive' pip install --upgrade pip setuptools + + # Put all Python binaries and the utilities on the $PATH + pyenv global 'interactive' $_py3_versions 'utils' $_py2_version +} + + + # ============================= # Automate the update machinery # ============================= @@ -278,6 +404,28 @@ update-zsh() { } +# Update the entire Python tool chain +update-python() { + echo -e '\nUpdating the Python tool chain\n' + + if command_exists pyenv; then + echo -e '\nUpdating pyenv\n' + pyenv update + echo + + echo -e '\nUpdating Python environments\n' + create-or-update-python-envs + echo + fi + + if command_exists zsh-pip-cache-packages; then + echo -e '\nUpdating pip packages cache\n' + zsh-pip-clear-cache + zsh-pip-cache-packages + fi +} + + # Wrapper to run several update functions at once update-machine() { sudo --validate || return @@ -295,9 +443,14 @@ update-machine() { remove-old-snaps fi + update-python + update-dotfiles update-zsh + echo -e '\nUpdating the configs managed by mackup' + mackup restore --force + echo -e '\nUpdating password store\n' pass git pull echo diff --git a/.profile b/.profile index 2681a9a..640dc09 100644 --- a/.profile +++ b/.profile @@ -34,6 +34,11 @@ export BAT_CONFIG_PATH="$HOME/.config/bat/config" export LESSHISTFILE="${XDG_CACHE_HOME:-$HOME/.cache}/.lesshst" +export PYENV_ROOT="$HOME/.pyenv" +_prepend_to_path "$PYENV_ROOT/bin" +# No need for *.pyc files on a dev machine +export PYTHONDONTWRITEBYTECODE=1 + export PSQLRC="$HOME/.psqlrc" diff --git a/.zshrc b/.zshrc index 0e5b910..eabedc4 100644 --- a/.zshrc +++ b/.zshrc @@ -102,7 +102,10 @@ zplug "plugins/command-not-found", from:oh-my-zsh zplug "plugins/dotenv", from:oh-my-zsh zplug "plugins/dirhistory", from:oh-my-zsh zplug "plugins/git-escape-magic", from:oh-my-zsh +zplug "plugins/invoke", from:oh-my-zsh # completions for `invoke` zplug "plugins/jsontools", from:oh-my-zsh +zplug "plugins/pip", from:oh-my-zsh # completions for `pip` +zplug "plugins/poetry", from:oh-my-zsh # completions for `poetry` zplug "plugins/z", from:oh-my-zsh zplug "romkatv/powerlevel10k", as:theme, depth:1 @@ -141,6 +144,21 @@ zstyle ':completion:*:warnings' format 'No matches for: %d' zstyle ':completion:*' group-name '' +# Enable completions for various tools + +# invoke -> see plugins above +# command_exists invoke && eval "$(invoke --print-completion-script=zsh)" + +command_exists nox && eval "$(register-python-argcomplete nox)" + +# pip -> see plugins above +# command_exists pip && eval "$(pip completion --zsh)" + +command_exists pipx && eval "$(register-python-argcomplete pipx)" + +# poetry -> see plugins above + + # ============ # Key Bindings diff --git a/README.md b/README.md index 3625b50..1d262f1 100644 --- a/README.md +++ b/README.md @@ -23,3 +23,21 @@ Furthermore, `zsh` is set up with [`oh-my-zsh`](https://ohmyz.sh/) and `zplug`. Otherwise, `~/.profile` is probably *not* sourced. Don't worry: Your current dotfiles are backed up in the `~/.dotfiles.bak` folder! + + +### Python Development Environments + +The develop environments for Python are managed by [`pyenv`](https://github.com/pyenv/pyenv). + +To set them up, run: + +```bash +install-pyenv && create-or-update-python-envs +``` + +Several Python binaries are installed. +Additionally, two `virtualenv`s, "interactive" and "utils", are also created: + - "interactive" is the default environment with *no* libraries installed, and + - "utils" hosts globally available utilities. + +Use `pyenv local ...` to specify a particular Python binary for a project. From c90705bc6212f1f4cb624746b2a094d6aef3b009 Mon Sep 17 00:00:00 2001 From: Alexander Hess Date: Wed, 27 Jul 2022 14:20:29 +0200 Subject: [PATCH 14/27] Add public SSH keys --- .config/shell/init_dotfiles.sh | 1 + .ssh/authorized_keys | 6 ++++++ 2 files changed, 7 insertions(+) create mode 100644 .ssh/authorized_keys diff --git a/.config/shell/init_dotfiles.sh b/.config/shell/init_dotfiles.sh index 18d84fc..bfb4117 100755 --- a/.config/shell/init_dotfiles.sh +++ b/.config/shell/init_dotfiles.sh @@ -22,6 +22,7 @@ git clone --bare git@git.webartifex.biz:alexander/dotfiles.git "$HOME/.dotfiles" rm -rf "$HOME/.dotfiles.bak" >/dev/null mkdir -p $HOME/.dotfiles.bak/.config/{bat,flameshot,git,Nextcloud,pop-system-updater,psql,pypoetry,shell} && \ mkdir -p $HOME/.dotfiles.bak/.vim/{after/ftplugin,backup,swap,undo} && \ +mkdir -p $HOME/.dotfiles.bak/.ssh && \ /usr/bin/git --git-dir=$HOME/.dotfiles/ --work-tree=$HOME checkout 2>&1 | egrep "\s+\." | awk {'print $1'} | \ xargs -I{} mv {} "$HOME/.dotfiles.bak"/{} diff --git a/.ssh/authorized_keys b/.ssh/authorized_keys new file mode 100644 index 0000000..0f23558 --- /dev/null +++ b/.ssh/authorized_keys @@ -0,0 +1,6 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINMe2fzyH4b4AwQBRgZ60enFagogaEG2dkO4NIOKllss alexander@webartifex.biz (gateway) +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMRDaWrT2hH7BOV4Zv1ctVGqwfeqkssnHklRXBmng6Wr alexander@webartifex.biz (laptop1) +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOhhfx063dGoaE62cbdyGL3kp1AIovWFojQGNdqUpxr8 alexander@webartifex.biz (laptop2) +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIO4WZPkmknmo3R+DLjWrebt+X8UrHgoWwjHckbhxHVKC alexander@webartifex.biz (phone1) +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIbVaLHl4T+TjphPGSutYKH00Z3cNG+EmlhUfh+N/m6E alexander@webartifex.biz (tablet1) +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGGNCrFt/gUbBHVqhthBuRmdDH6yS30+GGcCnARSzg+q alexander@webartifex.biz (workstation1) From 4c6526b1cc0afde3dad0f3543f321ad99c07cc71 Mon Sep 17 00:00:00 2001 From: Alexander Hess Date: Wed, 27 Jul 2022 15:39:06 +0200 Subject: [PATCH 15/27] Add config for mackup - ignore apps whose config files are in the `dotfiles` repo (see: https://gitlab.webartifex.biz/alexander/dotfiles) - include various (config) files that should not be public: + Cisco's AnyConnect + history files for `bash`, `less`, `python`, `psql`, `tig`, and `zsh` + Nautilus' bookmarks + SSH config & known hosts --- .config/shell/init_dotfiles.sh | 1 + .mackup.cfg | 24 ++++++++++++++++++++++++ .mackup/README.md | 7 +++++++ .mackup/anyconnect.cfg | 5 +++++ .mackup/histories.cfg | 13 +++++++++++++ .mackup/nautilus.cfg | 5 +++++ .mackup/ssh_non-public.cfg | 7 +++++++ .psqlrc | 4 ++++ README.md | 7 +++++++ 9 files changed, 73 insertions(+) create mode 100644 .mackup.cfg create mode 100644 .mackup/README.md create mode 100644 .mackup/anyconnect.cfg create mode 100644 .mackup/histories.cfg create mode 100644 .mackup/nautilus.cfg create mode 100644 .mackup/ssh_non-public.cfg diff --git a/.config/shell/init_dotfiles.sh b/.config/shell/init_dotfiles.sh index bfb4117..729ccd9 100755 --- a/.config/shell/init_dotfiles.sh +++ b/.config/shell/init_dotfiles.sh @@ -21,6 +21,7 @@ git clone --bare git@git.webartifex.biz:alexander/dotfiles.git "$HOME/.dotfiles" # Backup old dotfiles rm -rf "$HOME/.dotfiles.bak" >/dev/null mkdir -p $HOME/.dotfiles.bak/.config/{bat,flameshot,git,Nextcloud,pop-system-updater,psql,pypoetry,shell} && \ +mkdir -p $HOME/.dotfiles.bak/.mackup && \ mkdir -p $HOME/.dotfiles.bak/.vim/{after/ftplugin,backup,swap,undo} && \ mkdir -p $HOME/.dotfiles.bak/.ssh && \ /usr/bin/git --git-dir=$HOME/.dotfiles/ --work-tree=$HOME checkout 2>&1 | egrep "\s+\." | awk {'print $1'} | \ diff --git a/.mackup.cfg b/.mackup.cfg new file mode 100644 index 0000000..da9e588 --- /dev/null +++ b/.mackup.cfg @@ -0,0 +1,24 @@ +[storage] +engine = file_system +path = nextcloud/getraenkemarkt +directory = mackup + +[applications_to_ignore] + +# Do not sync configuration files that are kept in `git` +# See: https://gitlab.webartifex.biz/alexander/dotfiles +bash +bat +git +flameshot +mackup +p10k +pgsql +poetry +ssh +vim +wget +zsh + +# Somehow, libreoffice cannot start with some other machine's configuration +libreoffice diff --git a/.mackup/README.md b/.mackup/README.md new file mode 100644 index 0000000..3ae9283 --- /dev/null +++ b/.mackup/README.md @@ -0,0 +1,7 @@ +# Custom Configuration for `mackup` + +This folder contains various **config** files + to include all kinds of files in the [`mackup backup`](https://github.com/lra/mackup). +Their format is described [here](https://github.com/lra/mackup/tree/master/doc#add-support-for-an-application-or-almost-any-file-or-directory). + +`mackup` is used to synchronize (dot) files the general public should *not* see. diff --git a/.mackup/anyconnect.cfg b/.mackup/anyconnect.cfg new file mode 100644 index 0000000..729f0de --- /dev/null +++ b/.mackup/anyconnect.cfg @@ -0,0 +1,5 @@ +[application] +name = Cisco's AnyConnect + +[configuration_files] +.anyconnect diff --git a/.mackup/histories.cfg b/.mackup/histories.cfg new file mode 100644 index 0000000..786c5ad --- /dev/null +++ b/.mackup/histories.cfg @@ -0,0 +1,13 @@ +[application] +name = various history files + +[configuration_files] +.bash_history +.lesshst +.python_history +.tig_history +.zsh_history + +[xdg_configuration_files] +# `~/.config/psql` is set in `~/.psqlrc` for all history files +psql diff --git a/.mackup/nautilus.cfg b/.mackup/nautilus.cfg new file mode 100644 index 0000000..c6c1e5b --- /dev/null +++ b/.mackup/nautilus.cfg @@ -0,0 +1,5 @@ +[application] +name = GNOME Files a.k.a. Nautilus + +[xdg_configuration_files] +gtk-3.0/bookmarks diff --git a/.mackup/ssh_non-public.cfg b/.mackup/ssh_non-public.cfg new file mode 100644 index 0000000..9e0dbd8 --- /dev/null +++ b/.mackup/ssh_non-public.cfg @@ -0,0 +1,7 @@ +[application] +name = non-public SSH (config) files + +[configuration_files] +.ssh/config +.ssh/known_hosts +.ssh/known_hosts.old diff --git a/.psqlrc b/.psqlrc index af0d26d..f2073cd 100644 --- a/.psqlrc +++ b/.psqlrc @@ -20,6 +20,10 @@ -- Use the best text editor in the world \set EDITOR vi +-- Use separate history files per database +-- and keep them in one folder for easier sync with `mackup` +\set HISTFILE ~/.config/psql/.psql_history- :DBNAME + -- Don't store the same SQL statement repeatedly \set HISTCONTROL ignoredups diff --git a/README.md b/README.md index 1d262f1..40e9ca0 100644 --- a/README.md +++ b/README.md @@ -41,3 +41,10 @@ Additionally, two `virtualenv`s, "interactive" and "utils", are also created: - "utils" hosts globally available utilities. Use `pyenv local ...` to specify a particular Python binary for a project. + + +### Non-public Dotfiles + +After setting up the Python environments (i.e., the "utils"), + running `mackup restore` symlinks further dotfiles into `~/`. +This only works for this project's maintainer. From 418eb402952fbb597ef5d612b78a49dcb76a6d00 Mon Sep 17 00:00:00 2001 From: Alexander Hess Date: Wed, 27 Jul 2022 23:39:46 +0200 Subject: [PATCH 16/27] Make Nextcloud auto-start on login --- .../com.nextcloud.desktopclient.nextcloud.desktop | 11 +++++++++++ .config/shell/init_dotfiles.sh | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 .config/autostart/com.nextcloud.desktopclient.nextcloud.desktop diff --git a/.config/autostart/com.nextcloud.desktopclient.nextcloud.desktop b/.config/autostart/com.nextcloud.desktopclient.nextcloud.desktop new file mode 100644 index 0000000..219765f --- /dev/null +++ b/.config/autostart/com.nextcloud.desktopclient.nextcloud.desktop @@ -0,0 +1,11 @@ +[Desktop Entry] +Name=Nextcloud +GenericName=File Synchronizer +Exec="/usr/bin/nextcloud" --background +Terminal=false +Icon=Nextcloud +Categories=Network +Type=Application +StartupNotify=false +X-GNOME-Autostart-enabled=true +X-GNOME-Autostart-Delay=10 diff --git a/.config/shell/init_dotfiles.sh b/.config/shell/init_dotfiles.sh index 729ccd9..7772e8b 100755 --- a/.config/shell/init_dotfiles.sh +++ b/.config/shell/init_dotfiles.sh @@ -20,7 +20,7 @@ git clone --bare git@git.webartifex.biz:alexander/dotfiles.git "$HOME/.dotfiles" # Backup old dotfiles rm -rf "$HOME/.dotfiles.bak" >/dev/null -mkdir -p $HOME/.dotfiles.bak/.config/{bat,flameshot,git,Nextcloud,pop-system-updater,psql,pypoetry,shell} && \ +mkdir -p $HOME/.dotfiles.bak/.config/{autostart,bat,flameshot,git,Nextcloud,pop-system-updater,psql,pypoetry,shell} && \ mkdir -p $HOME/.dotfiles.bak/.mackup && \ mkdir -p $HOME/.dotfiles.bak/.vim/{after/ftplugin,backup,swap,undo} && \ mkdir -p $HOME/.dotfiles.bak/.ssh && \ From f0e143242b7d42d8d6191cb348699b18307e819a Mon Sep 17 00:00:00 2001 From: Alexander Hess Date: Sat, 30 Aug 2025 11:19:10 +0200 Subject: [PATCH 17/27] Add base configuration - Follow XDG standard: ~/.config and ~/.local folders - Set environment variables and define aliases within ~/.config/shell - Add installation script for easy setup - Add README.md with info on the installation and general notes --- .bashrc | 8 ++++ .config/shell/README.md | 3 ++ .config/shell/aliases | 7 ++++ .config/shell/env | 28 ++++++++++++++ .local/bin/README.md | 3 ++ .local/bin/install-dotfiles | 74 +++++++++++++++++++++++++++++++++++++ .local/state/less/.gitkeep | 0 .profile | 54 +++++++++++++++++++++++++++ .zshrc | 7 ++++ README.md | 44 ++++++++++++++++++++++ 10 files changed, 228 insertions(+) create mode 100644 .bashrc create mode 100644 .config/shell/README.md create mode 100644 .config/shell/aliases create mode 100644 .config/shell/env create mode 100644 .local/bin/README.md create mode 100755 .local/bin/install-dotfiles create mode 100644 .local/state/less/.gitkeep create mode 100644 .profile create mode 100644 .zshrc create mode 100644 README.md diff --git a/.bashrc b/.bashrc new file mode 100644 index 0000000..8e7b6a1 --- /dev/null +++ b/.bashrc @@ -0,0 +1,8 @@ +#!/bin/bash + +# `bash`-specific configurations + + +# Load configuration files common to all kinds of shells, +# if not already done by a `bash` login shell +[ -z "$PROFILE_LOADED" ] && [ -f "$HOME/.profile" ] && . "$HOME/.profile" diff --git a/.config/shell/README.md b/.config/shell/README.md new file mode 100644 index 0000000..bd3a821 --- /dev/null +++ b/.config/shell/README.md @@ -0,0 +1,3 @@ +# Shell-related Configurations + +This folder contains files that are sourced by `bash` and `zsh`. diff --git a/.config/shell/aliases b/.config/shell/aliases new file mode 100644 index 0000000..eaf280d --- /dev/null +++ b/.config/shell/aliases @@ -0,0 +1,7 @@ +#!/bin/sh + +# Aliases used in all kinds of shells + + +# Manage the bare `git` repository in ~/ holding the dotfiles +alias dotfiles='git --git-dir=$XDG_DATA_HOME/dotfiles --work-tree=$HOME' diff --git a/.config/shell/env b/.config/shell/env new file mode 100644 index 0000000..297742d --- /dev/null +++ b/.config/shell/env @@ -0,0 +1,28 @@ +#!/bin/sh + +# Environment variables for all kinds of shells + + +# Standard XDG base directories +# See: https://wiki.archlinux.org/title/XDG_Base_Directory +export XDG_CACHE_HOME="$HOME/.cache" +export XDG_CONFIG_HOME="$HOME/.config" +export XDG_DATA_HOME="$HOME/.local/share" # also set in ~/.local/bin/install-dotfiles +export XDG_STATE_HOME="$HOME/.local/state" +# Make up a XDG directory for binaries (that does not exist in the standard) +export XDG_BIN_HOME="$HOME/.local/bin" + + +# Convenient names for various places in the system +export DOTFILES_DIR="$XDG_DATA_HOME/dotfiles" # also set in ~/.local/bin/install-dotfiles + + +# Generic shell configs +export GPG_TTY=$(tty) +export PAGER="less --chop-long-lines --ignore-case --LONG-PROMPT --no-init --status-column --quit-if-one-screen" +export TERM=xterm-256color +export TZ="Europe/Berlin" + + +# Move common tools' config and cache files into XDG directories +export LESSHISTFILE="$XDG_STATE_HOME/less/history" diff --git a/.local/bin/README.md b/.local/bin/README.md new file mode 100644 index 0000000..241ea08 --- /dev/null +++ b/.local/bin/README.md @@ -0,0 +1,3 @@ +# User-local Executables + +This folder contains executable files that are on the `$PATH`. diff --git a/.local/bin/install-dotfiles b/.local/bin/install-dotfiles new file mode 100755 index 0000000..4758e41 --- /dev/null +++ b/.local/bin/install-dotfiles @@ -0,0 +1,74 @@ +#!/bin/sh + +# Installation script to make the dotfiles available in ~/ +# +# `git` is the only dependency for this script to run (See: https://git-scm.com) +# +# See: https://code.webartifex.biz/alexander/dotfiles#installation + + +set -e + + +XDG_DATA_HOME="$HOME/.local/share" # also set in ~/.config/shell/env +DOTFILES_DIR="$XDG_DATA_HOME/dotfiles" # also set in ~/.config/shell/env + + +# Check if the dotfiles were installed previously +if [ -d "$DOTFILES_DIR" ] && [ "${FORCE_INSTALL:-}" != "1" ]; then + echo "" + echo "The dotfiles are already installed at: $DOTFILES_DIR" + echo "" + echo "Options:" + echo " - Set 'export FORCE_INSTALL=1' and run installation again" + echo " - Update with 'dotfiles pull' and continue using them" + echo "" +else + # Remove an already installed dotfiles repository + if [ -d "$DOTFILES_DIR" ]; then + rm -rf "$DOTFILES_DIR" + fi + + if [ -z "$DOTFILES_BRANCH" ]; then + # Auto-detect if we're on a desktop system + if [ -n "$DISPLAY" ] || [ -n "$WAYLAND_DISPLAY" ] || [ "$(systemctl --user is-active graphical-session.target 2>/dev/null)" = "active" ]; then + export DOTFILES_BRANCH="desktop" + else + export DOTFILES_BRANCH="main" + fi + elif [ "$DOTFILES_BRANCH" != "desktop" ] && [ "$DOTFILES_BRANCH" != "main" ]; then + echo "" + echo "'DOTFILES_BRANCH' may only be one of: 'desktop' or 'main'" + exit 1 + fi + + mkdir -p "$XDG_DATA_HOME" + + git clone --bare https://code.webartifex.biz/alexander/dotfiles "$XDG_DATA_HOME/dotfiles" + + # Do not checkout project documentation intended for web GUIs (e.g., GitHub) + git --git-dir="$DOTFILES_DIR" --work-tree="$HOME" config core.sparseCheckout true + echo "/*" > "$DOTFILES_DIR/info/sparse-checkout" + echo "!LICENSE.txt" >> "$DOTFILES_DIR/info/sparse-checkout" + echo "!README.md" >> "$DOTFILES_DIR/info/sparse-checkout" + + # Put the dotfiles in the user's `$HOME` folder + git --git-dir="$DOTFILES_DIR" --work-tree="$HOME" checkout --force "$DOTFILES_BRANCH" + + # Do not show files not tracked in the dotfiles repository because there are simply too many + git --git-dir="$DOTFILES_DIR" --work-tree="$HOME" config --local status.showUntrackedFiles no + + # The author of this file prefers to use SSH to sync his machines with the origin + git --git-dir="$DOTFILES_DIR" --work-tree="$HOME" remote set-url origin git@git.webartifex.biz:alexander/dotfiles.git + + echo "" + echo "The dotfiles were installed successfully" + + # Mimic starting a new shell to get new dotfiles right away + if [ -n "$ZSH_VERSION" ]; then + . "$HOME/.zshrc" + else + . "$HOME/.profile" + fi + +fi diff --git a/.local/state/less/.gitkeep b/.local/state/less/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/.profile b/.profile new file mode 100644 index 0000000..9641b87 --- /dev/null +++ b/.profile @@ -0,0 +1,54 @@ +#!/bin/sh + +# Main setup file executed for all kinds of shells + + +# Prevent loading ~/.profile twice in `bash` +export PROFILE_LOADED=1 + + +# Basic utilities + +_command_exists() { + command -v "$1" 1>/dev/null 2>&1 +} + +_in_bash() { + [ -n "$BASH_VERSION" ] +} + +_in_zsh() { + [ -n "$ZSH_VERSION" ] +} + +_prepend_to_path () { + if [ -d "$1" ] ; then + case :$PATH: in + *:$1:*) ;; + *) PATH=$1:$PATH ;; + esac + fi +} + + +# Load configuration files common to all kinds of shells +[ -f "$HOME/.config/shell/env" ] && . "$HOME/.config/shell/env" +[ -f "$HOME/.config/shell/aliases" ] && . "$HOME/.config/shell/aliases" + + +# Source ~/.profile_local, which holds machine-specific ENV variables +[ -f "$HOME/.profile_local" ] && . "$HOME/.profile_local" + + +# Load `bash`-specific configurations for non-login `bash` shells +if [ -n "$BASH_VERSION" ] && [ -f "$HOME/.bashrc" ]; then + . "$HOME/.bashrc" +fi + + +# Put local executables on the `$PATH` +_prepend_to_path "$HOME/.local/bin" + + +# Ensure ~/.profile is loaded each time `bash` starts +unset PROFILE_LOADED diff --git a/.zshrc b/.zshrc new file mode 100644 index 0000000..3a46429 --- /dev/null +++ b/.zshrc @@ -0,0 +1,7 @@ +#!/bin/zsh + +# `zsh`-specific configurations + + +# Load configuration files common to all kinds of shells +[ -f "$HOME/.profile" ] && . "$HOME/.profile" diff --git a/README.md b/README.md new file mode 100644 index 0000000..f0acd59 --- /dev/null +++ b/README.md @@ -0,0 +1,44 @@ +# Dotfiles + +This repository contains useful (config) files. + +It is structured into two branches: +- [desktop](https://code.webartifex.biz/alexander/dotfiles/src/branch/desktop) +- [main](https://code.webartifex.biz/alexander/dotfiles/src/branch/main) + +`main` contains dotfiles intended to be used on all kinds of machines + and can be thought of as a "minimal" or "server" version. +`desktop` is (re-)based on top of `main` + and adds "desktop" related dotfiles (e.g., GNOME stuff). + + +## Installation + +Simply run: + +```sh +curl https://code.webartifex.biz/alexander/dotfiles/raw/branch/main/.local/bin/install-dotfiles > install-dotfiles && . ./install-dotfiles && rm ./install-dotfiles +``` + +or + +``` +wget https://code.webartifex.biz/alexander/dotfiles/raw/branch/main/.local/bin/install-dotfiles -O install-dotfiles && . ./install-dotfiles && rm ./install-dotfiles +``` + +This downloads a simple [installation script](.local/bin/install-dotfiles) + and then executes it. +The script has only one dependency, namely [git](https://git-scm.com). +So, it should not be too hard to get this going. + +Normally, I advice against executing shell scripts from the internet, + but this one is short enough to be read even by beginners. +So, convince yourself that it is not harmful! + + +## Shells + +The config files in this repository are optimized for usage with + [GNU's Bourne again shell](https://man7.org/linux/man-pages/man1/bash.1.html), + or `bash` for short, + and the popular [zsh](https://www.zsh.org/). From dc154f29c734d916b06fb96c515348d2e8b11c83 Mon Sep 17 00:00:00 2001 From: Alexander Hess Date: Sat, 30 Aug 2025 11:19:19 +0200 Subject: [PATCH 18/27] Mark this repository as open-source ... ... to be used by anyone under the MIT license --- LICENSE.txt | 19 +++++++++++++++++++ README.md | 6 ++++++ 2 files changed, 25 insertions(+) create mode 100644 LICENSE.txt diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..eb196e9 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,19 @@ +Copyright (c) 2022-2025 Alexander Hess [alexander@webartifex.biz] + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index f0acd59..92ea970 100644 --- a/README.md +++ b/README.md @@ -42,3 +42,9 @@ The config files in this repository are optimized for usage with [GNU's Bourne again shell](https://man7.org/linux/man-pages/man1/bash.1.html), or `bash` for short, and the popular [zsh](https://www.zsh.org/). + + +## Copyright + +This repository and *all* of its contents are open-source + under the [MIT license](./LICENSE.txt). From 1f3fe882161173246855a9582c8682325a323f81 Mon Sep 17 00:00:00 2001 From: Alexander Hess Date: Sat, 30 Aug 2025 11:19:24 +0200 Subject: [PATCH 19/27] Add configuration for `bash` - Add ~/.bashrc + Configure on how the `history` works + Enable nicer `cd` and globbing behavior + Enable tab completion, even for aliases + Add some more stuff from Debian's ~/.bashrc - Add ~/.bash_logout clearing the screen - Adapt the installation script to remove possibly conflicting files - Ensure ~/.local/state/bash/ exists --- .bash_logout | 3 + .bashrc | 130 ++++++++++++++++++++++++++++++++++++ .config/shell/logout | 25 +++++++ .local/bin/install-dotfiles | 4 ++ .local/state/bash/.gitkeep | 0 .profile | 5 ++ 6 files changed, 167 insertions(+) create mode 100644 .bash_logout create mode 100644 .config/shell/logout create mode 100644 .local/state/bash/.gitkeep diff --git a/.bash_logout b/.bash_logout new file mode 100644 index 0000000..4a71b10 --- /dev/null +++ b/.bash_logout @@ -0,0 +1,3 @@ +#!/bin/bash + +. "$XDG_CONFIG_HOME/shell/logout" diff --git a/.bashrc b/.bashrc index 8e7b6a1..e67c28a 100644 --- a/.bashrc +++ b/.bashrc @@ -6,3 +6,133 @@ # Load configuration files common to all kinds of shells, # if not already done by a `bash` login shell [ -z "$PROFILE_LOADED" ] && [ -f "$HOME/.profile" ] && . "$HOME/.profile" + + +# Ensure `bash` is running interactively +case $- in + *i*) ;; + *) return;; +esac + + +# Configure the `history` + +# Set these environment variables here +# to avoid conflict/overlap with `zsh` + +export HISTFILE="$XDG_STATE_HOME/bash/history" + +export HISTSIZE=999999 # Number of lines kept in memory +export HISTFILESIZE=999999 # Number of lines kept in the `$HISTFILE` + +# Ignore commands prefixed with a space +# and ones entered identically just before +export HISTCONTROL=ignoreboth + +shopt -s cmdhist # Remember multi-line commands as just one line +shopt -s histappend # Do not overwrite the `$HISTFILE` +shopt -s histreedit # Allow editing failed history substitutions +shopt -s lithist # Store multi-line commands in history without `;` + + +# Make `bash` feel a bit more like `zsh` + +shopt -s autocd # Just type the directory to `cd` into it +shopt -s cdspell # Correct minor spelling mistakes with `cd` +shopt -s checkjobs # Show number of running jobs when exiting `bash` +shopt -s checkwinsize # Update `$ROWS` and `$COLUMNS` after commands +shopt -s globstar # Expand ** into recursive directories + + +stty -ixon # Prevent Ctrl+S from freezing `bash` + + +# Make `bash` show `chroot`s +if [ -z "${debian_chroot:-}" ] && [ -r /etc/debian_chroot ]; then + debian_chroot=$(cat /etc/debian_chroot) +fi + + +# Make `bash` more colorful + +case "$TERM" in + xterm-color|*-256color) color_prompt=yes;; +esac + +if [ -x /usr/bin/dircolors ]; then + test -r ~/.dircolors && eval "$(dircolors -b ~/.dircolors)" || eval "$(dircolors -b)" + alias ls='ls --color=auto' +fi + + +# Enable tab completion + +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 + +# Add tab completion for all aliases to commands with completion functions +# (must come after bash completions have been set up) +# Source: https://superuser.com/a/437508 +_alias_completion() { + local namespace="alias_completion" + # parse function based completion definitions, where capture group 2 => function and 3 => trigger + local compl_regex='complete( +[^ ]+)* -F ([^ ]+) ("[^"]+"|[^ ]+)' + # parse alias definitions, where capture group 1 => trigger, 2 => command, 3 => command arguments + local alias_regex="alias ([^=]+)='(\"[^\"]+\"|[^ ]+)(( +[^ ]+)*)'" + # create array of function completion triggers, keeping multi-word triggers together + eval "local completions=($(complete -p | sed -Ene "/$compl_regex/s//'\3'/p"))" + (( ${#completions[@]} == 0 )) && return 0 + # create temporary file for wrapper functions and completions + rm -f "/tmp/${namespace}-*.tmp" # preliminary cleanup + local tmp_file; tmp_file="$(mktemp "/tmp/${namespace}-${RANDOM}XXX.tmp")" || return 1 + local completion_loader; completion_loader="$(complete -p -D 2>/dev/null | sed -Ene 's/.* -F ([^ ]*).*/\1/p')" + # read in " '' ''" lines from defined aliases + local line; while read line; do + eval "local alias_tokens; alias_tokens=($line)" 2>/dev/null || continue # some alias arg patterns cause an eval parse error + local alias_name="${alias_tokens[0]}" alias_cmd="${alias_tokens[1]}" alias_args="${alias_tokens[2]# }" + # skip aliases to pipes, boolean control structures and other command lists + # (leveraging that eval errs out if $alias_args contains unquoted shell metacharacters) + eval "local alias_arg_words; alias_arg_words=($alias_args)" 2>/dev/null || continue + # avoid expanding wildcards + read -a alias_arg_words <<< "$alias_args" + # skip alias if there is no completion function triggered by the aliased command + if [[ ! " ${completions[*]} " =~ " $alias_cmd " ]]; then + if [[ -n "$completion_loader" ]]; then + # force loading of completions for the aliased command + eval "$completion_loader $alias_cmd" + # 124 means completion loader was successful + [[ $? -eq 124 ]] || continue + completions+=($alias_cmd) + else + continue + fi + fi + local new_completion="$(complete -p "$alias_cmd")" + # create a wrapper inserting the alias arguments if any + if [[ -n $alias_args ]]; then + local compl_func="${new_completion/#* -F /}"; compl_func="${compl_func%% *}" + # avoid recursive call loops by ignoring our own functions + if [[ "${compl_func#_$namespace::}" == $compl_func ]]; then + local compl_wrapper="_${namespace}::${alias_name}" + echo "function $compl_wrapper { + (( COMP_CWORD += ${#alias_arg_words[@]} )) + COMP_WORDS=($alias_cmd $alias_args \${COMP_WORDS[@]:1}) + (( COMP_POINT -= \${#COMP_LINE} )) + COMP_LINE=\${COMP_LINE/$alias_name/$alias_cmd $alias_args} + (( COMP_POINT += \${#COMP_LINE} )) + $compl_func + }" >> "$tmp_file" + new_completion="${new_completion/ -F $compl_func / -F $compl_wrapper }" + fi + fi + # replace completion trigger by alias + new_completion="${new_completion% *} $alias_name" + echo "$new_completion" >> "$tmp_file" + done < <(alias -p | sed -Ene "s/$alias_regex/\1 '\2' '\3'/p") + . "$tmp_file" && \rm -f "$tmp_file" +}; _alias_completion diff --git a/.config/shell/logout b/.config/shell/logout new file mode 100644 index 0000000..e5c5993 --- /dev/null +++ b/.config/shell/logout @@ -0,0 +1,25 @@ +#!/bin/sh + +# When logging out of a machine, clear the screen to increase privacy + + +if [ "$SHLVL" = 1 ]; then # If on the outermost shell instance + + # Clear screen and scrollback in SSH/terminal emulators + if _command_exists clear; then + clear + printf '\e[3J' # Clear scrollback buffer in modern emulators + fi + + # On real Linux tty, run `clear_console` for full reset as well + if [ -t 0 ] && [ "$(tty)" != "not a tty" ]; then + case "$(tty)" in + /dev/tty[0-9]*) + if _command_exists clear_console; then + clear_console -q + fi + ;; + esac + fi + +fi diff --git a/.local/bin/install-dotfiles b/.local/bin/install-dotfiles index 4758e41..bb2e6ce 100755 --- a/.local/bin/install-dotfiles +++ b/.local/bin/install-dotfiles @@ -61,6 +61,10 @@ else # The author of this file prefers to use SSH to sync his machines with the origin git --git-dir="$DOTFILES_DIR" --work-tree="$HOME" remote set-url origin git@git.webartifex.biz:alexander/dotfiles.git + # Remove potentially conflicting `bash` startup files + rm -f "$HOME/.bash_login" + rm -f "$HOME/.bash_profile" + echo "" echo "The dotfiles were installed successfully" diff --git a/.local/state/bash/.gitkeep b/.local/state/bash/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/.profile b/.profile index 9641b87..3d44a67 100644 --- a/.profile +++ b/.profile @@ -1,6 +1,11 @@ #!/bin/sh # Main setup file executed for all kinds of shells +# +# For `bash`, the following two files must not exist: +# - ~/.bash_login +# - ~/.bash_profile +# If they do, this file may not be executed! # Prevent loading ~/.profile twice in `bash` From fa98b224316a2100d621087f6804b5b99f41f2e0 Mon Sep 17 00:00:00 2001 From: Alexander Hess Date: Sat, 30 Aug 2025 11:19:30 +0200 Subject: [PATCH 20/27] Add configuration for `zsh` - Add ~/.zshrc + Configure on how the `history` works + Enable nicer `cd` and globbing behavior + Enable tab completion, and make them feel nicer + Enable VI mode and add some VI-like key bindings - Add ~/.zlogout clearing the screen - Add ~/.config/zsh/.zshrc and make it dispatch to ~/.zshrc to make `zsh` use the same configuration even on more recent Debian/Ubuntu machines that do not look for ~/.zshrc any more - Ensure ~/.local/state/zsh/ exists --- .config/zsh/.zshrc | 10 ++++++ .config/zsh/README.md | 3 ++ .local/state/zsh/.gitkeep | 0 .profile | 4 +++ .zlogout | 3 ++ .zshrc | 73 +++++++++++++++++++++++++++++++++++++++ 6 files changed, 93 insertions(+) create mode 100644 .config/zsh/.zshrc create mode 100644 .config/zsh/README.md create mode 100644 .local/state/zsh/.gitkeep create mode 100644 .zlogout diff --git a/.config/zsh/.zshrc b/.config/zsh/.zshrc new file mode 100644 index 0000000..571e93c --- /dev/null +++ b/.config/zsh/.zshrc @@ -0,0 +1,10 @@ +#!/bin/zsh + +# Load the real `zsh` config file in ~/ +# +# Recent Debian/Ubuntu versions look for .zshrc +# in .config/zsh and no longer in ~/ which +# is still the main location in many other distributions + + +. "$HOME/.zshrc" diff --git a/.config/zsh/README.md b/.config/zsh/README.md new file mode 100644 index 0000000..a2882a4 --- /dev/null +++ b/.config/zsh/README.md @@ -0,0 +1,3 @@ +# `zsh`-related Configurations + +This folder contains files that are sourced by `zsh`. diff --git a/.local/state/zsh/.gitkeep b/.local/state/zsh/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/.profile b/.profile index 3d44a67..db89137 100644 --- a/.profile +++ b/.profile @@ -51,6 +51,10 @@ if [ -n "$BASH_VERSION" ] && [ -f "$HOME/.bashrc" ]; then fi +# `zsh`-specific configurations are automatically sourced from ~/.zshrc, +# which then also ensures that this file is sourced + + # Put local executables on the `$PATH` _prepend_to_path "$HOME/.local/bin" diff --git a/.zlogout b/.zlogout new file mode 100644 index 0000000..4ec153e --- /dev/null +++ b/.zlogout @@ -0,0 +1,3 @@ +#!/bin/zsh + +. "$XDG_CONFIG_HOME/shell/logout" diff --git a/.zshrc b/.zshrc index 3a46429..81a88e8 100644 --- a/.zshrc +++ b/.zshrc @@ -3,5 +3,78 @@ # `zsh`-specific configurations +# Remove built-in aliases because we use our own, sourced via ~/.profile +unalias -a + + # Load configuration files common to all kinds of shells [ -f "$HOME/.profile" ] && . "$HOME/.profile" + + +# Ensure `zsh` is running interactively +[[ -o interactive ]] || return + + +# Make `zsh` behave like `bash` for prompts +PS1='%n@%m:%~%(!.#.$) ' + + +# Configure the `history` + +# Set these environment variables here +# to avoid conflict/overlap with `bash` + +export HISTFILE="$XDG_STATE_HOME/zsh/history" +export HISTSIZE=999999 # Number of lines kept in memory +export SAVEHIST=999999 # Number of lines kept in the `$HISTFILE` + +setopt APPEND_HISTORY # Do not overwrite the `$HISTFILE` +setopt INC_APPEND_HISTORY # Write to the `$HISTFILE` immediately +setopt HIST_REDUCE_BLANKS # Remove superfluous blanks from the `history` +setopt HIST_VERIFY # Show expanded `history` before executing + + +# Make `zsh` feel even nicer + +setopt AUTO_CD # Just type the directory to `cd` into it +setopt EXTENDED_GLOB # Advanced globbing patterns +setopt NULL_GLOB # Remove patterns with no matches +setopt CORRECT # Correct spelling of commands +setopt CHECK_JOBS # Show number of running jobs when exiting `zsh` +setopt NO_BEEP # Silence `zsh` + + +stty -ixon # Prevent Ctrl+S from freezing `zsh` + + +# Enable (tab) completions + +autoload -Uz compinit && compinit + +# Enable match highlighting and scrolling through long lists, +# and provide a different style of menu completion +zmodload zsh/complist + +# Include hidden files in tab completion +_comp_options+=(GLOB_DOTS) + +# Make selecting completions nicer with a visual menu +zstyle ':completion:*' menu select + +# Make new executables completable right away +zstyle ':completion:*' rehash true + + +# Configure key bindings + +# VI mode +bindkey -v + +# Use VI keys to navigate the completions in the menu +bindkey -M menuselect 'h' vi-backward-char +bindkey -M menuselect 'k' vi-up-line-or-history +bindkey -M menuselect 'l' vi-forward-char +bindkey -M menuselect 'j' vi-down-line-or-history + +# Enable Ctrl-R for reverse history search +bindkey "^R" history-incremental-search-backward From 1aaf15e9435b902aa79f6afeaae2664193a2c0b3 Mon Sep 17 00:00:00 2001 From: Alexander Hess Date: Sat, 30 Aug 2025 11:19:37 +0200 Subject: [PATCH 21/27] Show welcome message after starting a shell ... ... with some basic information, mainly to show that the dotfiles are used --- .config/shell/welcome | 44 +++++++++++++++++++++++++++++++++++++++++++ .profile | 4 ++++ 2 files changed, 48 insertions(+) create mode 100644 .config/shell/welcome diff --git a/.config/shell/welcome b/.config/shell/welcome new file mode 100644 index 0000000..1c707a9 --- /dev/null +++ b/.config/shell/welcome @@ -0,0 +1,44 @@ +#!/bin/sh + +# Show system info each time a shell is started + + +_hostname=$(hostname) +_os="$(uname -s) $(uname -r)" +_uptime=$(uptime -p | sed 's/up //; s/weeks\?/w/g; s/days\?/d/g; s/hours\?/h/g; s/minutes\?/m/g; s/ //g') +_user=$(whoami) +_work_dir=$(echo "$PWD" | sed "s|^$HOME|~|") + + +if [ "$(id -u)" -eq 0 ]; then + _prompt="#" +else + _prompt="$" +fi + + +if [ -n "$SSH_CLIENT" ] || [ -n "$SSH_TTY" ]; then + _remote=" ssh" +else + _remote=" local" +fi + + +if _in_bash; then + _shell_type="bash" +elif _in_zsh; then + _shell_type="zsh" +else + _shell_type="non-bash/zsh shell" +fi + + +_info_line="$_user@$_hostname:$_work_dir$_prompt$_remote $_os uptime: $_uptime $_shell_type" +_sep_line=$(echo "$_info_line" | sed 's/./─/g') + + +echo "" +echo "$_sep_line" +echo "$_info_line" +echo "$_sep_line" +echo "" diff --git a/.profile b/.profile index db89137..0ef05d4 100644 --- a/.profile +++ b/.profile @@ -61,3 +61,7 @@ _prepend_to_path "$HOME/.local/bin" # Ensure ~/.profile is loaded each time `bash` starts unset PROFILE_LOADED + + +# When everything is loaded, show a little welcome message +[ -f "$HOME/.config/shell/welcome" ] && . "$HOME/.config/shell/welcome" From de2918071e43eb8a518cd3b7933a31917ec2aabb Mon Sep 17 00:00:00 2001 From: Alexander Hess Date: Sat, 30 Aug 2025 11:19:43 +0200 Subject: [PATCH 22/27] Add configuration for `git` - Add .config/git/config + Define aliases + Configure default behavior in various situations + Add user information with signing key - Add .config/git/commit_msg_template.txt - Add .config/git/ignore - Integrate `git` aliases into the shell --- .config/git/commit_msg_template.txt | 18 ++ .config/git/config | 273 ++++++++++++++++++++++++++++ .config/git/ignore | 6 + .config/shell/aliases | 21 +++ 4 files changed, 318 insertions(+) create mode 100644 .config/git/commit_msg_template.txt create mode 100644 .config/git/config create mode 100644 .config/git/ignore diff --git a/.config/git/commit_msg_template.txt b/.config/git/commit_msg_template.txt new file mode 100644 index 0000000..5b07947 --- /dev/null +++ b/.config/git/commit_msg_template.txt @@ -0,0 +1,18 @@ +# SUBJECT -> What does the commit do? +# - Imperative mood, no "." at the end +# - Start with "Add", "Fix", "Make", "Remove", ... +#---------- 50 characters / 1 line ---------------| + + +# BODY -> The why and how +# - Use plain text without formatting +# + Use "-" and "+" as bullets +# - "See: URL" to link to external resources +#---------- 72 characters / multiple lines -----------------------------| + + +# ISSUE TRACKER -> Uncomment one of the lines below +# Closes #41 +# Fixes #42 +# Resolves #43 + diff --git a/.config/git/config b/.config/git/config new file mode 100644 index 0000000..f0092cb --- /dev/null +++ b/.config/git/config @@ -0,0 +1,273 @@ +[alias] + +# Note that ~/.config/shell/aliases loads all `git` aliases with +# less than 7 characters into the shell's "namespace" with a "g" prefix +# Example: `git add` <=> `git a` <=> `ga` + +a = add +ap = add --patch + +br = branch +bra = branch --all +brd = branch --delete +brdd = branch --delete --force +brm = branch --move + +ci = commit +cim = commit --message + +cl = clone + +co = checkout +cob = checkout -b +cod = checkout develop +com = checkout main + +cp = cherry-pick + +df = diff + +fe = fetch + +lg = log +lga = log --all + +me = merge +mea = merge --abort +mec = merge --continue +meff = merge --ff-only +menoff = merge --no-ff + +pl = pull +plrb = pull --rebase + +ps = push +psf = push --force + +rb = rebase --committer-date-is-author-date +rba = rebase --abort +rbc = rebase --continue +rbi = rebase --interactive +rbq = rebase --quit +rbs = rebase --skip + +rl = reflog + +rm = rm # to make it available as the `grm` alias in the shell + +rs = reset + +rv = revert +s = status +ss = status --short + +sh = show + +st = stash +sta = stash push --include-untracked # "push" does not go into the shortcut! +stam = stash push --include-untracked --message +stapp = stash apply +stl = stash list +stp = stash pop +stsh = stash show + +# Synonyms as "specified" in the `git status` header +discard = checkout -- +unstage = reset HEAD -- + +amend-commit = !git log -n 1 --pretty=tformat:%B | git commit -F - --amend # Keep the commit message + +current-branch = !git rev-parse --abbrev-ref HEAD + +project-root = rev-parse --show-toplevel + +uncommit = reset --soft HEAD~1 + +# Sync the working directory into the index +sync-deleted = !git ls-files -z --deleted | xargs -r -0 git rm +sync = !git sync-deleted && git add . --all + +# Make minimal diff the default +diff-minimal = diff --color-words=. --ws-error-highlight=all +d = !git diff-minimal +dlc = diff --color-words=. --ws-error-highlight=all HEAD +ds = diff --color-words=. --ws-error-highlight=all --staged + +# Clean the project folder with intuitive commands +clean-all = !git reset --hard && git clean-ignored && git clean-untracked +clean-ignored = "!f() { if [ -f .python-version ]; then mv .python-version .python-version.XYZ; fi; if [ -f .env ]; then mv .env .env.XYZ; fi; git clean -X -d -f "$@"; if [ -f .python-version.XYZ ]; then mv .python-version.XYZ .python-version; fi; if [ -f .env.XYZ ]; then mv .env.XYZ .env; fi }; f" +clean-untracked = !git clean -x -d -e ".python-version" -e ".env" -f # because the "-e" flag does not work with "-X" + +# Delete EVERYTHING not reachable from a branch from the repository +gc-everything = "!f() { git -c gc.reflogExpire=0 -c gc.reflogExpireUnreachable=0 -c gc.rerereresolved=0 -c gc.rerereunresolved=0 -c gc.pruneExpire=now gc "$@"; }; f" + +# Make the logs look nice by default +log-format1 = log --pretty='%C(auto)%h: %s%d%Creset%n%C(dim)%an @ %ad => %ar%n' --date=format:'%a %Y-%m-%d %H:%M:%S %z' +log-format2 = log --pretty='%C(auto)%h: %s%d%Creset%n%C(dim)%aN @ %ad => %ar%n%+b' --date=format:'%a %Y-%m-%d %H:%M:%S %z' +last-commit = !git log-format2 -1 -p --stat +lc = !git last-commit +history = !git log-format2 --graph +hi = !git history +hia = !git history --all +summary = !git log-format1 --graph +su = !git summary +sua = !git summary --all +oneline = log --pretty='%C(auto)%h: %s%d' --graph +ol = !git oneline +ola = !git oneline --all + +# Search the repository +grep-code = grep --break --context 1 --full-name --heading --line-number --show-function +grepc = !git grep-code +grep-log = log --all --regexp-ignore-case --pretty='%C(auto)%h: %s%+D%Creset%n%C(reverse)%C(dim)%aN @ %ad = %ar%Creset%n%+b' --date=format:'%a %Y-%m-%d %H:%M:%S' --grep +grepl = !git grep-log +grep-text = grep --break --context 1 --full-name --heading --ignore-case --line-number +grept = !git grep-text + +# Prune local branches that were deleted remotely +prune-delete = "!git fetch --prune && git branch -vv | grep ': gone]' | awk '{print $1}' | xargs git branch -d" +prune-show = "!git fetch --prune && git branch -vv | grep ': gone]' | awk '{print $1}'" + +aliases = config --get-regexp 'alias.*' +aliases-internal = !git config --list | grep 'alias\\.' | sed 's/alias\\.\\([^=]*\\)=\\(.*\\)/\\1/' | sort # used in ~/.config/shell/aliases + + +[clean] + +requireforce = true + + +[color "branch"] + +current = cyan dim bold reverse +local = green bold +remote = red bold + + +[color "decorate"] + +HEAD = cyan dim bold reverse +branch = green bold +remoteBranch = red bold +stash = magenta dim bold reverse +tag = magenta bold + + +[color "diff"] + +context = white +frag = blue dim bold reverse +meta = yellow dim bold reverse +new = green bold +old = red bold +whitespace = red dim bold reverse + + +[color "grep"] + +context = white +filename = yellow dim bold reverse +function = white bold +linenumber = blue dim bold reverse +match = red bold +selected = white +separator = blue dim bold reverse + + +[color "interactive"] + +error = red dim bold reverse +header = white +help = yellow bold +prompt = white dim bold reverse + + +[color "status"] + +added = green bold +branch = cyan dim bold reverse +changed = yellow bold +header = white +localBranch = green bold +nobranch = red dim bold reverse +remoteBranch = red bold +unmerged = yellow dim bold reverse +untracked = red bold + + +[commit] + +cleanup = strip +gpgSign = true +template = ~/.config/git/commit_msg_template.txt +verbose = true + + +[core] + +editor = vim +excludesfile = ~/.config/git/ignore +pager = less --chop-long-lines --ignore-case --LONG-PROMPT --status-column --quit-if-one-screen +whitespace = -space-before-tab,tab-in-indent + + +[diff] + +renames = true +submodule = log + + +[help] + +autocorrect = 50 + + +[init] + +defaultBranch = main + + +[merge] + +conflictstyle = diff3 +ff = only + + +[pull] + +ff = only +rebase = true + + +[push] + +autoSetupRemote = true +default = upstream +recursesubmodules = check + + +[rerere] + +enabled = true + + +[url "https://bitbucket.org/"] + +insteadOf = bb: + + +[url "https://github.com/"] + +insteadOf = gh: + + +[url "https://gitlab.com/"] + +insteadOf = gl: + + +[user] + +name = Alexander Hess +email = alexander@webartifex.biz +signingKey = alexander@webartifex.biz diff --git a/.config/git/ignore b/.config/git/ignore new file mode 100644 index 0000000..a0ed808 --- /dev/null +++ b/.config/git/ignore @@ -0,0 +1,6 @@ +# Generic temporary files +*.backup +*.bak +*.orig +*.temp +*.tmp diff --git a/.config/shell/aliases b/.config/shell/aliases index eaf280d..19a151c 100644 --- a/.config/shell/aliases +++ b/.config/shell/aliases @@ -5,3 +5,24 @@ # Manage the bare `git` repository in ~/ holding the dotfiles alias dotfiles='git --git-dir=$XDG_DATA_HOME/dotfiles --work-tree=$HOME' + + +# Integrate `git` +if _command_exists git; then + alias g='git' + + # Make all `git` aliases become shell aliases with a "g" prefix + for al in $(git aliases-internal); do + # Only "real" (i.e., short) aliases are created + [ ${#al} -lt 7 ] && eval "alias g$al='git $al'" + done + + # Check if a "main" branch exists in place of a "master" branch + git_main_branch() { + if [[ -n "$(git branch --list main)" ]]; then + echo "main" + else + echo "master" + fi + } +fi From 52914804a5681af9eaf75a0c9ed5d0bc99b577fe Mon Sep 17 00:00:00 2001 From: Alexander Hess Date: Sat, 30 Aug 2025 11:19:48 +0200 Subject: [PATCH 23/27] Add configuration for `vim` - Add `/.config/vim/vimrc + Configure basic stuff + Activate spell checks + Activate syntax highlighting and ruler + Show whitespace characters + Add various snippets for mouse handling, toggling line numbers, and search + Set `vim`-related directories inside ~/.config/vim and ~/.local/state/vim - Integrate extra settings for Python files in ~/.config/vim/after/ftplugin/python.vim - Add `vim` artifacts in ~/.config/git/ignore --- .config/git/ignore | 21 ++ .config/shell/env | 3 + .config/vim/after/ftplugin/python.vim | 65 ++++++ .config/vim/spell/.gitkeep | 0 .config/vim/vimrc | 308 ++++++++++++++++++++++++++ .local/state/vim/backup/.gitkeep | 0 .local/state/vim/swap/.gitkeep | 0 .local/state/vim/undo/.gitkeep | 0 8 files changed, 397 insertions(+) create mode 100644 .config/vim/after/ftplugin/python.vim create mode 100644 .config/vim/spell/.gitkeep create mode 100644 .config/vim/vimrc create mode 100644 .local/state/vim/backup/.gitkeep create mode 100644 .local/state/vim/swap/.gitkeep create mode 100644 .local/state/vim/undo/.gitkeep diff --git a/.config/git/ignore b/.config/git/ignore index a0ed808..ee17658 100644 --- a/.config/git/ignore +++ b/.config/git/ignore @@ -4,3 +4,24 @@ *.orig *.temp *.tmp + +# Vim +# Source: https://github.com/github/gitignore/blob/main/Global/Vim.gitignore +# +# Swap +[._]*.s[a-v][a-z] +!*.svg +[._]*.sw[a-p] +[._]s[a-rt-v][a-z] +[._]ss[a-gi-z] +[._]sw[a-p] +# Session +Session.vim +Sessionx.vim +# Temporary +.netrwhist +*~ +# Auto-generated tag files +tags +# Persistent undo +[._]*.un~ diff --git a/.config/shell/env b/.config/shell/env index 297742d..c25d2b8 100644 --- a/.config/shell/env +++ b/.config/shell/env @@ -18,11 +18,14 @@ export DOTFILES_DIR="$XDG_DATA_HOME/dotfiles" # also set in ~/.local/bin/instal # Generic shell configs +export EDITOR=vim export GPG_TTY=$(tty) export PAGER="less --chop-long-lines --ignore-case --LONG-PROMPT --no-init --status-column --quit-if-one-screen" export TERM=xterm-256color export TZ="Europe/Berlin" +export VISUAL=$EDITOR # Move common tools' config and cache files into XDG directories export LESSHISTFILE="$XDG_STATE_HOME/less/history" +export VIMINIT="source $XDG_CONFIG_HOME/vim/vimrc" diff --git a/.config/vim/after/ftplugin/python.vim b/.config/vim/after/ftplugin/python.vim new file mode 100644 index 0000000..0bf9971 --- /dev/null +++ b/.config/vim/after/ftplugin/python.vim @@ -0,0 +1,65 @@ +" Set the search path to the folder of the current file and its sub-folders +setlocal path=.,** +" Exclude Python's compiled files from searches +setlocal wildignore=*/__pycache__/*,*.pyc + + +" TODO: This does not work, maybe because we spell out imports +" as project-local imports (e.g. from lalib.fields import base)? +" Include *.py files imported as modules when searching. +" Source: https://www.youtube.com/watch?v=Gs1VDYnS-Ac +set include=^\\s*\\(from\\\|import\\)\\s*\\zs\\(\\S\\+\\s\\{-}\\)*\\ze\\($\\\|\ as\\) +" 1) import foo.bar -> foo/bar.py +" 2) from foo import bar as var -> foo/bar.py or foo.py +function! PyInclude(fname) + let parts = split(a:fname, ' import ') " 1) [foo.bar] or 2) [foo, bar] + let left = parts[0] " 1) foo.bar or 2) foo + if len(parts) > 1 + let right = parts[1] " only 2) bar + let joined = join([left, right], '.') + let fpath = substitute(joined, '\.', '/', 'g') . '.py' + let found = glob(fpath, 1) + if len(found) + return found + endif + endif + return substitute(left, '\.', '/', 'g') . '.py' +endfunction +setlocal includeexpr=PyInclude(v:fname) +setlocal define=^\\s*\\<\\(def\\|class\\)\\> + + +" Number of spaces used for each step of auto-indent +set shiftwidth=4 + +" Number of spaces a counts for in the file +set tabstop=4 + +" Number of spaces a counts for in editing mode +set softtabstop=4 + +" Change s into spaces +set expandtab + +" Copy indent from previous line when starting a new line +set autoindent + +" Use indent according to the syntax of the open file +set smartindent + +" Auto-wrap lines after 88 characters, which is PEP8's limit plus 10%, +" a more relaxed boundary which occasionally may be used +set textwidth=88 + + +" Make column 80 red to indicate PEP8's maximum allowed line length +set colorcolumn=80 + +" Additionally, give every character beyond 80 columns a red background +highlight ColorColumn ctermbg=DarkRed +call matchadd('ColorColumn', '\%80v', 100) +match ErrorMsg '\%>80v.\+' + + +" Show line numbers by default for .py files +let g:show_numbers=1 diff --git a/.config/vim/spell/.gitkeep b/.config/vim/spell/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/.config/vim/vimrc b/.config/vim/vimrc new file mode 100644 index 0000000..ccaae72 --- /dev/null +++ b/.config/vim/vimrc @@ -0,0 +1,308 @@ +" Use VIM improved mode +set nocompatible + + +" Set environment variables for convenient usage +let $RC="$XDG_CONFIG_HOME/vim/vimrc" +let $RTP=split(&runtimepath, ',')[0] + +" Disable VIM's startup message +set shortmess+=I + +" Number of remembered undo steps +set undolevels=1000 + + +" Detect the file's type and load the corresponding plugin and indent files +filetype plugin indent on + +" Enable syntax highlighting +syntax on + + +" Allow backspace to delete characters in insert mode +" beyond the start of the insertion and end of lines +set backspace=start,eol,indent + + +" Hide buffers instead of closing them, wich means we can have +" unwritten changes to a file and open a new one with :e, +" without having to write the changes first +set hidden + + +" Set to the folder of the current file and its sub-folders +" (this may need to be adapted for large project folders) +set path=.,** + + +" Store all vim-related working files in the ~/.local/state/vim folder +set viminfo+=n$XDG_STATE_HOME/vim/viminfo +" Use dedicated folders to store temporary backup, swap, and undo files +" (the // means that VIM adapts names automatically to avoid duplicates) +set backupdir=$XDG_STATE_HOME/vim/backup// +set directory=$XDG_STATE_HOME/vim/swap// +set undodir=$XDG_STATE_HOME/vim/undo// + +" To disable any of the temporary files, uncomment one of the following +" set nobackup +" set nowritebackup +" set noswapfile +" set noundofile + + +set runtimepath+=$XDG_CONFIG_HOME/vim,$XDG_CONFIG_HOME/vim/after,$VIM,$VIMRUNTIME + + +" Show the filename in the terminal window's title bar +set title + + +" Do not wrap lines when showing text +set nowrap + +" This avoids a problem of loosing data upon insertion in old VIMs +set wrapmargin=0 + + +" Show spelling mistakes (in English) in italics +set spelllang=en_us,de_de +set spell +hi clear SpellBad +hi clear SpellCap +hi clear SpellRare +hi clear SpellLocal +hi SpellBad cterm=italic + + +" Show whitespace characters +set listchars=tab:»»,extends:›,precedes:‹,nbsp:·,trail:· +set list + + +" Highlight matching brackets +set showmatch +set matchpairs+=<:> + + +" Always show the status bar at the bottom +set laststatus=2 + +" Show current position in status bar +set ruler +set rulerformat=%=%l/%L\ %c\ (%P) + +" Show commands in status bar +set showcmd + +" If in non-normal mode, show the mode in the status bar +set showmode + +" Show a dialog to save changes instead of an error message +set confirm + +" Auto-clear messages from the status bar +autocmd CursorHold * :echo + + +" Better copy and paste behavior +set pastetoggle= +set clipboard=unnamed + + +" Make : and ; synonyms +nnoremap ; : + + +" Use \ and as the keys and lower time to enter key sequences +let mapleader='\' +set timeoutlen=750 +" Make the in visual mode as well +nmap \ +vmap \ + + +" Q normally goes into Ex mode +nmap Q + + +" Get sudo rights when writing a buffer with w!! +cnoremap w!! w !sudo tee % >/dev/null + + +" Fix mouse issues with Alacritty terminal +" Source: https://wiki.archlinux.org/title/Alacritty#Mouse_not_working_properly_in_Vim +set ttymouse=sgr + + +" Enable the mouse for selections, including a toggle for this mode +set mouse=a +let g:mouse_enabled=1 +function ToggleMouse() + if g:mouse_enabled == 1 + echo "Mouse OFF" + set mouse= + let g:mouse_enabled=0 + else + echo "Mouse ON" + set mouse=a + let g:mouse_enabled=1 + endif +endfunction +noremap m :call ToggleMouse() + + +" Enable toggling between +" - showing and hiding line numbers (l) +" - absolute and relative numbers (a) in normal mode +" (default: relative line numbering) +let g:show_numbers=0 +let g:show_absolute_numbers=0 +function! ShowLineNumbers() + if g:show_numbers == 1 + set number + if g:show_absolute_numbers + set norelativenumber + else + set relativenumber + endif + else + set nonumber + set norelativenumber + endif +endfunction +function! ToggleLineNumbers() + if g:show_numbers == 1 + let g:show_numbers=0 + else + let g:show_numbers=1 + endif + call ShowLineNumbers() +endfunction +function! ToggleAbsoluteAndRelativeLineNumbers() + if g:show_absolute_numbers == 1 + let g:show_absolute_numbers=0 + else + let g:show_absolute_numbers=1 + endif + call ShowLineNumbers() +endfunction +" Auto-switch between absolute and relative numbering when switching modes +" (insert mode always shows absolute numbers when numbers are shown) +augroup numbertoggle + autocmd! + autocmd BufEnter,FocusGained,InsertLeave * call ShowLineNumbers() + autocmd BufLeave,FocusLost,InsertEnter * if g:show_numbers == 1 | set number | set norelativenumber | endif +augroup END +" Key bindings +nnoremap l :call ToggleLineNumbers() +nnoremap a :call ToggleAbsoluteAndRelativeLineNumbers() + + +" Show all possible matches above command-line when tab completing +set wildmenu +set wildmode=longest:full,full + + +" Highlight search results +set hlsearch + +" Shortcut to remove current highlighting +nnoremap h :nohlsearch + +" Move cursor to result while typing immediately +set incsearch + +" Ignore case when searching +set ignorecase + +" Upper case search term => case sensitive search +set smartcase + +" Highlight the next match in red for 0.25 seconds +function! HighlightNext() + let [bufnum, lnum, col, off] = getpos('.') + let matchlen = strlen(matchstr(strpart(getline('.'),col-1),@/)) + let target_pat = '\c\%#\%('.@/.'\)' + let ring = matchadd('ErrorMsg', target_pat, 101) + redraw + exec 'sleep ' . float2nr(250) . 'm' + call matchdelete(ring) + redraw +endfunction +nnoremap n n:call HighlightNext() +nnoremap N N:call HighlightNext() + + +" Make w safe the buffer in normal mode +" and save the buffer in all modes +" (the latter disables making VIM a background job; +" is useful to have as w does not work in INSERT mode) +nnoremap w :update +nnoremap :update +vnoremap :update +inoremap :update + +" q quits VIM +nnoremap q :quit + +" Easier switching between tabs +noremap , :tabprevious +noremap . :tabnext + +" Arrow keys and either (un)indent lines or move them up or down +" (same for blocks of lines in visual mode) +nnoremap << +nnoremap >> +nnoremap :m-2 +nnoremap :m+ +nmap +nmap +nmap +nmap +vnoremap >gv +vnoremap :m'<-2gv=gv +vnoremap :m'>+1gv=gv +vmap +vmap +vmap +vmap + +" Make (un)indent lines +nnoremap >> +nnoremap << +inoremap >> +inoremap << +vnoremap >gv +vnoremap s :sort + +" Switch two words, just like xp switches two characters +noremap xp dwElp + + +" Auto-reload a file that was changed by some other process +" if the buffer has not yet been changed in the meantime +set autoread +augroup checktime + autocmd! + autocmd BufEnter * silent! checktime + autocmd CursorHold * silent! checktime + autocmd CursorHoldI * silent! checktime + autocmd CursorMoved * silent! checktime + autocmd CursorMovedI * silent! checktime +augroup END + + +" Auto-reload ~/.config/vim/vimrc +augroup vimrc + autocmd! BufWritePost $RC source % | redraw +augroup END +" Key binding to reload ~/.vim/vimrc manually +nnoremap rc :so $RC diff --git a/.local/state/vim/backup/.gitkeep b/.local/state/vim/backup/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/.local/state/vim/swap/.gitkeep b/.local/state/vim/swap/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/.local/state/vim/undo/.gitkeep b/.local/state/vim/undo/.gitkeep new file mode 100644 index 0000000..e69de29 From 739ef9148f36f74e098e1671ee4fb066221620c1 Mon Sep 17 00:00:00 2001 From: Alexander Hess Date: Sat, 30 Aug 2025 11:45:56 +0200 Subject: [PATCH 24/27] Add configuration for `bat` --- .config/bat/config | 7 +++++++ .config/shell/env | 1 + 2 files changed, 8 insertions(+) create mode 100644 .config/bat/config diff --git a/.config/bat/config b/.config/bat/config new file mode 100644 index 0000000..5236fce --- /dev/null +++ b/.config/bat/config @@ -0,0 +1,7 @@ +--theme="TwoDark" + +--style="numbers,changes,header" + +--map-syntax ".bash_history:Bourne Again Shell (bash)" +--map-syntax ".flake8:INI" +--map-syntax "poetry.lock:TOML" diff --git a/.config/shell/env b/.config/shell/env index c25d2b8..f064294 100644 --- a/.config/shell/env +++ b/.config/shell/env @@ -27,5 +27,6 @@ export VISUAL=$EDITOR # Move common tools' config and cache files into XDG directories +export BAT_CONFIG_PATH="$XDG_CONFIG_HOME/bat/config" export LESSHISTFILE="$XDG_STATE_HOME/less/history" export VIMINIT="source $XDG_CONFIG_HOME/vim/vimrc" From e7e42b93ef65edc3b5d14ecb0b90c1e13c758c03 Mon Sep 17 00:00:00 2001 From: Alexander Hess Date: Sat, 30 Aug 2025 11:53:13 +0200 Subject: [PATCH 25/27] Add configuration for `psql` --- .config/psql/psqlrc | 48 ++++++++++++++++++++++++++++++++++++++ .config/shell/env | 1 + .local/state/psql/.gitkeep | 0 3 files changed, 49 insertions(+) create mode 100644 .config/psql/psqlrc create mode 100644 .local/state/psql/.gitkeep diff --git a/.config/psql/psqlrc b/.config/psql/psqlrc new file mode 100644 index 0000000..e65bdc3 --- /dev/null +++ b/.config/psql/psqlrc @@ -0,0 +1,48 @@ +-- `psql` executes the commands in this file creating output +-- => This flag hides that and is unset again at the bottom +\set QUIET 1 + + +-- Show verbose error messages +\set VERBOSITY verbose + + +-- Use normal "table" format by default +-- and "expanded table" with lots of columns +\x auto + + +-- By default, `NULL`s show up as empty spaces, +-- which may be confused with empty strings +-- => Show "NULL" instead for clarity +\pset null 'NULL' + + +-- Ignore errors in interactive sessions +-- but not when executing scripts +\set ON_ERROR_ROLLBACK interactive + + +-- Upper case SQL keywords +\set COMP_KEYWORD_CASE upper + + +-- Make VI the default editor +\set EDITOR vi + + +-- Use separate history files per database +-- and keep them in one folder +\set HISTFILE ~/.local/state/psql/history- :DBNAME + + +-- Don't store the same SQL statement repeatedly +\set HISTCONTROL ignoredups + + +-- Make all queries display query times +\timing + + +-- Unset the flag set at the top of this file +\unset QUIET diff --git a/.config/shell/env b/.config/shell/env index f064294..76326ed 100644 --- a/.config/shell/env +++ b/.config/shell/env @@ -29,4 +29,5 @@ export VISUAL=$EDITOR # Move common tools' config and cache files into XDG directories export BAT_CONFIG_PATH="$XDG_CONFIG_HOME/bat/config" export LESSHISTFILE="$XDG_STATE_HOME/less/history" +export PSQLRC="$XDG_CONFIG_HOME/psql/psqlrc" export VIMINIT="source $XDG_CONFIG_HOME/vim/vimrc" diff --git a/.local/state/psql/.gitkeep b/.local/state/psql/.gitkeep new file mode 100644 index 0000000..e69de29 From 651b161fe12173c96aeba6b425406f36ce1aaa75 Mon Sep 17 00:00:00 2001 From: Alexander Hess Date: Sat, 30 Aug 2025 11:26:33 +0200 Subject: [PATCH 26/27] Add public `ssh` keys ... ... to allow other people to give me access to their systems --- .ssh/authorized_keys | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .ssh/authorized_keys diff --git a/.ssh/authorized_keys b/.ssh/authorized_keys new file mode 100644 index 0000000..b9c64de --- /dev/null +++ b/.ssh/authorized_keys @@ -0,0 +1,5 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIN0GVKtgpgzpdf7E6e2vCytDSa2zPSgZ+8fAKCOotugH alexander@webartifex.biz (getraenkemarkt.io) +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMRDaWrT2hH7BOV4Zv1ctVGqwfeqkssnHklRXBmng6Wr alexander@webartifex.biz (laptop1.getraenkemarkt.io) +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOhhfx063dGoaE62cbdyGL3kp1AIovWFojQGNdqUpxr8 alexander@webartifex.biz (laptop2.getraenkemarkt.io) +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGGNCrFt/gUbBHVqhthBuRmdDH6yS30+GGcCnARSzg+q alexander@webartifex.biz (workstation1.getraenkemarkt.io) +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKfaK5LUp7ghZLfl7urwQx+l+m/Vm7iksz8deGx4L5sD alexander@webartifex.biz (workstation2.getraenkemarkt.io) From 82d15915515ed2c0dbe7891acb8f049a06e9b7a2 Mon Sep 17 00:00:00 2001 From: Alexander Hess Date: Sat, 30 Aug 2025 12:09:41 +0200 Subject: [PATCH 27/27] Add configuration for `python` Move Python's history into ~/.local/state/python --- .config/python/startup.py | 53 ++++++++++++++++++++++++++++++++++++ .config/shell/env | 2 ++ .local/state/python/.gitkeep | 0 3 files changed, 55 insertions(+) create mode 100644 .config/python/startup.py create mode 100644 .local/state/python/.gitkeep diff --git a/.config/python/startup.py b/.config/python/startup.py new file mode 100644 index 0000000..9c1a938 --- /dev/null +++ b/.config/python/startup.py @@ -0,0 +1,53 @@ +"""Move Python's history file to "$XDG_STATE_HOME/python/history".""" + +import atexit +import os +import readline +import sys + + +# For Python 3.13+ let `$PYTHON_HISTORY` handle it +if sys.version_info >= (3, 13): + sys.exit(0) + + +# For Python 2, do nothing +try: + import pathlib +except ImportError: + sys.exit(0) + + +if readline.get_current_history_length() == 0: + state_home = os.environ.get("XDG_STATE_HOME") + + if state_home is None: + state_home = pathlib.Path.home() / ".local" / "state" + else: + state_home = pathlib.Path(state_home) + + history_path = state_home / "python" / "history" + history_path.parent.mkdir(parents=True, exist_ok=True) + + history_location = str(history_path) + + if history_path.is_dir(): + msg = history_location + " must not be a directory" + raise OSError(msg) + + try: + readline.read_history_file(history_location) + except OSError: # Non existent + pass + + readline.set_auto_history() + readline.set_history_length(99999) + + def write_history(): + try: + readline.write_history_file(history_location) + except OSError: + pass + + atexit.register(write_history) + diff --git a/.config/shell/env b/.config/shell/env index 76326ed..b1f9a2d 100644 --- a/.config/shell/env +++ b/.config/shell/env @@ -30,4 +30,6 @@ export VISUAL=$EDITOR export BAT_CONFIG_PATH="$XDG_CONFIG_HOME/bat/config" export LESSHISTFILE="$XDG_STATE_HOME/less/history" export PSQLRC="$XDG_CONFIG_HOME/psql/psqlrc" +export PYTHON_HISTORY="$XDG_STATE_HOME/python/history" +export PYTHONSTARTUP="$XDG_CONFIG_HOME/python/startup.py" export VIMINIT="source $XDG_CONFIG_HOME/vim/vimrc" diff --git a/.local/state/python/.gitkeep b/.local/state/python/.gitkeep new file mode 100644 index 0000000..e69de29