doomemacs/modules/config/tutorial/autoload/tutorial.el

90 lines
3.3 KiB
EmacsLisp

;;; config/tutorial/autoload/tutorial.el -*- lexical-binding: t; -*-
(defvar doom-tutorial-hist-file
(expand-file-name "tutorial-progress.el" doom-cache-dir)
"Directory where tutorial progress information is saved.")
(defvar doom-tutorial--progress
(when (file-exists-p doom-tutorial-hist-file)
(with-temp-buffer
(insert-file-contents doom-tutorial-hist-file)
(read (current-buffer))))
"An alist of tutorials and progress information.")
(defun doom-tutorial--save-progress ()
"Write `doom-tutorial--progress' to `doom-tutorial-hist-file'."
(with-temp-buffer
(insert
";; -*- mode: emacs-lisp -*-\n"
";; Tutorial progress file, automatically generated by `doom-tutorial--save-progress'.\n"
"\n")
(let ((print-length nil)
(print-level nil)
(print-quoted t))
(prin1 doom-tutorial--progress
(current-buffer)))
(insert ?\n)
(condition-case err
(write-region (point-min) (point-max) doom-tutorial-hist-file nil
(unless (called-interactively-p 'interactive) 'quiet))
(file-error
(lwarn '(doom-tutorial-hist-file) :warning "Error writing `%s': %s"
doom-tutorial-hist-file (caddr err))))))
(defvar doom-tutorials--loaded nil
"An alist of loaded tutorials.")
(defun doom-tutorial-normalise-plist (somelist)
(cdr (cl-reduce
(lambda (result new)
(if (keywordp new)
(progn (push new result)
(push nil result))
(push new (car result)))
result)
(nreverse somelist)
:initial-value (list nil))))
;;;###autoload
(defmacro define-tutorial! (name &optional docstring &rest body)
(declare (doc-string 2) (indent defun))
(unless (stringp docstring)
(push docstring body)
(setq docstring nil))
(let ((parameters (doom-tutorial-normalise-plist body)))
(when (plist-get parameters :setup)
(plist-put parameters :setup
(append (list #'progn) (plist-get parameters :setup))))
(when (plist-get parameters :teardown)
(plist-put parameters :teardown
(append (list #'progn) (plist-get parameters :teardown))))
`(progn
(defun ,(intern (format "doom-tutorial-%s" name)) (&optional autotriggered)
,docstring
(interactive "p")
(if autotriggered
(doom-tutorial-run ',name)
(doom-tutorial-run-maybe ',name)))
(doom-tutorial-register ',name ',parameters))))
(defun doom-tutorial-register (name parameters)
(push (cons name parameters) doom-tutorials--loaded)
(unless (assoc name doom-tutorial--progress)
(push (list name :skipped nil :complete nil :page 0)
doom-tutorial--progress))
(dolist (target (plist-get parameters :triggers))
(advice-add target :after name))
(dolist (filepattern (plist-get parameters :file-triggers))
(add-to-list 'doom-tutorials--file-triggers (cons (eval filepattern) name))))
;;;###autoload
(defun doom-tutorial-load-modules ()
(let (loaded-tutorials)
(maphash (lambda (key _plist)
(let ((tutorial-file (doom-module-path (car key) (cdr key) "tutorial.el")))
(when (file-exists-p tutorial-file)
(push (cdr key) loaded-tutorials)
(load tutorial-file 'noerror 'nomessage))))
doom-modules)
loaded-tutorials))