#!/bin/bash XL_PRODUCT="Vim Note System" XL_VER="1.0a2" # Environment Constants readonly VNS_STORE="$HOME/.local/vns" readonly VNS_KEYFILE="$VNS_STORE/.pubkey" readonly IFS=$'\n\t' set -euo pipefail readonly VNS_RED_COLOR='\033[1;31m' readonly VNS_YELLOW_COLOR='\033[1;33m' readonly VNS_RESET_COLOR='\033[0m' # Erroneous Exit Constants # Invocation Errors readonly VNS_ERR_NO_STORE=5 # The vns store needs to be initialized readonly VNS_ERR_NO_OPTS=10 # No mode argument was specified readonly VNS_ERR_NS_ARGS=11 # The specified mode requires an argument readonly VNS_ERR_NO_EDTR=15 # No editor specified in environment # Dependency Errors readonly VNS_ERR_DEPS=20 # Base error - add the following codes readonly VNS_ERR_NO_gpg2=1 # GPG is not installed readonly VNS_ERR_NO_tree=2 # Tree is not installed readonly VNS_ERR_NO_git=3 # Git is not installed # Global Variables typeset -a VNS_ACTION=("") typeset -a MISSING_DEPS typeset -i VNS_EXIT=0 declare VNS_PUBKEY= # Function Definitions # vns_index Print the $1th index of array ${2[@]} (friendly to -euo) # vns_printError Prints an error message # vns_NoteHeader Prints standard note header to stdout # vns_checkDeps Checks the system for required dependencies # vns_checkStore Checks if $VNS_STORE exists # vns_sanityCheck Wrapper for vns_checkDeps and vns_checkStore # ---- # vns_initStore Initializes the VNS Store ( -i) # vns_printHelp Prints help page ( -h) # vns_list Lists all notes in `tree` format ( *) # vns_create Creates note; calls vns_edit() ( -c) # vns_edit Decrypts note to /tmp, calls editor, re-encrypts note ( -e) # vns_print Prints note to stdout ( -p) # vns_rm Deletes note from store ( -d) # vns_gitPassthrough Passes through all instructions to git (git) function vns_index(){ echo "$@" | awk -v i="$(($1+1))" '{print $i}' } function vns_printError(){ printf "$VNS_RED_COLOR!$VNS_RESET_COLOR - %s\n" "$@" } function vns_NoteHeader(){ printf "%s\n%s\n" "Title:" "Date:" } function vns_checkDeps(){ local VNS_RETURN="true"; for DEP in "${VNS_DEPS[@]}"; do if test ! -e "$(which "$DEP" 2>/dev/null)"; then MISSING_DEPS+=("$DEP") VNS_RETURN="false"; fi done "$VNS_RETURN"; } function vns_checkStore(){ if [ -d "$VNS_STORE" ]; then true; else false; fi } function vns_sanityCheck { if ! vns_checkDeps; then VNS_EXIT="$VNS_ERR_DEPS" for DEP in "${MISSING_DEPS[@]}"; do local VNS_DEP_EC="\$ERR_NO_$DEP" vns_printError "Dependency %s not in path." "$DEP"; VNS_EXIT+=${!VNS_DEP_EC} done fi if [ -r "$VNS_STORE/.pubkey" ]; then VNS_PUBKEY="$(cat "$VNS_STORE/.pubkey")" elif ! vns_checkStore; then if [ "$(vns_index "1" "${VNS_ACTION[@]}")" != "vns_initStore" ]; then vns_printError "The vns store does not exist." printf " - %s\n" "Please run \`vns -i [gpg-key]\` to initialize vns." VNS_EXIT="$VNS_ERR_NO_STORE" fi fi } #---- function vns_initStore { mkdir -p "$VNS_STORE" echo "$@" | awk '{print $1}' > "$VNS_KEYFILE" } function vns_printHelp(){ printf "%s" "usage: vns [-cedlp] " printf "\n%s" " vns -i " printf "\n%s" " vns -h" printf "\n%s%s%s" "usage: vns " "git" " ..." printf "\n%s" " -c | --create : Create note" printf "\n%s" " -d | --delete : Delete note" printf "\n%s" " -e | --edit : Open note for editing" printf "\n%s" " -h | --help : Display this message" printf "\n%s" " -i | --init : Write default config and initalize VNS store" printf "\n%s" " -l | --list : List all notes in NOTEBOOK" printf "\n%s" " -p | --print : Print note to console" printf "\n\n" } function vns_list(){ # Print the tree tree -C --noreport --prune "$VNS_STORE/$(vns_index "1" "$@")" | tail -n +2 | sed s/\.gpg//g } function vns_rm(){ local readonly VNS_NOTE; VNS_NOTE="$VNS_STORE/$(vns_index "1" "$@").gpg" echo "Deleting $VNS_NOTE" rm -f "$VNS_NOTE" } function vns_create(){ local readonly VNS_NOTE; VNS_NOTE="$VNS_STORE/$(vns_index "1" "$@").gpg" # Make sure the note doesn't already exist if [ -r "$VNS_NOTE" ]; then vns_printError "Note already exists." else if [ ! -d "$(dirname "$VNS_NOTE")" ]; then mkdir -p "$(dirname "$VNS_NOTE")" fi vns_NoteHeader | gpg2 -e -r "$VNS_PUBKEY" -o "$VNS_NOTE" vns_edit "$@" fi } function vns_edit(){ # Make the function more readable local readonly VNS_NOTE; VNS_NOTE="$VNS_STORE/$(vns_index "1" "$@").gpg" # Edit the note vim "$VNS_NOTE" } function vns_print(){ gpg2 -d "$VNS_STORE/$(vns_index "1" "$@").gpg" } function vns_gitPassthrough(){ cd "$VNS_STORE" || exit; git "$@"; } # ---- function vns_argParse(){ ARGS=($@) #echo "${#ARGS}" VNS_ACTION=() while getopts ":i:hc:e:p:d:" OPT; do # If an option requiring an argument was passed without an argument, # inform the user and set exit code to "$VNS_ERR_NS_ARGS" case "${ARGS[!OPTIND]}" in -i|-c|-e|-p|-d) if [ "${#ARGS}" -lt 2 ]; then vns_printError "A required argument was not given." VNS_EXIT="$VNS_ERR_NS_ARGS" return fi esac case "$OPT" in i) VNS_ACTION=("vns_initStore" "$OPTARG");; h) VNS_ACTION=("vns_printHelp");; c) VNS_ACTION=("vns_create $OPTARG");; e) VNS_ACTION=("vns_edit $OPTARG");; p) VNS_ACTION=("vns_print $OPTARG");; d) VNS_ACTION=("vns_rm $OPTARG");; esac done if [ "${#VNS_ACTION[@]}" -eq 0 ]; then if [ "$(vns_index "1" "$@")" == "git" ]; then VNS_ACTION=($@) else if [ -d "$VNS_STORE/$*" ]; then VNS_ACTION=("vns_list" "$@") else VNS_ACTION=("vns_list" "") fi fi fi } # Entry Point printf "%s, %s\n" "$XL_PRODUCT" "$XL_VER" printf "\n" cd "$VNS_STORE" || exit; readonly VNS_EDITOR="vim" readonly VNS_DEPS=("vim" "gpg2" "tree" "git") vns_argParse "$@" vns_sanityCheck if [ "$VNS_EXIT" -eq 0 ]; then eval "${VNS_ACTION[@]}" fi printf "\n" exit "$VNS_EXIT"