;; TODO prelude
(defun string/join (xs)
  (let (accumulator "")
    (while (cons? xs)
      (if accumulator
        (setq accumulator (+ accumulator " " (car xs)))
        (setq accumulator (car xs))
        )
      (setq xs (cdr xs))
      )
    accumulator
    )
  )

(declare-command "q" () (red/quit))
(declare-command "q!" () (red/quit #t))
(declare-command
  "w" (&optional filename)
  (if filename
    (red/buffer/write filename)
    (red/buffer/write)
    )
  )
(declare-command
  "wq" ()
  (red/buffer/write)
  (red/quit)
  )
(declare-command
  "e" (&optional filename)
  (if filename
    (red/buffer/open filename)
    )
  )
(declare-command
  "e!" (&optional filename)
  (if filename
    (red/buffer/open filename #t)
    )
  )
(declare-command
  "source" (filename)
  (import filename)
  )

;; TODO only allow some keys to be set
;; TODO at least check that the key is defined
(declare-command
  "set" (key &rest value)
  (let* (
         key-symbol (symbol (+ "red/" key))
         expression (string/join value)
         eval-result (if (nil? value) '(ok #t) (read-eval expression))
         )
    (cond
      ((result/ok? eval-result) (set key-symbol (cadr eval-result)))
      (&otherwise (red/message (+ "error: " (cadr eval-result))))
      )
    )
  )
(declare-command
  "unset" (key)
  (let (key-symbol (symbol (+ "red/" key)))
    (set key-symbol nil)
    )
  )
(declare-command
  "eval" (&rest expressions)
  (let*  (
          expression (string/join expressions)
          eval-result (read-eval expression)
          )
    (cond
      ((result/ok? eval-result) (red/status (+ "ok: " (cadr eval-result))))
      (&otherwise (red/message (+ "error: " (cadr eval-result))))
      )
    )
  )
