diff --git a/CHANGELOG b/CHANGELOG deleted file mode 100644 index e12f80d..0000000 --- a/CHANGELOG +++ /dev/null @@ -1,3 +0,0 @@ -v1.1 -Added merge, rename options -Enabled gpg-agent diff --git a/DEBUG b/DEBUG deleted file mode 100644 index 9c323a3..0000000 --- a/DEBUG +++ /dev/null @@ -1,30 +0,0 @@ -Vim Note System, v1.1 - -The following is a table of exit codes - -Code In Function Meaning ------------------------------------------------------ -10 vns Invalid argument given - -20 sanityCheck Missing dependencies -21 sanityCheck VNS store not initialized - -30 rm Insufficient arguments -31 rm Note does not exist - -40 create Insufficient arguments -41 create Note already exists - -50 edit Insufficient arguments -51 edit Note not found - -60 print Insufficient arguments - -70 mv Insufficient arguments -71 mv Couldn't read source note -72 mv Destination note already exists - -81 merge No output specified -82 merge Output file already exists. -83 merge could not open note - diff --git a/README.md b/README.md index 45c90d7..1c4f8a4 100644 --- a/README.md +++ b/README.md @@ -1,66 +1,8 @@ -Vim Note System +Simple Note System ================== ## About -Vim Note System is a shell script partially inspired by [pass]. -vns stores notes as asymmetrically encrypted plaintext using the -vim-gnupg plugin. - -VNS, formerly SNS, was originally conceived one morning during an update -to a popular note-taking app. The thought occurred that a note system need -not reinvent the wheel with its own GUI editor and proprietary file format, -but instead could use the tools already provided by the operating system. - - vim note system - ================== - - usage: vns [-cedlp] - vns [-hi] - vns git ... - - -c | --create : Create note - -d | --delete : Delete note - -e | --edit : Open note for editing - -h | --help : Display this message - -i | --init : Initialize note store" - -l | --list : List all notes in - -p | --print : Print note to console - -## Installing - ### Dependencies - * vim - * gpg2 - * tree - * git - - ** Note: ** Install [vim-gnupg] before use. vns *does* check this, but only *after* - a note has been created. - - To install, place `vns` in your path, and run `vns -i`. - - vim note system will establish its note store under ~/.config/vns. - The location of the store may be changed on line 6. - - To uninstall, remove the files you copied. Notes will still exist in ~/.config/vns - -## Tips and Tricks -* To list all notes in all notebooks, simply run `vns`. -* Notes beginning with . will not appear in the listing - -## Credits -The code here is my own, however much of VNS's design and behavior was -influenced by [pass]. - -## License -Vim Note System is licensed under the terms of the GNU General Public License -Version 2, as detailed in `LICENSE`. - -## Bugs and Feature Requests -If something seems off, or just doesn't work, please open an issue and I'll look -into it. - -Feature requests should be submitted to jon.lewis@xenami.net with [SNS Feature Request] -in the subject line. - -[pass]: http://passwordstore.org -[vim-gnupg]:http://www.vim.org/scripts/script.php?script_id=3645 +Simple Note System, a script for managing notes inspired in part by "pass" is +deprecated in favor of Vim Note System. This version 1.0 copy of Simple Note +System is present under the legacy branch of Vim Note System for the purpose +of helping convert old openssl-encrypted SNS notes to GPG format. diff --git a/errors.md b/errors.md deleted file mode 100644 index 936ec07..0000000 --- a/errors.md +++ /dev/null @@ -1,28 +0,0 @@ -# Simple Note System, version 2 -## Error Code Reference - -### General Codes -| Name | Code | Meaning | -|--------------|------|---------------------------------------| -| ERR_NO_STORE | 5 | the SNS store needs to be initialized | -| | | | -| ERR_NO_OPTS | 10 | No mode argument was specified | -| | | | -| ERR_NO_ARGS | 11 | A mode requiring an argument was | -| | | specified without an argument | -| | | | - -### Encryption-related codes -|Name | Code | Meaning | -|------------|------|-----------------------------------------| -| ERR_NO_GPG | 100 | Encryption is enabled, but GPG is not | -| | | installed | -| | | | -| ERR_NO_KEY | 110 | Encryption is enabled, but no recipient | -| | | was specified | - -### Creation-related codes -|Name | Code | Meaning | -|-----------------|------|------------------------------------| -| ERR_NOTE_EXiSTS | 200 | The specified note already exists | -| ERR_NOTE_NO_READ| 205 | The specified note cannot be read | diff --git a/sns.sh b/sns.sh new file mode 100644 index 0000000..edd6b40 --- /dev/null +++ b/sns.sh @@ -0,0 +1,311 @@ +#!/bin/bash +#========================================================== +# Simple Note System, v1.0 +# Copyright 2014, Xenese Labs/Sicron-Perion XNF +#========================================================== + +PROD_STR="Simple Note System" +VER_STR=v1.0 + +#============================================================================== +# Section: Helper Functions +#============================================================================== +function writeconf { +cat > $HOME/.sns << EOF +#========================================================== +# Simple Note System Config, v1.0 +# Copyright 2014, Xenese Labs/Sicron-Perion XNF +#========================================================== + +#Directory where notes will be stored +BASEDIR=$HOME/notes + +#File extension to use (for listing notes) +EXT=note + +#Preferred Editor +EDITOR=vim + +#Encryption +#WARNING: ANY PREVIOUSLY UNENCRYPTED NOTES WILL BE LOST +ENCRYPTION="FALSE" +ENC_KEY="" +EOF + +chmod 600 $HOME/.sns +} + +function help { + echo "" + echo "usage: sns [-ce] NAME NOTEBOOK SECTION" + echo " sns [-d ] NAME NOTEBOOK SECTION" + echo " sns [-l ] NOTEBOOK" + echo " sns [-w ]" + + echo "" + echo " -c | --create : Create note" + echo " -d | --delete : Delete note" + echo " -e | --edit : Open note for editing" + echo " -l | --list : List all notes in NOTEBOOK" + echo " -w | --wconf : Write default configuration to ~/.sns (useful for Encryption)" + echo "" +} + +function pause { + read -p " Press [Enter] to continue." + echo "" +} + +#============================================================================== +# End Section: Helper Functions +#============================================================================== + +#============================================================================== +# Section: Configuration +#============================================================================== +if [ -r $HOME/.sns ]; then + source $HOME/.sns +else + BASEDIR=$HOME/notes + EDITOR=vim + EXT=note +fi + +if [ "$ENCRYPTION" == "TRUE" ]; then + if [ -z "$ENC_KEY" ]; then + ERR_NO_KEY="TRUE" + ENCRYPTION="FALSE" + pause + fi + command -v openssl >/dev/null 2>&1 || { ERR_NO_SSL="TRUE"; ENCRYPTION="FALSE"; } +fi + +if [ "$ENCRYPTION" == "TRUE" ]; then + PROD_STR="Simple Note System (Encryption Enabled)" + EXT="$EXT.enc" + if [ ! -d ~/.tmp ]; then + mkdir -p ~/.tmp + fi +fi + +echo "$PROD_STR, $VER_STR" +if [ -n "$ERR_NO_SSL" ]; then + echo >&2 " Warning: OpenSSL not installed. Encryption disabled." +fi +if [ -n "$ERR_NO_KEY" ]; then + echo " Warning: No encryption key was provided. Encryption disabled." +fi + +if [ -n "$ERR_NO_SSL" -o -n "$ERR_NO_KEY" ]; then + pause +fi + +#============================================================================== +# End Section: Read Configuration +#============================================================================== + + +#============================================================================== +# Section: Argument Parsing +#============================================================================== + +NAME="" +NOTEBOOK="" +SECTION="" + +if [ -z "$1" ]; then #If no input was given, print help + help + exit +else #Assume the user wants to do something. + ARGS=( "$@" ) + for ARG in ${ARGS[@]};do + if [ "$ARG" = "-c" -o $ARG == "--create" ]; then + CREATE="TRUE" + elif [ "$ARG" = "-d" -o $ARG == "--delete" ]; then + DELETE="TRUE" + elif [ "$ARG" = "-e" -o $ARG == "--edit" ]; then + EDIT="TRUE" + elif [ "$ARG" = "-ce" -o $ARG == "-ec" ]; then + EDIT="TRUE" + CREATE="TRUE" + elif [ "$ARG" == "-l" -o "$ARG" == "--list" ]; then #If user asks for list, print list + LIST="TRUE" + elif [ "$ARG" == "-h" -o "$ARG" == "--help" ]; then #If user asks for help, print help + help + exit + elif [ "$ARG" == "-w" -o "$ARG" == "--wconf" ]; then #If user wants to write config, write config + writeconf + exit + + else + if [ -z "$NAME" -a -n $ARG ]; then + NAME=$ARG + echo "Name: $NAME" + elif [ -z "$NOTEBOOK" -a -n $ARG ]; then + NOTEBOOK=$ARG + echo "Notebook: $NOTEBOOK" + elif [ -z "$SECTION" -a -n $ARG ]; then + SECTION=$ARG/ + echo "Section: $SECTION" + fi + fi + done +fi + + + +#============================================================================== +# End Section: Argument Parsing +#============================================================================== + +#============================================================================== +# Section: Main +#============================================================================== + + NOTEDIR=$BASEDIR/$NOTEBOOK/$SECTION + NOTE=$NOTEDIR$NAME.$EXT + + if [ "$ENCRYPTION" == "TRUE" ]; then + NOTE=$NOTE.tmp + fi + + #========================================================================== + # Subection: List + #========================================================================== + if [ -n "$LIST" ]; then + NOTEBOOK="$NAME" #In case of a list command, arg parsing fails. + if [ -z "$NOTEBOOK" ]; then + echo " ERROR: Insufficient arguments" + help + exit + else + if [ -d "$BASEDIR"/"$NOTEBOOK" ]; then + + echo "" + printf "Notes in $(basename $NOTEBOOK):" + echo "" + #find $BASEDIR/$NOTEBOOK -name "*.$EXT" -print0 | sed s:$BASEDIR/$NOTEBOOK/:" ":g | sed -e s:$EXT::g | tr "." " " + NOTES=( $(find $BASEDIR/$NOTEBOOK -name "*.$EXT" -print0 | sed s:$BASEDIR/$NOTEBOOK/:" ":g | sed -e s:$EXT::g | tr "." " " | tr "/" " ") ) + + let i=0 + for NOTE in ${NOTES[@]}; do + if [ -d $BASEDIR/$NOTEBOOK/$NOTE ]; then + if [ "$LAST_SECTION" != "$NOTE" ]; then + printf " Section: $NOTE\n" + fi + LAST_SECTION=$NOTE + else + #if [ $(($i % 1)) -eq 0 ]; then + # printf "\n " + #fi + printf " $NOTE\n" + fi + let i++ + done + printf "\n" + else + echo "" + echo "ERROR: Notebook $NOTEBOOK does not exist." + echo "" + fi + fi + exit + fi + #====================================================================== + # Sanity Check - Actions below require a valid $NAME and $NOTEBOOK + #====================================================================== + if [ -z "$NAME" -o -z "$NOTEBOOK" ]; then + if [ -z "$NAME" -o -z "$NOTEBOOK" ]; then + echo " ERROR: Insufficient arguments" + help + exit + fi + fi + + #========================================================================== + # Subection: Delete + #========================================================================== + if [ "$DELETE" == "TRUE" ]; then + if [ -e $NOTE -o -e ${NOTE%.*} ]; then + if [ "$ENCRYPTION" == "TRUE" ]; then + rm ${NOTE%.*} + else + rm $NOTE + fi + + echo "" + echo "Deleted note: $NOTEBOOK/$SECTION$NAME." + exit + else + + echo "" + echo "ERROR: Note $NOTEBOOK/$SECTION$NAME does not exist." + exit + fi + fi + + #========================================================================== + # Subection: Create + #========================================================================== + if [ -z "$CREATE" -a -z "$EDIT" ]; then #If no action specified, print help and exit + help + exit + else + + + if [ "$CREATE" == "TRUE" ]; then + if [ -e $NOTE -o -e ${NOTE%.*} ]; then + + echo "" + echo "ERROR: Note already exists" + echo "Hint: use -e to edit the note." + echo "" + exit + else + #Create any necessary folders + mkdir -p $NOTEDIR + + #Fill in title + echo "TITLE: $NAME" > $NOTE + #Fill the second line with the date + echo "DATE: $(date)" >> $NOTE + + if [ "$ENCRYPTION" == "TRUE" ]; then + if [ $EDIT == "FALSE" ]; then + openssl enc -aes-256-cbc -salt -in $NOTE -out ${NOTE%.*} -pass pass:$ENC_KEY + fi + fi + fi + fi + + #========================================================================== + # Subection: Edit + #========================================================================== + if [ "$EDIT" == "TRUE" ]; then + if [ -r "$NOTE" -o -r ${NOTE%.*} ]; then + if [ -z "$CREATE" ]; then + if [ "$ENCRYPTION" == "TRUE" ]; then + openssl enc -d -aes-256-cbc -in ${NOTE%.*} -pass pass:$ENC_KEY > $NOTE + fi + echo "" >> $NOTE + echo "EDIT $(date)" >> $NOTE + fi + $EDITOR $NOTE + if [ "$ENCRYPTION" == "TRUE" ]; then + openssl enc -aes-256-cbc -salt -in $NOTE -out ${NOTE%.*} -pass pass:$ENC_KEY + rm $NOTE + fi + + else + + echo "" + echo "ERROR: Note cannot be opened for editting." + echo "" + + fi + fi + +fi + + +exit \ No newline at end of file diff --git a/vns b/vns deleted file mode 100644 index c4bd632..0000000 --- a/vns +++ /dev/null @@ -1,370 +0,0 @@ -#!/usr/bin/env bash -# Vim Note System v1.1, a simple script for managing encrypted plaintext notes -# Copyright (C) 2018 Jon Lewis - -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -set -euo pipefail # Terminate the script if anything goes wrong - # http://redsymbol.net/articles/unofficial-bash-strict-mode/ - -readonly VNS_PRODUCT="Vim Note System, v1.1" # String to print for reports -readonly VNS_STORE="$HOME/.config/vns" # Where vns expects its note store -readonly GPG_TTY="$(tty)" # Sets up gpg-agent for use - -vns_raise (){ - - # raise (message) (exit code) - # Prints error (message) to stderr, then exits with (exit code) - - local -r VNS_RED_COLOR='\033[0;31m' - local -r VNS_RESET_COLOR='\033[0m' - - printf "%s, %s\\n\\n" "$VNS_PRODUCT" - printf "$VNS_RED_COLOR!$VNS_RESET_COLOR - %s\\n" "$1" 1>&2 - exit "$2" - -} - -vns_checkDeps (){ - - # checkDeps - # Prints a list of unbound variables - - readonly VNS_DEPS=("vim" "gpg2" "tree" "git") - - for DEP in "${VNS_DEPS[@]}"; do - if test ! -e "$(which "$DEP" 2>/dev/null)"; then - printf "%s " "$DEP" - fi - done - -} - -vns_sanityCheck () { - - # sanityCheck - # Terminates script if environment is not suitable for vns - - # --- Dependencies --- - # Get list of missing dependencies - local MISSING; MISSING="$(vns_checkDeps)" - - # If that list is not empty, inform the user and exit on code 20 - if [ -n "$MISSING" ]; then - vns_raise "Missing Dependencies: $MISSING" 20 - fi - - # --- Store --- - # Verify that the note store has been initialized - if [ ! -d "$VNS_STORE" ]; then - vns_raise "The vns store needs to be initialized (hint: -i)" 21 - fi - -} - -vns_init () { - - # initStore - # Prepares $VNS_STORE for use - - if [ -d "$VNS_STORE/.git" ]; then - vns_raise "Store already initialized" 2; - fi - - mkdir -p "$VNS_STORE" - cd "$VNS_STORE" || exit - git init >/dev/null - -} - -vns_printHelp (){ - - # printHelp - # Prints help information to stdout - - printf "%s" "usage: vns [-cedlp] " - printf "\\n%s" " vns -I" - printf "\\n%s" " vns -h" - printf "\\n%s" " vns git ..." - printf "\\n" - printf "\\n%s" " -c : Create note" - printf "\\n%s" " -d : Delete note" - printf "\\n%s" " -e : Open note for editing" - printf "\\n%s" " -h : Display this message" - printf "\\n%s" " -i : import file as note" - printf "\\n%s" " -I : Initialize note store" - printf "\\n%s" " -l : List all notes in " - printf "\\n%s" " -m : Merge two or more notes" - printf "\\n%s" " -p : Print note to console" - printf "\\n\\n" - -} - -vns_list () { - - # list (notebook) - # Prints a tree containing all notes in the notebook - # If no notebook is specified, the entire store is used - - numNotes () { find . -name "*.gpg" \( ! -regex '.*/\..*' \) | wc -l; } - - # Check for default behavior - if [ -z "${*:1:1}" ]; then - readonly NOTEBOOK="" - if [ "$(numNotes)" != "0" ];then - printf "%s\\n" "Store" - fi - else - readonly NOTEBOOK="$1" - printf "%s\\n" "$1" - fi - - tree -C --noreport --prune "$VNS_STORE/$NOTEBOOK"\ - | tail -n +2\ - | sed s/\.gpg//g - -} - -vns_rm () { - - # rm (note) - # removes (note) from the store - - local -r VNS_BLUE_COLOR='\033[0;34m' - local -r VNS_RESET_COLOR='\033[0m' - - # Verify $1 is bound - if [ -z "${*:1:1}" ]; then vns_raise "Insufficient arguments" 30; fi - - # Verify the note exists - if [ ! -r "$VNS_STORE/$1.gpg" ]; then - vns_raise "Note does not exist" 31; - fi - # Delete the Note - git rm "$VNS_STORE/$1.gpg" > /dev/null - git commit -m "Deleted $1" > /dev/null - - # Report success - printf "%s, %s\\n\\n" "$VNS_PRODUCT" - printf "$VNS_BLUE_COLOR!$VNS_RESET_COLOR - %s\\n" "Deleted $VNS_STORE/$1" - -} - -vns_create () { - - # create (note) - # Create a new note and open it for editing - - local -r VNS_RED_COLOR='\033[0;31m' - local -r VNS_RESET_COLOR='\033[0m' - - # Verify $1 is bound - if [ -z "${*:1:1}" ]; then vns_raise "Insufficient arguments" 40; fi - - # Refuse to overwrite a note - if [ -r "$VNS_STORE/$1.gpg" ]; then vns_raise "Note already exists" 41; fi - - # If the note belongs to a new notebook, create the notebook - if [ ! -d "$(dirname "$1")" ]; then mkdir -p "$VNS_STORE/$(dirname "$1")"; fi - - # Create-Edit the note - vim "$VNS_STORE/$1.gpg" - - # Warn the user if the note failed to encrypt - if ! grep "PGP" <<< "$(file "$VNS_STORE/$1.gpg")" > /dev/null; then - printf "$VNS_RED_COLOR!$VNS_RESET_COLOR - %s\\n %s\\n"\ - "The created note was not encrypted."\ - "Check your vim-gnupg setup." - fi - - # Update Git - git add "$VNS_STORE/$1.gpg" > /dev/null - git commit -m "Added $1" > /dev/null - -} - -vns_edit () { - - # edit (note) - # Open (note) for editing in Vim - - # Verify $1 is bound - if [ -z "${*:1:1}" ]; then vns_raise "Insufficient arguments" 50; fi - - # Refuse to edit non-existent notes - if [ ! -r "$VNS_STORE/$1.gpg" ]; then vns_raise "Note not found: $1" 51; fi - - # Edit the specified note - vim "$VNS_STORE/$1.gpg" - - # Update Git - git add "$VNS_STORE/$1.gpg" > /dev/null - git commit -m "Edited $1" > /dev/null -} - -vns_import () { - - # import (src) (dest) - # If src is the path to a file, and dest is a valid note name, - # import src dest copies an encrypted version of src to the note store - - if [ -z "${*:1:1}" ]; then - vns_raise "No source file specified" 90 - - elif [ -z "${*:2:2}" ]; then - vns_raise "No destination name specified" 91 - - elif [ ! -f "$1" ]; then - vns_raise "Cannot read $1" 92 - - elif [ -f "$VNS_STORE/$2" ]; then - printf "%s" "Note already exists. Overwrite? (Y/N) " - local response; read -r response - case "$response" in - Yy) - rm "$VNS_STORE/$2";; - *) - vns_raise "User declined overwrite" 0;; - esac - fi - - printf "%s:" "Specify GPG Public Key: " - local gpg_key; read -r gpg_key - - gpg2 -r "$gpg_key" -o "$VNS_STORE/$2.gpg" -e "$1" - - git add "$VNS_STORE/$2.gpg" - git commit -m "Imported file $1 as $2" - -} - -vns_print () { - - # print (note) - # print the given note to stdout - - # Verify $1 is bound - if [ -z "${*:1:1}" ]; then vns_raise "Insufficient arguments" 11; fi - - # Decrypt the specified note - gpg2 -d "$VNS_STORE/$1.gpg" - -} - -vns_mv () { - - # mv (src) (dest) - # If (src) is a note in the vns store, mv src dest moves src to dest - - if [ -z "${*:2}" ]; then vns_raise "Insufficient arguments" 70; fi - if [ ! -r "$VNS_STORE/$1.gpg" ]; then vns_raise "Cannot read $1" 71; fi - if [ -r "$VNS_STORE/$2.gpg" ]; then vns_raise "Note $2 already exists" 72; fi - - git mv "$VNS_STORE/$1.gpg" "$VNS_STORE/$2.gpg" - -} - -vns_merge () { - - # merge (output) (notes[]) - # If notes[] is an array of note names and output is a new note name, - # merge (output) (notes[]) concatenates notes[] into output. - - if [ -z "${*:1}" ]; then vns_raise "No output specified" 81; fi - if [ -z "${*:2}" ]; then vns_raise "No inputs specified" 84; fi - if [ -r "$VNS_STORE/$1.gpg" ]; then vns_raise "Output file already exists." 82; fi - - # Make output file - if [ ! -r "$VNS_STORE/$2.gpg" ]; then vns_raise "Could not read $2" 83; fi - cp "$VNS_STORE/$2.gpg" "$VNS_STORE/$1.gpg" - - local -r GPG_RECIP="$(gpg --list-only -v -d "$VNS_STORE/$1.gpg" 2>&1 | cut -f 5 -d " ")" - - for note in "${@:3}"; do - if [ ! -r "$VNS_STORE/$note.gpg" ]; then - rm "$VNS_STORE/$1.gpg" - vns_raise "Could not read $note" 83; - fi - - gpg2 --batch --yes -r "$GPG_RECIP" -o "$VNS_STORE/$1.gpg" -e <<< "$(gpg2 -d "$VNS_STORE/$1.gpg") $(gpg2 -d "$VNS_STORE/$note.gpg")" - done - - for note in "${@:2}"; do - git rm "$VNS_STORE/$note.gpg" - done - - git add "$VNS_STORE/$1.gpg" - - git commit -m "merged files ${*:2} into $1" -} - -vns_duplicate () { - if [ -z "${*:1:1}" ]; then - vns_raise "No source note specified" 100 - - elif [ -z "${*:2:2}" ]; then - vns_raise "No destination name specified" 101 - - elif [ ! -f "$VNS_STORE/$1" ]; then - vns_raise "Cannot read $1" 102 - - elif [ -f "$VNS_STORE/$2" ]; then - printf "%s" "Note already exists. Overwrite? (Y/N) " - local response; read -r response - case "$response" in - Yy) - rm "$VNS_STORE/$2";; - *) - vns_raise "User declined overwrite" 0;; - esac - fi - - cp "$VNS_STORE/$1.gpg" "$VNS_STORE/$2.gpg" - - git add "$VNS_STORE/$2" -} -vns () { - - # Bypass sanity check if told to initialize store - if [ "$*" != "-i" ]; then - vns_sanityCheck; - # Change Directory to Store for Git passthrough - cd "$VNS_STORE" || exit; - fi - - - # Default action is to list all notes - if [ -z "${*:1:1}" ]; then vns_list ""; exit 0; fi - - # List of valid arguments - declare -A -r ACTIONS=( ["-c"]="vns_create" ["-d"]="vns_rm"\ - ["-e"]="vns_edit" ["-l"]="vns_list"\ - ["-h"]="vns_printHelp" ["-I"]="vns_init"\ - ["-i"]="vns_import" ["-m"]="vns_merge"\ - ["-p"]="vns_print" ["-r"]="vns_mv"\ - ["-u"]="vns_duplicate" ["git"]="git" ) - - # If given an invalid argument, inform the user and exit on code 10 - # Otherwise, perform the corresponding action - if ! test "${ACTIONS["$1"]+isset}"; then - vns_raise "Invalid argument: $1" 10 - else - "${ACTIONS["$1"]}" "${@:2}" - fi - - exit 0; -} - -vns "$@"