Merge branch 'maint'

This commit is contained in:
Nicolas Goaziou 2019-04-29 20:49:09 +02:00
commit 9bbae3ce8f
2 changed files with 85 additions and 93 deletions

View File

@ -83,51 +83,61 @@ directly, use instead:
;;; Functions ;;; Functions
(defun org-macro--collect-macros () (defun org-macro--set-template (name value templates)
"Set template for the macro NAME.
VALUE is the template of the macro. The new value override the
previous one, unless VALUE is nil. TEMPLATES is the list of
templates. Return the updated list."
(when value
(let ((old-definition (assoc name templates)))
(if old-definition
(setcdr old-definition value)
(push (cons name value) templates))))
templates)
(defun org-macro--collect-macros (&optional files templates)
"Collect macro definitions in current buffer and setup files. "Collect macro definitions in current buffer and setup files.
Return an alist containing all macro templates found." Return an alist containing all macro templates found.
(letrec ((collect-macros
(lambda (files templates) FILES is a list of setup files names read so far, used to avoid
;; Return an alist of macro templates. FILES is a list circular dependencies. TEMPLATES is the alist collected so far.
;; of setup files names read so far, used to avoid The two arguments are used in recursive calls."
;; circular dependencies. TEMPLATES is the alist (let ((case-fold-search t))
;; collected so far. (org-with-point-at 1
(let ((case-fold-search t)) (while (re-search-forward "^[ \t]*#\\+\\(MACRO\\|SETUPFILE\\):" nil t)
(org-with-wide-buffer (let ((element (org-element-at-point)))
(goto-char (point-min)) (when (eq (org-element-type element) 'keyword)
(while (re-search-forward (let ((val (org-element-property :value element)))
"^[ \t]*#\\+\\(MACRO\\|SETUPFILE\\):" nil t) (if (equal "MACRO" (org-element-property :key element))
(let ((element (org-element-at-point))) ;; Install macro in TEMPLATES.
(when (eq (org-element-type element) 'keyword) (when (string-match "^\\(\\S-+\\)[ \t]*" val)
(let ((val (org-element-property :value element))) (let ((name (match-string 1 val))
(if (equal (org-element-property :key element) "MACRO") (value (substring val (match-end 0))))
;; Install macro in TEMPLATES. (setq templates
(when (string-match (org-macro--set-template name value templates))))
"^\\(.*?\\)\\(?:\\s-+\\(.*\\)\\)?\\s-*$" val) ;; Enter setup file.
(let* ((name (match-string 1 val)) (let* ((uri (org-strip-quotes val))
(template (or (match-string 2 val) "")) (uri-is-url (org-file-url-p uri))
(old-cell (assoc name templates))) (uri (if uri-is-url
(if old-cell (setcdr old-cell template) uri
(push (cons name template) templates)))) (expand-file-name uri))))
;; Enter setup file. ;; Avoid circular dependencies.
(let* ((uri (org-strip-quotes (org-trim val))) (unless (member uri files)
(uri-is-url (org-file-url-p uri)) (with-temp-buffer
(uri (if uri-is-url (unless uri-is-url
uri (setq default-directory (file-name-directory uri)))
(expand-file-name uri)))) (org-mode)
;; Avoid circular dependencies. (insert (org-file-contents uri 'noerror))
(unless (member uri files) (setq templates
(with-temp-buffer (org-macro--collect-macros
(unless uri-is-url (cons uri files) templates)))))))))))
(setq default-directory (let ((macros `(("author" . ,(org-macro--find-keyword-value "AUTHOR"))
(file-name-directory uri))) ("email" . ,(org-macro--find-keyword-value "EMAIL"))
(org-mode) ("title" . ,(org-macro--find-keyword-value "TITLE" t))
(insert (org-file-contents uri 'noerror)) ("date" . ,(org-macro--find-date)))))
(setq templates (pcase-dolist (`(,name . ,value) macros)
(funcall collect-macros (cons uri files) (setq templates (org-macro--set-template name value templates))))
templates))))))))))) templates))
templates))))
(funcall collect-macros nil nil)))
(defun org-macro-initialize-templates () (defun org-macro-initialize-templates ()
"Collect macro templates defined in current buffer. "Collect macro templates defined in current buffer.
@ -161,27 +171,12 @@ a file, \"input-file\" and \"modification-time\"."
(prin1-to-string (prin1-to-string
(file-attribute-modification-time (file-attribute-modification-time
(file-attributes visited-file)))))))) (file-attributes visited-file))))))))
;; Install built-in macros. ;; Install generic macros.
(list (list
'("n" . "(eval (org-macro--counter-increment $1 $2))") '("n" . "(eval (org-macro--counter-increment $1 $2))")
`("author" . ,(org-macro--find-keyword-value "AUTHOR"))
`("email" . ,(org-macro--find-keyword-value "EMAIL"))
'("keyword" . "(eval (org-macro--find-keyword-value $1))") '("keyword" . "(eval (org-macro--find-keyword-value $1))")
'("time" . "(eval (format-time-string $1))") '("time" . "(eval (format-time-string $1))")
`("title" . ,(org-macro--find-keyword-value "TITLE")) '("property" . "(eval (org-macro--get-property $1 $2))")))))
'("property" . "(eval (org-macro--get-property $1 $2))")
`("date" .
,(let* ((value (org-macro--find-keyword-value "DATE"))
(date (org-element-parse-secondary-string
value (org-element-restriction 'keyword))))
(if (and (consp date)
(not (cdr date))
(eq 'timestamp (org-element-type (car date))))
(format "(eval (if (org-string-nw-p $1) %s %S))"
(format "(org-timestamp-format '%S $1)"
(org-element-copy (car date)))
value)
value)))))))
(defun org-macro-expand (macro templates) (defun org-macro-expand (macro templates)
"Return expanded MACRO, as a string. "Return expanded MACRO, as a string.
@ -332,21 +327,39 @@ by `org-link-search', or the empty string."
(error "Macro property failed: cannot find location %s" location)))) (error "Macro property failed: cannot find location %s" location))))
(org-entry-get nil property 'selective))) (org-entry-get nil property 'selective)))
(defun org-macro--find-keyword-value (name) (defun org-macro--find-keyword-value (name &optional collect)
"Find value for keyword NAME in current buffer. "Find value for keyword NAME in current buffer.
KEYWORD is a string. Return value associated to the keywords Return value associated to the keywords named after NAME, as
named after NAME, as a string, or nil." a string, or nil. When optional argument COLLECT is non-nil,
concatenate values, separated with a space, from various keywords
in the buffer."
(org-with-point-at 1 (org-with-point-at 1
(let ((regexp (format "^[ \t]*#\\+%s:" (regexp-quote name))) (let ((regexp (format "^[ \t]*#\\+%s:" (regexp-quote name)))
(case-fold-search t) (case-fold-search t)
(result nil)) (result nil))
(while (re-search-forward regexp nil t) (catch :exit
(let ((element (org-element-at-point))) (while (re-search-forward regexp nil t)
(when (eq 'keyword (org-element-type element)) (let ((element (org-element-at-point)))
(setq result (concat result (when (eq 'keyword (org-element-type element))
" " (let ((value (org-element-property :value element)))
(org-element-property :value element)))))) (if (not collect) (throw :exit value)
(and result (org-trim result))))) (setq result (concat result " " value)))))))
(and result (org-trim result))))))
(defun org-macro--find-date ()
"Find value for DATE in current buffer.
Return value as a string."
(let* ((value (org-macro--find-keyword-value "DATE"))
(date (org-element-parse-secondary-string
value (org-element-restriction 'keyword))))
(if (and (consp date)
(not (cdr date))
(eq 'timestamp (org-element-type (car date))))
(format "(eval (if (org-string-nw-p $1) %s %S))"
(format "(org-timestamp-format '%S $1)"
(org-element-copy (car date)))
value)
value)))
(defun org-macro--vc-modified-time (file) (defun org-macro--vc-modified-time (file)
(save-window-excursion (save-window-excursion

View File

@ -103,18 +103,7 @@
"#+MACRO: macro expansion\n* COMMENT H1\n** H2\n<point>{{{macro}}}" "#+MACRO: macro expansion\n* COMMENT H1\n** H2\n<point>{{{macro}}}"
(org-macro-initialize-templates) (org-macro-initialize-templates)
(org-macro-replace-all org-macro-templates) (org-macro-replace-all org-macro-templates)
(org-with-wide-buffer (buffer-string))))) (org-with-wide-buffer (buffer-string))))))
;; User-defined macros take precedence over built-in macros.
(should
(equal
"foo"
(org-test-with-temp-text
"#+MACRO: title foo\n#+TITLE: bar\n<point>{{{title}}}"
(org-macro-initialize-templates)
(org-macro-replace-all org-macro-templates)
(goto-char (point-max))
(buffer-substring-no-properties (line-beginning-position)
(line-end-position))))))
(ert-deftest test-org-macro/property () (ert-deftest test-org-macro/property ()
"Test {{{property}}} macro." "Test {{{property}}} macro."
@ -312,16 +301,6 @@
"#+keyword: value\n<point>{{{keyword(KEYWORD)}}}" "#+keyword: value\n<point>{{{keyword(KEYWORD)}}}"
(org-macro-initialize-templates) (org-macro-initialize-templates)
(org-macro-replace-all org-macro-templates) (org-macro-replace-all org-macro-templates)
(buffer-substring-no-properties
(line-beginning-position) (point-max)))))
;; Replace macro with keyword's value.
(should
(equal
"value value2"
(org-test-with-temp-text
"#+keyword: value\n#+keyword: value2\n<point>{{{keyword(KEYWORD)}}}"
(org-macro-initialize-templates)
(org-macro-replace-all org-macro-templates)
(buffer-substring-no-properties (buffer-substring-no-properties
(line-beginning-position) (point-max)))))) (line-beginning-position) (point-max))))))