#!/bin/sh
 
-[ -n "$VCSH_DEBUG" ] && set -x
-
-SELF=$(basename $0)
-
+[ -n "$VCSH_DEBUG" ]      && set -x
 [ -z "$XDG_CONFIG_HOME" ] && XDG_CONFIG_HOME="$HOME/.config"
 [ -z "$VCSH_BASE" ]       && VCSH_BASE="$XDG_CONFIG_HOME/vcsh/repo.d"
-for check_directory in "$VCSH_BASE" "$HOME/.gitignore.d"
-do
-       if [ ! -d "$check_directory" ]; then
-               if [ -e "$check_directory" ]; then
-                       echo "$SELF: error: $check_directory exists but is not a directory" >&2
-                       exit 2
-               else
-                       echo "$SELF: info: attempting to create $check_directory"
-                       mkdir -p "$check_directory" || (echo "$SELF: error: could not create $check_directory" >&2; exit 2)
-               fi
-       fi
-done
 
-debug() {
-       [ -n "$VCSH_DEBUG" ] && echo "$SELF: debug: $1"
-}
+SELF=$(basename $0)
+if [ "$SELF" = 'bash' ] ||
+   [ "$SELF" = 'dash' ] ||
+   [ "$SELF" = 'sh' ] ||
+   [ "$SELF" = 'zsh' ]; then
+       SELF='vcsh'
+       VCSH_SOURCED=1
+fi
 
-verbose() {
-       if [ -n "$VCSH_DEBUG" ] || [ -n "$VCSH_VERBOSE" ]; then echo "$SELF: verbose: $1"; fi
-}
 
-#   use <repo>     Use this repository
-#
-#   exit              Exit vcsh mode" >&2
 help() {
        echo "usage: $SELF <args>
 
    clone <remote> \\
-         [<repo>]    Clone from an existing repository
-   help              Display this help
-   delete            Delete an existing repository
-   init <repo>       Initialize a new repository
-   list              List all repos
+         [<repo>]       Clone from an existing repository
+   help                 Display this help text
+   delete               Delete an existing repository
+   enter                Enter repository; spawn new $SHELL
+   exit                 Exit repository; unset ENV
+   init <repo>          Initialize a new repository
+   list                 List all repositories
    run <repo> \\
-       <command>     Use this repository
+       <command>        Use this repository
 
    seed-gitignore \\
-   <repo>            Seed .gitignore.d/<repo> from git ls-files" >&2
+   <repo>               Seed .gitignore.d/<repo> from git ls-files
+   use <repo>           Use repository; set ENV
+
+   <repo> <git command> Special command that allows you to run git commands
+                        directly without having to type so much ;)" >&2
+}
+
+debug() {
+       [ -n "$VCSH_DEBUG" ] && echo "$SELF: debug: $@"
+}
+
+verbose() {
+       if [ -n "$VCSH_DEBUG" ] || [ -n "$VCSH_VERBOSE" ]; then echo "$SELF: verbose: $@"; fi
 }
 
 use() {
        verbose "use() begin"
-       REPO_NAME="$1"
-       GIT_DIR="$VCSH_BASE/$REPO_NAME.git"
-
        if [ ! -d "$GIT_DIR" ]; then
-               echo E: no repository found for "$REPO_NAME" >&2
+               echo E: no repository found for "$VCSH_REPO_NAME" >&2
                return 1
        fi
-
        export GIT_DIR
        export GIT_WORK_TREE="$(git config --get core.worktree)"
-       export VCSH_DIRECTORY="$REPO_NAME"
+       export VCSH_DIRECTORY="$VCSH_REPO_NAME"
        verbose "use() end"
 }
 
        mkdir -p "$GIT_WORK_TREE"
        cd "$GIT_WORK_TREE" ||
                (echo "$SELF: fatal: could not enter $GIT_WORK_TREE" &&
-                exit 20) || exit 20
+                return 1) || return $?
        cd "$GIT_WORK_TREE"
        git init
        git config core.worktree     "$GIT_WORK_TREE"
-       git config core.excludesfile ".gitignore.d/$REPO_NAME"
-       touch   "$HOME/.gitignore.d/$REPO_NAME"
-       git add "$HOME/.gitignore.d/$REPO_NAME"
+       git config core.excludesfile ".gitignore.d/$VCSH_REPO_NAME"
+       touch   "$HOME/.gitignore.d/$VCSH_REPO_NAME"
+       git add "$HOME/.gitignore.d/$VCSH_REPO_NAME"
        verbose "init() end"
 }
 
        unset VCSH_DIRECTORY
 }
 
