diff options
Diffstat (limited to 'dot_config/emacs/lisp/org-demo-macro.el')
| -rw-r--r-- | dot_config/emacs/lisp/org-demo-macro.el | 66 |
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) |
