;; External API

(defmacro ignore (&rest expressions) nil)

(defmacro declare-key (mode seq action-head &rest action-tail)
  (let (bind-function (symbol (+ "red/bind-" (->string mode) "-hook")))
    `(,bind-function ,seq (lambda () (progn ,action-head ,@action-tail)))
    )
  )

(defmacro declare-command
  (command args &rest body)
  (unless (cons? body)
    (error "No body provided in declare-command"))
  (unless (list? args)
    (error "Argument list must either be a NIL or a list"))
  (let*
    (
     args-has-rest (find (lambda (x) (= x '&rest)) args)
     lambda-args (if args-has-rest
                   `(,@args)
                   `(,@args &rest _)
                   )
     )
    `(setq
       _red/command-table
       (cons
         (list ,command (lambda ,lambda-args ,@body))
         _red/command-table
         )
       )
    )
  )
;; (defmacro declare-command
;;   (command args body-head &rest body-tail)
;;   ;; TODO auto-rest?
;;   `(setq
;;      _red/command-table
;;      (cons
;;        (list ,command (lambda (,@args &rest _) ,body-head ,@body-tail))
;;        _red/command-table
;;        )
;;      )
;;   )

(defun try-import (path)
  (when (fs/file? path) (import path) #t))

(setq _red/command-table nil)

;; Hooks for the editor/buffer events
(defun _red/lookup-command (name)
  (find (lambda (cmd) (= name (car cmd))) _red/command-table)
  )

(defun _red/root-command-hook (command &rest args)
  (let (entry (_red/lookup-command command))
    (if entry
      (apply (cadr entry) args)
      (red/message (+ "Unhandled command: :" command))
      )
    )
  )

(defun _red/root-post-render-hook (width height)
  nil
  )

;; Bind the hooks
(red/bind-command-hook _red/root-command-hook)
(red/bind-post-render-hook _red/root-post-render-hook)

;; Child modules
(import "keyboard.lysp")
(import "command.lysp")
(import "highlight.lysp")

;; User configuration
(try-import "/etc/red/init.lysp")
(try-import (+ (fs/home-directory) "/.red.d/init.lysp"))
