On Thu, Nov 22, 2018 at 4:06 PM Matt Price wrote: > > > On Thu, Nov 22, 2018 at 1:19 PM Matt Price wrote: > >> It would be nice for me to overlay the macro invocations with the values >> that they will evaluate to on export. I guess I would have to figure out >> when to trigger recalculation of the values (maybe not too often, say only >> when the macro is first created, when it's edited or deleted/deformed, and >> perhaps on structure editing. >> >> I do not understand emacs overlays very well so this feels a little >> daunting to me. Does anyone out there have ideas about how to do it >> effectively? >> >> > This is what I've come up with; it feels somewhat close but not quite > there yet. I can create, remove, and the overlays, which is great. What I > miss is the awesomeness of the way that overlays work with org links. I > love how the link target and the enclosing [[ ][ ]] are invisible until I > delete one of the "[" elements. However, with my code, the whole macro > expression {{{macroname}}} ius invisible until I delete the whole thing, at > which point the overlay helpfully disappears. Is htere a way to get > something like the link behaviour? > Oops! Here is the actual code (a bit long actually! Largely stolen from org source code). #+begin_src emacs-lisp (defun mwp-show-macros () (interactive) (remove-overlays (point-min) (point-max) 'macro-ov-p t) (save-excursion (goto-char (point-min)) ;; keeping this properties/keywordsstuff b/c I don't quite understand it (let* ((keywords nil) (properties-regexp (format "\\`EXPORT_%s\\+?\\'" (regexp-opt keywords))) record) (while (re-search-forward "{{{[-A-Za-z0-9_]" nil t) (unless (save-match-data (org-in-commented-heading-p)) (let* ((datum (save-match-data (org-element-context))) (type (org-element-type datum)) (macro (cond ((eq type 'macro) datum) ;; In parsed keywords and associated node ;; properties, force macro recognition. ((or (and (eq type 'keyword) (member (org-element-property :key datum) keywords)) (and (eq type 'node-property) (string-match-p properties-regexp (org-element-property :key datum)))) (save-excursion (goto-char (match-beginning 0)) (org-element-macro-parser)))))) (when macro (let* ((key (org-element-property :key macro)) (value (org-macro-expand macro org-macro-templates)) (begin (org-element-property :begin macro)) (end (save-excursion (goto-char (org-element-property :end macro)) (skip-chars-backward " \t") (point))) (signature (list begin macro (org-element-property :args macro)))) ;; Avoid circular dependencies by checking if the same ;; macro with the same arguments is expanded at the ;; same position twice. (cond ((member signature record) (error "Circular macro expansion: %s" key)) (value (push signature record) (let ((ov (make-overlay begin end))) (overlay-put ov 'invisible t) (overlay-put ov 'evaporate t) (overlay-put ov 'macro-ov-p t) (overlay-put ov 'before-string value ))) ;; Special "results" macro: if it is not defined, ;; simply leave it as-is. It will be expanded in ;; a second phase. ((equal key "results")) (t ;; (error "Undefined Org macro: %s; aborting" ;; (org-element-property :key macro)) ))))))))) (org-macro--counter-initialize) (setq-local mwp-macro-overlays t) ) (defun mwp-hide-macros () (interactive) (remove-overlays (point-min) (point-max) 'macro-ov-p t) (setq-local mwp-macro-overlays nil) ;; (cl-loop for o in (overlays-in (point-min) (point-max)) ;; if (overlay-get o 'macro-ov-p) ;; ()) ) (defun mwp-toggle-macros () (interactive) (if mwp-macro-overlays (mwp-hide-macros) (mwp-show-macros)) ) (defvar-local mwp-macro-overlays nil) #+end_src