diff --git a/ansible/roles/dotfiles_common/tasks/main.yml b/ansible/roles/dotfiles_common/tasks/main.yml new file mode 100644 index 0000000..136655a --- /dev/null +++ b/ansible/roles/dotfiles_common/tasks/main.yml @@ -0,0 +1,16 @@ +--- +- name: Copy .bashrc + ansible.builtin.copy: + src: "{{ playbook_dir }}/../dotfiles/common/.bashrc" + dest: "{{ user_home }}/.bashrc" + owner: "{{ username }}" + group: "{{ user_group }}" + mode: "0644" + +- name: Copy .bash_profile + ansible.builtin.copy: + src: "{{ playbook_dir }}/../dotfiles/common/.bash_profile" + dest: "{{ user_home }}/.bash_profile" + owner: "{{ username }}" + group: "{{ user_group }}" + mode: "0644" diff --git a/ansible/site.yml b/ansible/site.yml index bbaecd2..7c102c6 100644 --- a/ansible/site.yml +++ b/ansible/site.yml @@ -1,4 +1,10 @@ --- +- hosts: all + become: true + + roles: + - dotfiles_common + - hosts: void become: true diff --git a/dotfiles/common/.bash_profile b/dotfiles/common/.bash_profile new file mode 100644 index 0000000..6223493 --- /dev/null +++ b/dotfiles/common/.bash_profile @@ -0,0 +1,10 @@ +# .bash_profile + +[ -f $HOME/.profile ] && . $HOME/.profile + +# Get the aliases and functions +[ -f $HOME/.bashrc ] && . $HOME/.bashrc + +if [ -z "$DISPLAY" ] && [ "$(tty)" = "/dev/tty1" ]; then + exec startx +fi diff --git a/dotfiles/common/.bashrc b/dotfiles/common/.bashrc new file mode 100644 index 0000000..c56cc4b --- /dev/null +++ b/dotfiles/common/.bashrc @@ -0,0 +1,316 @@ +# ========================= +# Portable Bash config +# Target: Void Linux + FreeBSD +# ========================= + +# Exit if not interactive +[[ $- != *i* ]] && return + +# --- environment detection +case "$(uname -s)" in + Linux) PLATFORM="linux" ;; + FreeBSD) PLATFORM="freebsd" ;; + *) PLATFORM="other" ;; +esac + +export PLATFORM + +# --- history +HISTSIZE=10000 +HISTFILESIZE=20000 +HISTCONTROL=ignoredups:erasedups +HISTIGNORE='ls:ll:la:l:pwd:exit:clear:history' +HISTTIMEFORMAT= +shopt -s histappend +shopt -s checkwinsize + +__history_sync() { + history -a + history -c + history -r +} + +# --- shell options +set -o emacs +shopt -s cmdhist + +# --- PATH +[ -d "$HOME/.local/bin" ] && PATH="$HOME/.local/bin:$PATH" +[ -d "$HOME/bin" ] && PATH="$HOME/bin:$PATH" +export PATH + +# ========================= +# Aliases (portable) +# ========================= + +if ls --color=auto >/dev/null 2>&1; then + alias ls='ls --color=auto' +else + alias ls='ls -G' +fi + +alias l='ls' +alias ll='ls -lh' +alias la='ls -lah' + +if grep --color=auto "" /dev/null >/dev/null 2>&1; then + alias grep='grep --color=auto' +fi + +alias ..='cd ..' +alias ...='cd ../..' +alias cls='clear' + +alias cp='cp -i' +alias mv='mv -i' +alias rm='rm -i' + +# Git +alias g='git' +alias ga='git add' +alias gb='git branch' +alias gc='git commit' +alias gca='git commit -a' +alias gco='git checkout' +alias gd='git diff' +alias gl='git pull' +alias gp='git push' +alias gs='git status -sb' +alias glog='git log --oneline --decorate --graph -20' + +# ========================= +# Git prompt helpers +# ========================= + +__git_branch() { + git rev-parse --is-inside-work-tree >/dev/null 2>&1 || return 1 + command git symbolic-ref --quiet --short HEAD 2>/dev/null && return + command git rev-parse --short HEAD 2>/dev/null && return + return 1 +} + +__git_flags() { + git rev-parse --is-inside-work-tree >/dev/null 2>&1 || return 1 + + local flags="" + git diff --no-ext-diff --quiet --exit-code 2>/dev/null || flags="${flags}*" + git diff --cached --no-ext-diff --quiet --exit-code 2>/dev/null || flags="${flags}+" + [ -n "$(git ls-files --others --exclude-standard 2>/dev/null)" ] && flags="${flags}?" + + printf '%s' "$flags" +} + +# ========================= +# Colors +# ========================= + +if [ -t 1 ]; then + C_RESET='\[\033[0m\]' + C_USER='\[\033[1;97m\]' + C_HOST='\[\033[38;5;250m\]' + C_PATH='\[\033[1;96m\]' + C_GIT='\[\033[38;5;197m\]' + C_GIT_FLAG='\[\033[38;5;204m\]' + C_VENV='\[\033[38;5;177m\]' + C_CONT='\[\033[38;5;208m\]' + C_OK='\[\033[38;5;46m\]' + C_ERR='\[\033[38;5;196m\]' + C_DIM='\[\033[38;5;240m\]' +else + C_RESET='' + C_USER='' + C_HOST='' + C_PATH='' + C_GIT='' + C_GIT_FLAG='' + C_VENV='' + C_CONT='' + C_OK='' + C_ERR='' + C_DIM='' +fi + +# ========================= +# Prompt helpers +# ========================= + +__prompt_git() { + local branch flags + + branch="$(__git_branch)" || return 0 + flags="$(__git_flags)" + + if [ -n "$flags" ]; then + printf ' %s<%s%s:%s%s>%s' \ + "$C_GIT" "$branch" "$C_DIM" "$C_GIT_FLAG" "$flags" "$C_RESET" + else + printf ' %s<%s>%s' "$C_GIT" "$branch" "$C_RESET" + fi +} + +__prompt_venv() { + [ -n "${VIRTUAL_ENV-}" ] || return 0 + printf ' %s(%s)%s' "$C_VENV" "${VIRTUAL_ENV##*/}" "$C_RESET" +} + +__prompt_container() { + local marker="" + + if [ -f /run/.containerenv ]; then + marker="ctr" + elif [ -f /.dockerenv ]; then + marker="docker" + elif [ -n "${container-}" ]; then + marker="$container" + elif [ -n "${debian_chroot-}" ]; then + marker="$debian_chroot" + fi + + [ -n "$marker" ] || return 0 + printf ' %s[%s]%s' "$C_CONT" "$marker" "$C_RESET" +} + +# ========================= +# Prompt +# ========================= + +__set_prompt() { + local last_status="$1" + local host_part symbol status_color + + if [ -n "${SSH_CONNECTION-}" ] || [ -n "${SSH_CLIENT-}" ]; then + host_part="${C_USER}\u${C_DIM}@${C_HOST}\h${C_RESET}" + else + host_part="${C_USER}\u${C_RESET}" + fi + + if [ "${EUID:-$(id -u)}" -eq 0 ]; then + symbol="#" + else + symbol="›" + fi + + if [ "$last_status" -eq 0 ]; then + status_color="${C_OK}" + else + status_color="${C_ERR}" + fi + + PS1="${host_part}${C_DIM}:${C_RESET}${C_PATH}\w${C_RESET}$(__prompt_venv)$(__prompt_container)$(__prompt_git) ${status_color}${symbol}${C_RESET} " +} + +__prompt_command() { + local last_status=$? + __history_sync + __set_prompt "$last_status" +} + +PROMPT_COMMAND="__prompt_command" + +# ========================= +# Readline / history search +# ========================= + +bind '"\e[A": history-search-backward' +bind '"\e[B": history-search-forward' + +bind '"\e[1;5C": forward-word' +bind '"\e[1;5D": backward-word' +bind '"\e[5C": forward-word' +bind '"\e[5D": backward-word' + +# ========================= +# fzf history on Ctrl-r +# ========================= + +if command -v fzf >/dev/null 2>&1; then + __fzf_history() { + local selected history_data + + if command -v tac >/dev/null 2>&1; then + history_data="$( + builtin history \ + | sed 's/^[[:space:]]*[0-9][0-9]*[[:space:]]*//' \ + | awk '!seen[$0]++' \ + | awk 'NF' \ + | tac + )" + else + history_data="$( + builtin history \ + | sed 's/^[[:space:]]*[0-9][0-9]*[[:space:]]*//' \ + | awk '!seen[$0]++' \ + | awk 'NF' \ + | tail -r + )" + fi + + selected="$(printf '%s\n' "$history_data" | fzf --height 40% --layout=reverse --border --prompt='history> ')" || return + + READLINE_LINE=$selected + READLINE_POINT=${#READLINE_LINE} + } + + bind -x '"\C-r":__fzf_history' +fi + +# ========================= +# Completion +# ========================= + +for bc in \ + /usr/share/bash-completion/bash_completion \ + /usr/local/share/bash-completion/bash_completion \ + /etc/bash_completion +do + if [ -r "$bc" ]; then + . "$bc" + break + fi +done + +# ========================= +# Portable helpers +# ========================= + +mkcd() { + [ $# -eq 1 ] || return 1 + mkdir -p -- "$1" && cd -- "$1" || return +} + +extract() { + [ $# -eq 1 ] || { + printf 'usage: extract \n' >&2 + return 1 + } + + [ -f "$1" ] || { + printf 'extract: file not found: %s\n' "$1" >&2 + return 1 + } + + case "$1" in + *.tar.bz2|*.tbz2) tar xjf "$1" ;; + *.tar.gz|*.tgz) tar xzf "$1" ;; + *.tar.xz|*.txz) tar xJf "$1" ;; + *.tar) tar xf "$1" ;; + *.bz2) bunzip2 "$1" ;; + *.gz) gunzip "$1" ;; + *.xz) unxz "$1" ;; + *.zip) unzip "$1" ;; + *.7z) 7z x "$1" ;; + *) printf 'extract: unsupported archive: %s\n' "$1" >&2; return 1 ;; + esac +} + +# ========================= +# OS-specific small touches +# ========================= + +if [ "$PLATFORM" = "freebsd" ]; then + alias df='df -h' + alias du='du -h' +elif [ "$PLATFORM" = "linux" ]; then + alias df='df -h' + alias du='du -h' +fi