#!/usr/bin/env sh
# -*- wisp -*-
guile-2.0 -L $(dirname $(dirname $(realpath "$0"))) -c '(import (language wisp spec))'
exec guile-2.0 -L $(dirname $(dirname $(realpath "$0"))) --language=wisp -e '(examples commandline-handling)' -s "$0" "$@"
; !#

;; This is an example for complex commandline handling for a tool
;; which takes a list of tasks to run as arguments.

define-module : examples commandline-handling
              . #:export : main

import
    ice-9 format
    srfi srfi-1
    srfi srfi-37
    ice-9 popen ; for pipe-open*
    ice-9 rdelim ; for read-string



define : runcommand cmd
  let*
    : port : open-input-pipe cmd
      output : read-string port
    display output
    newline


define : run-my-shell-command
    . "Run a predefined shell command"
    let
      :
        cmd
          string-join
            list "for i in {1..5}; do echo $i; done"
      when : debug?
        display cmd : current-error-port
        newline : current-error-port
      runcommand cmd


define : help . args ; args used for simpler option parsing
         if
              and
                 >= (length args) 3
                 third args
                 member (string->symbol (third args)) : task-list ; help got an argument
              let*
                  : fun : string->symbol : third args
                    mod : resolve-module '(examples commandline-handling)
                    doc : procedure-documentation : module-ref mod fun
                  format #t "~a\n\n~a\n" fun doc
              format #t "Usage: commandline-handling.w [option ...] [--] [task ...]

Run the selected tasks given on the commandline.

  -h [TASK] --help[=TASK]
                 display this help or infomation about the task and exit
  -V --version   output version information and exit
     --tasks     list all available tasks
  -d [LEVEL] --debug[=LEVEL]
                 set logging to debug or to the given level

Defined tasks:

  ~a

" : string-join : map symbol->string : task-list
         exit 0


define : version
         display "commandline-handling 0.0.0

Copyright (C) 2016 Arne Babenhauserheide, for IMK-ASF at Karlsruhe Institute for Technology
See the file COPYING. There is NO warranty.
"

define help-option
  option '(#\h "help")
          . #f #t help

define version-option
  option '(#\V "version")
          . #f #f
          λ : option name arg operands
              version
              exit 0

define : debug?
    equal? 'debug : assoc-ref %options 'log-level


define debug-option
  let
    : required #f
      optional #t ; can take an argument
    option '(#\d "debug")
          . required optional
          λ : option name arg operands
              if arg
                 set! %options : alist-cons 'log-level (string->symbol arg) %options
                 set! %options : alist-cons 'log-level 'debug %options
              format : current-error-port
                     . "debug: activate log level ~a\n"
                     if arg arg 'debug
              . operands


define utility-procedures
    ' parse-args main run-task task-list runcommand debug?

define debug-procedures
    ' tasks help options version

define : task-list
      let : : mod : resolve-module '(examples commandline-handling)
          delete #f
                module-map
                    λ : x y
                        if
                          and
                            procedure? : module-ref mod x
                            not : member x utility-procedures
                            if : equal? 'debug : assoc-ref %options 'log-level
                               . #t
                               not : member x debug-procedures
                          . x
                          . #f
                    . mod

define : tasks . args
    map : λ (x) (display x)(newline)
          task-list

define tasks-option
  option '("tasks")
          . #f #f
          λ : option name arg operands
              tasks
              exit 0


define %options
    '
      log-level . info

define : options
         format : current-error-port
                . "Currently active options: ~A\n"
                . %options

define %option-list
    list help-option version-option debug-option tasks-option


define : run-task task
       let*
         : mod : resolve-module '(examples commandline-handling)
           t : string->symbol task
           var : module-variable mod t
         cond
           var
             let : : T : module-ref mod t
               if : procedure? T
                  T
                  format : current-error-port
                         . "Not a procedure: ~a refers to ~a\n" task var
           else
              format : current-error-port
                     . "Unknown task: ~a\n" task


define : parse-args args
    let
      :
        tasks
           reverse
            args-fold args
             . %option-list
             λ : option name arg operands
               format : current-error-port
                      . "unrecognized command line argument name: ~a arg: ~a operands: ~a\n"
                      . name arg operands
               exit 1
             λ : operand operands
               cons operand operands
             . '()
      for-each
       λ : task
           if : and (equal? task "help") (not (null? (delete "help" tasks)))
                map
                  λ : x
                      help #f #f x
                  delete "help" tasks
                run-task task
       . tasks

define* : main args
    if : null? : cdr args
         help
         parse-args : cdr args