;;; 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))