-if [ "$1" = 'help' ] || [ "$#" -eq 0 ]; then
-       help
-       [ "$1" = 'help' ]
-       exit $?
-
-elif [ "$1" = 'list' ]; then
-       verbose "list begin"
-       for i in "$VCSH_BASE"/*.git; do
-               echo $(basename "$i" .git)
-       done
-       verbose "list end"
-       exit 0
 
-elif [ "$1" = 'run' ]; then
-       verbose "run begin"
-       use "$2" || return 1
+if [ "$1" = 'clone' ]; then
+       GIT_REMOTE="$2"
+       export GIT_REMOTE
+       VCSH_REPO_NAME="$3"
+       [ -z "$VCSH_REPO_NAME" ] && VCSH_REPO_NAME=$(basename "$GIT_REMOTE" .git)
+       export VCSH_REPO_NAME
+       export GIT_DIR="$VCSH_BASE/$VCSH_REPO_NAME.git"
+elif [ "$1" = 'delete' ] ||
+     [ "$1" = 'enter' ] ||
+     [ "$1" = 'init' ] ||
+     [ "$1" = 'run' ] ||
+     [ "$1" = 'seed-gitignore' ] ||
+     [ "$1" = 'use' ]; then
+       [ -z $2 ] && echo "$SELF $1: error: please specify repository to work on" && return 1
+       export VCSH_COMMAND="$1"
+       export VCSH_REPO_NAME="$2"
+       export GIT_DIR="$VCSH_BASE/$VCSH_REPO_NAME.git"
        shift 2
-       "$@"
-       leave
-       verbose "run end"
-       exit 0
+       export VCSH_EXTERNAL_COMMAND="$*"
+       if [ "$VCSH_COMMAND" = 'run' ]; then
+               [ -z "$VCSH_EXTERNAL_COMMAND" ] && echo "$SELF $1 $2: error: please specify a command" && return 1
+       fi
+elif [ "$1" = 'exit' ] ||
+     [ "$1" = 'help' ] ||
+     [ "$1" = 'list' ]; then
+       export VCSH_COMMAND="$1"
+else
+       [ -z $1 ] && help && return 0
+       export VCSH_COMMAND='run'
+       export VCSH_REPO_NAME="$1"
+       export GIT_DIR="$VCSH_BASE/$VCSH_REPO_NAME.git"
+       [ -d $GIT_DIR ] || (help && return 1) || return 0
+       shift 1
+       export VCSH_EXTERNAL_COMMAND="git $*"
+fi
 
-#elif [ "$1" = 'use' ]; then
-#      verbose "use begin"
-#      if [ -n "$ZSH_VERSION" ]; then
-#              if [ -o NO_IGNORE_EOF ]; then
-#                      export VCSH_NO_IGNORE_EOF=1
-#                      setopt IGNORE_EOF
-#              fi
-#              vcsh_exit() {
-#                      vcsh exit;
-#                      zle reset-prompt;
-#              }
-#              zle -N vcsh_exit
-#              bindkey '^d' 'vcsh_exit'
-#      fi
-#      use "$2" || return 1
-#      [ -n "$ZSH_VERSION" ] && [ "$USER" = richih ] && buildPS1
-#      verbose "use end"
-#      exit 0
 
-elif [ "$1" = 'clone' ]; then
+for check_directory in "$VCSH_BASE" "$HOME/.gitignore.d"
+do
+       if [ ! -d "$check_directory" ]; then
+               if [ -e "$check_directory" ]; then
+                       echo "$SELF: error: $check_directory exists but is not a directory" >&2
+                       return 2
+               else
+                       echo "$SELF: info: attempting to create $check_directory"
+                       mkdir -p "$check_directory" || (echo "$SELF: error: could not create $check_directory" >&2; return 2) || return $?
+               fi
+       fi
+done
+
+
+if [ "$VCSH_COMMAND" = 'clone' ]; then
        verbose "clone begin"
-       GIT_REMOTE="$2"
-       REPO_NAME="$3"
-       [ -z "$REPO_NAME" ] && REPO_NAME=$(basename "$GIT_REMOTE" .git)
-       export REPO_NAME
-       export GIT_DIR="$VCSH_BASE/$REPO_NAME.git"
        init
-
        git remote add origin "$GIT_REMOTE"
        git config branch.master.remote origin
        git config branch.master.merge  refs/heads/master
-       git config core.excludesfile    ".gitignore.d/$REPO_NAME"
        git fetch
        for object in $(git ls-tree -r origin/master | awk '{print $4}'); do
                [ -e "$object" ] &&
        [ "$VCSH_CONFLICT" = '1' ] &&
                echo "$SELF: fatal: will stop after fetching and not try to merge!\n" &&
                echo "  Once this situation has been resolved, run 'vcsh run <foo> git pull' to finish cloning.\n" &&
-               exit 3
+               return 3
        git merge origin/master
-#      use $REPO_NAME || return 1
+#      use || return $?
        verbose "clone end"
 
-elif [ "$1" = 'init' ]; then
-       verbose "init begin"
-       [ -z $2 ] && help && echo && echo "$SELF $1: error: please specify repository to work on" && return 0
-       export REPO_NAME="$2"
-       export GIT_DIR="$VCSH_BASE/$REPO_NAME.git"
-       init
-#      use "$REPO_NAME" || return 1
-       verbose "init end"
+#elif [ "$VCSH_COMMAND" = 'help' ] || [ "$#" -eq 0 ]; then
+elif [ "$VCSH_COMMAND" = 'help' ]; then
+       help
+
+elif [ "$VCSH_COMMAND" = 'delete' ]; then
+       verbose "delete begin"
+       old_dir="$PWD"
+       cd "$HOME"
+       use || return $?
+       echo "$SELF: info: This operation WILL DETROY DATA!"
+       files=$(git ls-files)
+       echo "These files will be deleted:
+
+$files
 
-#elif [ "$1" = 'exit' ]; then
-#      verbose "exit begin"
+AGAIN, THIS WILL DELETE YOUR DATA!
+To continue, type \"Yes, do as I say\""
+       read answer
+       [ "x$answer" = "xYes, do as I say" ] || return 1
+       for file in $files; do
+               rm -f $file || echo "$SELF: info: could not delete '$file', continuing with deletion"
+       done
+       rm -rf "$GIT_DIR" || echo "$SELF: info: could not delete '$GIT_DIR'"
+       cd "$old_dir"
+       verbose "delete end"
+
+elif [ "$VCSH_COMMAND" = 'enter' ]; then
+       verbose "enter begin"
+       use || return $?
+       $SHELL
+       leave
+       verbose "enter end"
+
+elif [ "$VCSH_COMMAND" = 'exit' ]; then
+       verbose "exit begin"
 #      if [ -n "$ZSH_VERSION" ] && [ "$VCSH_NO_IGNORE_EOF" = '1' ]; then
 #              unset VCSH_NO_IGNORE_EOF
 #              setopt NO_IGNORE_EOF
 #      fi
-#      leave
+       [ -z "$VCSH_SOURCED" ] && echo "$SELF $VCSH_COMMAND: You need to source vcsh if you want to run in this mode" && return 10
+       leave
 #      [ -n "$ZSH_VERSION" ] && [ "$USER" = richih ] && buildPS1
-#      verbose "exit end"
-#      exit 0
+       verbose "exit end"
+       return 0
 
-elif [ "$1" = 'seed-gitignore' ]; then
+elif [ "$VCSH_COMMAND" = 'init' ]; then
+       verbose "init begin"
+       init
+#      use || return $?
+       verbose "init end"
+
+elif [ "$VCSH_COMMAND" = 'list' ]; then
+       verbose "list begin"
+       for i in "$VCSH_BASE"/*.git; do
+               echo $(basename "$i" .git)
+       done
+       verbose "list end"
+
+elif [ "$VCSH_COMMAND" = 'run' ]; then
+       verbose "run begin"
+       use || return $?
+       $VCSH_EXTERNAL_COMMAND
+       leave
+       verbose "run end"
+
+elif [ "$VCSH_COMMAND" = 'seed-gitignore' ]; then
        verbose "seed-gitignore begin"
-       [ -z $2 ] && help && echo && echo "$SELF $1: error: please specify repository to work on" && return 0
-       use $2 || return 1
+       use || return $?
        # Switching directory as this has to be executed from $HOME to be of any use.
        # Going back into old directory at the end in case `vcsh use` is reactivated.
        old_dir="$PWD"
        cd "$HOME"
-       git config core.excludesfile ".gitignore.d/$REPO_NAME"
+       git config core.excludesfile ".gitignore.d/$VCSH_REPO_NAME"
        gitignores=$(for file in $(git ls-files); do
                while true; do
                        echo $file; new="${file%/*}"
                        [ "$file" = "$new" ] && break
                        file="$new"
                done;
-       done | sort -u | sed 's/^/!/')
+       done | sort -u)
        tempfile=$(mktemp) ||
-               (echo "$SELF: fatal: could not create tempfile" && exit 1) 
+               (echo "$SELF: fatal: could not create tempfile" && return 1) || return $?
        echo '*' > "$tempfile"
        for gitignore in $gitignores; do
-               echo "$gitignore" >> "$tempfile"
+               echo "$gitignore" | sed 's/^/!/' >> "$tempfile"
+               [ -d "$gitignore" ] && echo "$gitignore/*" | sed 's/^/!/'>> "$tempfile"
        done
-       diff -N "$tempfile" "$HOME/.gitignore.d/$2" > /dev/null &&
+       diff -N "$tempfile" "$HOME/.gitignore.d/$VCSH_REPO_NAME" > /dev/null &&
                rm -f "$tempfile" &&
                return
-       if [ -e "$HOME/.gitignore.d/$2" ]; then
-               echo "$SELF: info: $HOME/.gitignore.d/$2 differs from new data, moving it to $HOME/.gitignore.d/$2.bak"
-               mv -f "$HOME/.gitignore.d/$2" "$HOME/.gitignore.d/$2.bak" ||
-                       (echo "$SELF: fatal: could not move $HOME/.gitignore.d/$2 to $HOME/.gitignore.d/$2.bak" && exit 1)
+       if [ -e "$HOME/.gitignore.d/$VCSH_REPO_NAME" ]; then
+               echo "$SELF: info: $HOME/.gitignore.d/$VCSH_REPO_NAME differs from new data, moving it to $HOME/.gitignore.d/$VCSH_REPO_NAME.bak"
+               mv -f "$HOME/.gitignore.d/$VCSH_REPO_NAME" "$HOME/.gitignore.d/$VCSH_REPO_NAME.bak" ||
+                       (echo "$SELF: fatal: could not move $HOME/.gitignore.d/$VCSH_REPO_NAME to $HOME/.gitignore.d/$VCSH_REPO_NAME.bak" &&
+                        return 1) || return $?
        fi
-       mv -f "$tempfile" "$HOME/.gitignore.d/$2" ||
-               (echo "$SELF: fatal: could not move $tempfile to $HOME/.gitignore.d/$2" && exit 1)
+       mv -f "$tempfile" "$HOME/.gitignore.d/$VCSH_REPO_NAME" ||
+               (echo "$SELF: fatal: could not move $tempfile to $HOME/.gitignore.d/$VCSH_REPO_NAME" && return 1) || return $?
        cd "$old_dir"
        verbose "seed-gitignore end"
 
-elif [ "$1" = 'delete' ]; then
-       verbose "delete begin"
-       REPO_NAME=$2
-       [ -z $REPO_NAME ] && help && echo && echo "$SELF $1: error: please specify repository to work on" && return 0
-       old_dir="$PWD"
-       cd "$HOME"
-       use $REPO_NAME || return 1
-       echo "$SELF: info: This operation WILL DETROY DATA!"
-       files=$(git ls-files)
-       echo "These files would be deleted:
-
-$files
-
-AGAIN, THIS WILL DELETE YOUR DATA!
-To continue, type \"Yes, do as I say\""
-       read answer
-       [ "x$answer" = "xYes, do as I say" ] || exit
-       for file in $files; do
-               rm -f $file || echo "$SELF: info: could not delete '$file', continuing with deletion"
-       done
-       rm -rf "$VCSH_BASE/$REPO_NAME.git" || echo "$SELF: info: could not delete '$VCSH_BASE/$REPO_NAME.git'"
-       cd "$old_dir"
-       verbose "delete end"
-
+elif [ "$VCSH_COMMAND" = 'use' ]; then
+       verbose "use begin"
+#      if [ -n "$ZSH_VERSION" ]; then
+#              if [ -o NO_IGNORE_EOF ]; then
+#                      export VCSH_NO_IGNORE_EOF=1
+#                      setopt IGNORE_EOF
+#              fi
+#              vcsh_exit() {
+#                      vcsh exit;
+#                      zle reset-prompt;
+#              }
+#              zle -N vcsh_exit
+#              bindkey '^d' 'vcsh_exit'
+#      fi
+       [ -z "$VCSH_SOURCED" ] && echo "$SELF $VCSH_COMMAND: You need to source vcsh if you want to run in this mode" && return 10
+       use || return $?
+#      [ -n "$ZSH_VERSION" ] && [ "$USER" = richih ] && buildPS1
+       verbose "use end"
 
 else
        verbose "defaulting to calling help()"
        help
-       exit 3
+       echo "$SELF: fatal: You should never reach this code. File a bug, please."
+       return 99
 
 fi
-