(local { : Gtk  } (require :lgi))
(local { : view } (require :fennel))

(local commands {})
(local Buffer (require :buffer))

;; when a command is invoked from a binding, the binding may provide
;; some or all of the parameter values. when there are missing params,
;; or when invoked from the commander, `invoke` prompts for the
;; missing params, offering default values which were specified by
;; define-command

(fn define-command [name function params]
  ;; required parameter names and default arguments
  (let [v {:name name :function function :params params}]
    (tset commands name v)))

(define-command "quit-browser" #(Gtk.main_quit) {})

(define-command
 "visit-location"
 (fn [{:url url :buffer buffer}]
   (buffer:visit url))
 {:buffer (fn [] (Buffer.current))
  :url #(do "http://www.example.com")
  })

(fn prompt-missing-args [params explicit-args]
  (collect [k v (pairs params)]
    (values k (or (. explicit-args k) (v)))))

(fn invoke [s args]
  (match (. commands s)
    {:function f :params p}
    (let [prompted-args (prompt-missing-args p args)]
      (f prompted-args))
    nil (print "undefined command " s)))


{ : invoke }