dotfiles

My personal shell configs and stuff
git clone git://git.alex.balgavy.eu/dotfiles.git
Log | Files | Refs | Submodules | README | LICENSE

commit b764aa522417b9a44d35fe34f83bee4e8521e201
parent 068499979c701e7c847b205fe5c824d560208b86
Author: Alex Balgavy <a.balgavy@gmail.com>
Date:   Mon,  4 Nov 2019 12:31:46 -0500

conf: multi-level mappings and other bells & whistles

Former-commit-id: 3815c4ee203e304531281eaca84bcee4c97e12b5
Diffstat:
Mdot.map | 4++++
Mscripts/conf | 57++++++++++++++++++++++++++++++++++++++++++++-------------
2 files changed, 48 insertions(+), 13 deletions(-)

diff --git a/dot.map b/dot.map @@ -1,3 +1,5 @@ +# Mappings for your dotfiles + # The format of this file is: # - lines starting with '#' are comments # - whitespace is ignored, except inside a mapping definition @@ -20,6 +22,8 @@ # vim/autoload/script1.vim => ~/.vim/autoload/script1.vim # vim/autoload/script2.vim => ~/.vim/autoload/script2.vim # tmux/tmux.conf => ~/.tmux.conf +# +# (the arrows show the symbolic links) # When linking/unlinking, names don't have to be complete. # You can also just provide the name of the top directory, conf will figure out the rest. diff --git a/scripts/conf b/scripts/conf @@ -1,6 +1,5 @@ #!/usr/bin/env bash -# TODO: handle multiple nesting levels, convert to posix shell - +# TODO: convert to posix shell # Set the dir for your dotfiles, mine comes from the environment DOTFILES="${DOTFILES}" @@ -11,11 +10,19 @@ die() { echo "$1" >&2 exit 1 } +get_bash_version() { + echo "${BASH_VERSION}" | cut -d'.' -f1 +} + +[ "$(get_bash_version)" -ge 4 ] || die "Requires Bash >= 4" # Don't want $DOTFILES expansion in the message # shellcheck disable=SC2016 [ -z "${DOTFILES}" ] && die '$DOTFILES variable not set.' cd "${DOTFILES}" || die "Can't read ${DOTFILES}" +[ -f "${mapfile}" ] || die "Mapfile ${mapfile} does not exist in $(pwd)" + + do_link() { if [ -e "$2" ]; then @@ -27,26 +34,25 @@ do_link() { mv "$2" "$2.bak" fi fi + mkdir -vp "${2%/*}" ln -svf "$(pwd)/$1" "$2" } parse_mapfile() { - if [ ! -f "$1" ]; then - die "Mapfile $1 does not exist." - fi - local nestdir="" local lineno=1 + local nestlevel=0 homedir="$(echo -n "${HOME}" | tr -d '\n\r')" while read -r map; do if [ -n "${map}" ] && [[ ! "${map}" == "#"* ]]; then - IFS=" " read -r -a mapping <<< "$(echo -n "${map}" | sed -e 's/^ *- /-/' -e "s:~:${homedir}:" | awk -F ': ' '{ print $1 " " $2 }')" + IFS=" " read -r -a mapping <<< "$(echo -n "${map}" | sed -e 's/^ *-* /-/' -e "s:~:${homedir}:" | awk -F ': ' '{ print $1 " " $2 }')" # Top level items if [[ ! "${mapping[0]}" == "-"* ]]; then nestdir="" + nestlevel=0 if [ -z "${mapping[1]}" ]; then # nestdir nestdir="${mapping[0]/://}" @@ -58,10 +64,27 @@ parse_mapfile() { mappings["${nestdir}${mapping[0]}"]="${mapping[1]}" fi else - if [ ! -e "${nestdir}${mapping[0]/-/}" ]; then - die "error in mapfile: ${nestdir}${mapping[0]/-/} does not exist (line ${lineno})" + levels="$(count_nestlevels "${mapping[0]}")" + pth="$(echo "${mapping[0]}" | sed -e 's/^-*//g' -e 's/://')" + if [ "${levels}" -lt "${nestlevel}" ]; then + while [ "${levels}" -lt "${nestlevel}" ]; do + nestdir="${nestdir%/*/}/" + ((nestlevel--)) + done + [ "${nestdir}" = "/" ] && nestdir="" + elif [ "${levels}" -gt "${nestlevel}" ]; then + while [ "${levels}" -gt "${nestlevel}" ]; do + ((nestlevel++)) + done + fi + if [ -z "${mapping[1]}" ]; then + nestdir="${nestdir}${pth}/" + else + if [ ! -e "${nestdir}${mapping[0]/-/}" ]; then + die "error in mapfile: ${nestdir}${pth} does not exist (line ${lineno})" + fi + mappings["${nestdir}${pth}"]="${mapping[1]}" fi - mappings["${nestdir}${mapping[0]/-/}"]="${mapping[1]}" fi fi ((lineno++)) @@ -111,9 +134,15 @@ unlink_specific(){ fi } list_mappings() { + mapstr="" for f in "${!mappings[@]}"; do - echo "${f} => ${mappings[${f}]}"; + mapstr="${mapstr}${f} => ${mappings[${f}]}\n"; done + + echo -e "${mapstr}" | sort +} +count_nestlevels() { + echo -n "$1" | sed 's/^\([-]*\).*/\1/' | tr -d '\n' | wc -m | tr -d ' ' } declare -A mappings @@ -125,6 +154,7 @@ while (( "$#" )); do case "$1" in -l|--list) parse_mapfile "./${mapfile}" + echo "Mappings:" list_mappings exit 0 ;; @@ -148,6 +178,7 @@ while (( "$#" )); do -e|--edit) # $EDITOR is an environment variable # shellcheck disable=SC2154 + echo "Opening ${mapfile} with ${EDITOR}" "${EDITOR}" "${DOTFILES}/${mapfile}" exit 0 ;; @@ -192,7 +223,7 @@ esac parse_mapfile "./${mapfile}" if [ "${link_mode}" -eq 1 ]; then if [ $# -eq 0 ]; then - read -srp "Link all dotfiles?" -n 1 -s conf + read -srp "Link all dotfiles? [Y/n]" -n 1 -s conf case "${conf}" in Y|y) echo @@ -208,7 +239,7 @@ if [ "${link_mode}" -eq 1 ]; then fi elif [ "${unlink_mode}" -eq 1 ]; then if [ $# -eq 0 ]; then - read -srp "Unlink all dotfiles?" -n 1 -s conf + read -srp "Unlink all dotfiles? [Y/n]" -n 1 -s conf case "${conf}" in Y|y) echo