summaryrefslogtreecommitdiff
path: root/dot_config/emacs/lisp/org-demo-macro.el
diff options
context:
space:
mode:
Diffstat (limited to 'dot_config/emacs/lisp/org-demo-macro.el')
-rw-r--r--dot_config/emacs/lisp/org-demo-macro.el66
1 files changed, 66 insertions, 0 deletions
diff --git a/dot_config/emacs/lisp/org-demo-macro.el b/dot_config/emacs/lisp/org-demo-macro.el
new file mode 100644
index 0000000..36f4100
--- /dev/null
+++ b/dot_config/emacs/lisp/org-demo-macro.el
@@ -0,0 +1,66 @@
+;;; Execute things in Org presentations
+;; https://www.howardism.org/Technical/Emacs/demonstrations-part-two.html
+(defun demo-match (triggers state)
+ "Return t if all elements of TRIGGERS are in STATE.
+Where TRIGGERS and STATE are lists of key/value tuple
+pairs, e.g. `((:a 1) (:b 2))'."
+ ;; If difference returns anything, we've failed:
+ (not (seq-difference triggers state)))
+
+(defvar demo-prev-state
+ (make-hash-table :test 'equal)
+ "Matched states in keys, and store number
+of matches as values.")
+
+(defun demo-state-match (triggers state)
+ "Return non-nil if STATE contains all TRIGGERS.
+The state also includes the number of times the triggers
+matched during previous calls. We do this by keeping track
+of the number of successful calls, and incrementing
+the iteration... if this function returns non-nil."
+ ;; If the first element is either parameter is NOT a list,
+ ;; we group it into a list of tuples:
+ (when (not (listp (car triggers)))
+ (setq triggers (seq-partition triggers 2)))
+ (when (not (listp (car state)))
+ (setq state (seq-partition state 2)))
+
+ (let* ((iteration (gethash state demo-prev-state 0))
+ (itful-state (cons `(:i ,iteration) state)))
+ (when (demo-match triggers itful-state)
+ (puthash state (1+ iteration) demo-prev-state))))
+
+(defmacro demo-step (&rest forms)
+ "Execute a function based matching list of states at point.
+Where FORMS is an even number of _matcher_ and _function_ to call.
+
+Probably best to explain this in an example:
+
+(demo-step
+ (:buffer \"demonstrations.py\") (message \"In a buffer\")
+ (:mode 'dired-mode) (message \"In a dired\")
+ (:head \"Raven Civilizations\" (message \"In an org file\")))
+
+Calling this function displays a message based on position of the
+point in a particular buffer or place in a heading in an Org file.
+
+You can use the `:i' to specify different forms to call when
+the trigger matches the first time, versus the second time, etc.
+
+(demo-step
+ (:buffer \"demonstrations.org\" :i 0) (message \"First time\")
+ (:buffer \"demonstrations.org\" :i 1) (message \"Second time\"))"
+ (interactive)
+ `(let ((state (list :buffer (buffer-name)
+ :mode major-mode
+ :head (when (eq major-mode 'org-mode)
+ (org-get-heading)))))
+ (cond
+ ,@(seq-map (lambda (tf-pair)
+ (seq-let (trigger func) tf-pair
+ (list
+ `(demo-state-match ',trigger state)
+ func)))
+ (seq-partition forms 2)))))
+
+(provide 'org-demo-macro)