;;; elephant.el --- Remember variables and modes -*- lexical-binding: t; -*-

;;; Code:

(defmacro elephant-remember (alist)
  "Setup a closure remembering symbols to apply with
`remember-reset'.  The variables will be renamed using TEMPLATE.
ALIST contains cells of the form (SYMBOL . NEW-VALUE), where
SYMBOL is a variable or mode name, and its value is what to set
after `remember-set'."
  (unless lexical-binding
    (user-error "`elephant' requires lexical binding."))

  (let* ((template (format "elephant--%s-%%s" (gensym)))
         (reset-fn (intern (format template "reset"))))
    (cl-destructuring-bind (let-list fn-set-list fn-reset-list)
        (cl-loop
         for (sym . val) in (if (symbolp alist) (symbol-value alist) alist)
         as rem = (intern (format template sym))

         collect (list rem sym)
         into let-list

         collect (cond ((eq val 'enable)
                        `(,sym +1))
                       ((eq val 'disable)
                        `(,sym -1))
                       (t `(setq-local ,sym ,val)))
         into fn-set-list

         collect (cond ((memq val '(enable disable))
                        `(progn (,sym (if ,rem +1 -1))
                                (fmakunbound ',rem)))
                       (t `(progn (setq-local ,sym ,rem)
                                  (makunbound ',rem))))
         into fn-reset-list

         finally return (list let-list
                              fn-set-list
                              fn-reset-list))
      `(progn
         (defvar-local ,reset-fn nil
           "Function to recall values from `elephant-remember'.")
         (let ,let-list
           (setf (symbol-function ',reset-fn)
                 (lambda ()
                   ,@fn-reset-list
                   (redraw-display)
                   (fmakunbound ',reset-fn))))
         ,@fn-set-list
         ',reset-fn))))

(defun elephant-forget ()
  "Forget all symbols generated by `elephant-remember'."
  )

(provide 'elephant)
;;; elephant.el ends here
