#!/bin/bash
# wisp-multiline.sh --- run multiline wisp code

# Copyright (C) 2013 Arne Babenhauserheide <arne_bab@web.de>

# Author: Arne Babenhauserheide <arne_bab@web.de>

# 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 3
# 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, see <http://www.gnu.org/licenses/>.


## global variables

# version of this script
version="wisp multiline 0.3"
# aggregated wisp code
wisp=""
# converted lisp code
lispcode=""


## Parse commandline options

getopt -T > /dev/null
if [ $? -eq 4 ]; then
    # GNU enhanced getopt is available
    eval set -- `getopt --long help,lisp:,verbose,version,output:,wisp:,interactive --options hl:vo:w:i -- "$@"`
else
    # Original getopt is available
    eval set -- `getopt hl:vo:w:i "$@"`
fi

PROGNAME=`basename $0`
ARGS=`getopt --name "$PN" --long help,lisp:,verbose,version,output:,wisp:interactive --options hl:vo:w:i -- "$@"`
if [ $? -ne 0 ]; then
  exit 1
fi
eval set -- $ARGS

# default options
HELP=no
LISP=guile
verbose=no
VERSION=no
OUTPUT=no
INTERACTIVE=no
WISP="./wisp.py"

# check, if the default wisp exists and can be executed. If not, fall
# back to wisp.py (which might be in PATH).
if [ ! -x $WISP ]; then
    WISP="wisp.py"
fi

while [ $# -gt 0 ]; do
    case "$1" in
        -h | --help)        HELP=yes;;
        -l | --lisp)        LISP="$2"; shift;;
        -o | --output)      OUTPUT="$2"; shift;;
        -w | --wisp)        WISP="$2"; shift;;
        -v | --verbose)     VERBOSE=yes;;
        -i | --interactive) INTERACTIVE=yes;;
        --version)          VERSION=yes;;
        --)              shift; break;;
    esac
    shift
done

# Provide help output

if [[ $HELP == "yes" ]]; then
    echo "$0 [-h] [-l] [-v] [-i] [[- | SCRIPT] ...]
        Run multiline commands through wisp or execute the SCRIPT.
        If you use - as script, it reads the script from standard input.
        
        -h | --help)        This help output.
        -l | --lisp)        Select the Lisp interpreter to call. 
                            Options: guile, emacs or the full command to use. 
                            If you use emacs, note that (message) writes to stdout.
                            Example: -l \"guile -s /dev/stdin/\"
        -o | --output)      Save the executed wisp code to this file.
        -w | --wisp)        Select the wisp preprocessor to use.
        -v | --verbose)     Provide verbose output.
        -i | --interactive) Run interactive commands after reading scripts. 
                            Does not work with reading from a pipe (standard input).
        --version)          Print the version string of this script.
"
    exit 0
fi

if [[ $VERSION == "yes" ]]; then
    echo "$version"
    exit 0
fi

# Select the lisp interpreter

if [[ "${LISP}" == "guile" ]]; then
    INTERPRETER="guile -s /dev/stdin"
# the following commented code does not work, sadly. I do not understand, why.
# elif [[ "${LISP}" == "emacs" ]]; then # thanks to http://superuser.com/a/487329
#    INTERPRETER="emacs -Q --batch --eval '(with-temp-buffer (progn (condition-case nil (let (line) (while (setq line (read-string \"\")) (insert line)(newline)(forward-char 1))) (error nil)) (eval-current-buffer)))'"
else
    INTERPRETER="${LISP}"
fi

## parameters

# if scripts are given, read those.

if [ $# -gt 0 ]; then
  # Remaining parameters can be processed
  for ARG in "$@"; do
      # ignore !#, which just finishes a shebang line comment for scheme
      if [[ "${ARG}" == "!#" ]]; then 
          continue
      fi
      l=$(${WISP} "${ARG}")
      lispcode="${lispcode}
${l}"
  done
  # if we do not need additional interactive commands, we only need to
  # execute the lisp.
  if [[ x"${INTERACTIVE}" == x"no" ]]; then
      if [[ x"${LISP}" == x"emacs" ]]; then
          emacs -Q --batch --eval "${lispcode}"
      else
          echo "${lispcode}" | eval "${INTERPRETER}"
      fi
      exit 0
  fi
fi

## Read code from interactive input

echo ";; Welcome to wisp. Please enter your code. 
;; Finish with two linebreaks, then execute with CTRL-D."

while IFS= read wispi ; do 
    wisp="${wisp}
${wispi}" 
done 

# if the user requests output, copy the pipe with tee and append it to
# the output

if [[ x"$OUTPUT" != x"no" ]]; then
    echo "${wisp}" >> "$OUTPUT"
fi

# convert the input to lisp

l=$(echo "${wisp}" |  ${WISP} - )
lispcode="${lispcode}
${l}"

# now run the code

if [[ x"${LISP}" == x"emacs" ]]; then
    emacs -Q --batch --eval "${lispcode}"
else
    echo "${lispcode}" | eval "${INTERPRETER}"
fi