mirror of
https://git.savannah.gnu.org/git/emacs/org-mode.git
synced 2024-09-29 20:07:46 +00:00
org-capture: Expand interactive placeholders last
* lisp/org-capture.el (org-capture-templates): Update docstring. (org-capture-fill-template): Expand interactive placeholders when the template is otherwise completely filled. This restores the previous behaviour for template's expansion.
This commit is contained in:
parent
11291ffcd0
commit
5c13a6b765
|
@ -231,8 +231,8 @@ be replaced with content and expanded:
|
||||||
%(sexp) Evaluate elisp `(sexp)' and replace it with the results.
|
%(sexp) Evaluate elisp `(sexp)' and replace it with the results.
|
||||||
Only placeholders pre-existing within the template, or
|
Only placeholders pre-existing within the template, or
|
||||||
introduced with %[pathname] are expanded this way. Since this
|
introduced with %[pathname] are expanded this way. Since this
|
||||||
happens very late in the process, other %-escapes can be used to
|
happens after expanding non-interactive %-escapes, those can
|
||||||
fill the expression.
|
be used to fill the expression.
|
||||||
%<...> The result of format-time-string on the ... format specification.
|
%<...> The result of format-time-string on the ... format specification.
|
||||||
%t Time stamp, date only.
|
%t Time stamp, date only.
|
||||||
%T Time stamp with date and time.
|
%T Time stamp with date and time.
|
||||||
|
@ -261,9 +261,8 @@ be replaced with content and expanded:
|
||||||
A default value and a completion table ca be specified like this:
|
A default value and a completion table ca be specified like this:
|
||||||
%^{prompt|default|completion2|completion3|...}.
|
%^{prompt|default|completion2|completion3|...}.
|
||||||
%? After completing the template, position cursor here.
|
%? After completing the template, position cursor here.
|
||||||
%number Insert the text entered at the nth %^{prompt}, where `number' is a
|
%\\N Insert the text entered at the nth %^{prompt}, where N
|
||||||
number, starting from 1. These placeholders are expanded as the
|
is a number, starting from 1.
|
||||||
last step of the process.
|
|
||||||
|
|
||||||
Apart from these general escapes, you can access information specific to
|
Apart from these general escapes, you can access information specific to
|
||||||
the link type that is created. For example, calling `org-capture' in emails
|
the link type that is created. For example, calling `org-capture' in emails
|
||||||
|
@ -1604,7 +1603,6 @@ The template may still contain \"%?\" for cursor positioning."
|
||||||
(erase-buffer)
|
(erase-buffer)
|
||||||
;; Turn on org-mode in temp buffer, set local variables. This
|
;; Turn on org-mode in temp buffer, set local variables. This
|
||||||
;; is to support completion in interactive prompts
|
;; is to support completion in interactive prompts
|
||||||
(let ((org-inhibit-startup t)) (org-mode))
|
|
||||||
(insert template)
|
(insert template)
|
||||||
(goto-char (point-min))
|
(goto-char (point-min))
|
||||||
(org-capture-steal-local-variables buffer)
|
(org-capture-steal-local-variables buffer)
|
||||||
|
@ -1629,140 +1627,151 @@ The template may still contain \"%?\" for cursor positioning."
|
||||||
;; Mark %() embedded elisp for later evaluation.
|
;; Mark %() embedded elisp for later evaluation.
|
||||||
(org-capture--expand-embedded-elisp 'mark)
|
(org-capture--expand-embedded-elisp 'mark)
|
||||||
|
|
||||||
(let ((regexp "%\\(:[-a-za-z]+\\|<\\([^>\n]+\\)>\\|[aAcfFikKlntTuUx]\\|\
|
;; Expand non-interactive templates.
|
||||||
\\^\\(?:{\\([^}]*\\)}\\)?\\([CgGLptTuU]\\)?\\)")
|
(let ((regexp "%\\(:[-a-za-z]+\\|<\\([^>\n]+\\)>\\|[aAcfFikKlntTuUx]\\)"))
|
||||||
(strings))
|
(save-excursion
|
||||||
(while (re-search-forward regexp nil t)
|
(while (re-search-forward regexp nil t)
|
||||||
(let ((pos (copy-marker (match-beginning 0)))
|
(let ((pos (copy-marker (match-beginning 0)))
|
||||||
(end (copy-marker (match-end 0)))
|
(end (copy-marker (match-end 0)))
|
||||||
(value (match-string 1))
|
(value (match-string 1))
|
||||||
(time-string (match-string 2))
|
(time-string (match-string 2)))
|
||||||
(prompt (match-string-no-properties 3))
|
(unless (org-capture-escaped-%)
|
||||||
(key (match-string 4)))
|
(goto-char pos)
|
||||||
(unless (org-capture-escaped-%)
|
(delete-region pos end)
|
||||||
(goto-char pos)
|
(pcase (string-to-char value)
|
||||||
(delete-region pos end)
|
(?<
|
||||||
(pcase (string-to-char value)
|
;; The current time.
|
||||||
(?<
|
(insert (format-time-string time-string)))
|
||||||
;; The current time.
|
(?:
|
||||||
(insert (format-time-string time-string)))
|
;; From the property list.
|
||||||
(?:
|
(insert (or (plist-get org-store-link-plist (intern value))
|
||||||
;; From the property list.
|
"")))
|
||||||
(insert (or (plist-get org-store-link-plist (intern value))
|
(?i (let ((lead (buffer-substring-no-properties
|
||||||
"")))
|
(line-beginning-position) pos)))
|
||||||
(?i (let ((lead (buffer-substring-no-properties
|
(insert (mapconcat #'identity
|
||||||
(line-beginning-position) pos)))
|
(split-string initial "\n")
|
||||||
(insert (mapconcat #'identity
|
(concat "\n" lead)))))
|
||||||
(split-string initial "\n")
|
(?a (insert v-a))
|
||||||
(concat "\n" lead)))))
|
(?A (insert v-A))
|
||||||
(?^
|
(?c (insert v-c))
|
||||||
;; Interactive template entries.
|
(?f (insert v-f))
|
||||||
(let ((completions nil)
|
(?F (insert v-F))
|
||||||
(default nil)
|
(?k (insert v-k))
|
||||||
(histvar nil))
|
(?K (insert v-K))
|
||||||
(when prompt
|
(?l (insert v-l))
|
||||||
(setq completions (org-split-string prompt "|"))
|
(?t (insert v-t))
|
||||||
(setq prompt (pop completions))
|
(?T (insert v-T))
|
||||||
(setq default (car completions))
|
(?u (insert v-u))
|
||||||
(setq histvar
|
(?U (insert v-U))
|
||||||
(intern (concat
|
(?x (insert v-x)))
|
||||||
"org-capture-template-prompt-history::"
|
(set-marker pos nil)
|
||||||
(or prompt ""))))
|
(set-marker end nil))))))
|
||||||
(setq completions (mapcar #'list completions)))
|
|
||||||
(pcase key
|
|
||||||
((or `"G" `"g")
|
|
||||||
(let* ((org-last-tags-completion-table
|
|
||||||
(org-global-tags-completion-table
|
|
||||||
(cond ((equal key "G") (org-agenda-files))
|
|
||||||
(file (list file))
|
|
||||||
(t nil))))
|
|
||||||
(org-add-colon-after-tag-completion t)
|
|
||||||
(ins (mapconcat
|
|
||||||
#'identity
|
|
||||||
(org-split-string
|
|
||||||
(completing-read
|
|
||||||
(if prompt (concat prompt ": ") "Tags: ")
|
|
||||||
'org-tags-completion-function nil nil nil
|
|
||||||
'org-tags-history)
|
|
||||||
"[^[:alnum:]_@#%]+")
|
|
||||||
":")))
|
|
||||||
(when (org-string-nw-p ins)
|
|
||||||
(unless (eq (char-before) ?:) (insert ":"))
|
|
||||||
(insert ins)
|
|
||||||
(unless (eq (char-after) ?:) (insert ":"))
|
|
||||||
(and (org-at-heading-p)
|
|
||||||
(let ((org-ignore-region t))
|
|
||||||
(org-set-tags nil 'align))))))
|
|
||||||
(`"C"
|
|
||||||
(cond
|
|
||||||
((= (length clipboards) 1) (insert (car clipboards)))
|
|
||||||
((> (length clipboards) 1)
|
|
||||||
(insert (read-string "Clipboard/kill value: "
|
|
||||||
(car clipboards)
|
|
||||||
'(clipboards . 1)
|
|
||||||
(car clipboards))))))
|
|
||||||
(`"L"
|
|
||||||
(cond ((= (length clipboards) 1)
|
|
||||||
(org-insert-link 0 (car clipboards)))
|
|
||||||
((> (length clipboards) 1)
|
|
||||||
(org-insert-link
|
|
||||||
0
|
|
||||||
(read-string "Clipboard/kill value: "
|
|
||||||
(car clipboards)
|
|
||||||
'(clipboards . 1)
|
|
||||||
(car clipboards))))))
|
|
||||||
(`"p" (org-set-property prompt nil))
|
|
||||||
((guard key)
|
|
||||||
;; These are the date/time related ones.
|
|
||||||
(let* ((upcase? (equal (upcase key) key))
|
|
||||||
(org-time-was-given upcase?)
|
|
||||||
(org-end-time-was-given)
|
|
||||||
(time (org-read-date upcase? t nil prompt)))
|
|
||||||
(org-insert-time-stamp
|
|
||||||
time org-time-was-given
|
|
||||||
(member key '("u" "U"))
|
|
||||||
nil nil (list org-end-time-was-given))))
|
|
||||||
(_
|
|
||||||
(push (org-completing-read-no-i
|
|
||||||
(concat (or prompt "Enter string")
|
|
||||||
(and default (format " [%s]" default))
|
|
||||||
": ")
|
|
||||||
completions nil nil nil histvar default)
|
|
||||||
strings)
|
|
||||||
(insert (car strings))))))
|
|
||||||
(?a (insert v-a))
|
|
||||||
(?A (insert v-A))
|
|
||||||
(?c (insert v-c))
|
|
||||||
(?f (insert v-f))
|
|
||||||
(?F (insert v-F))
|
|
||||||
(?k (insert v-k))
|
|
||||||
(?K (insert v-K))
|
|
||||||
(?l (insert v-l))
|
|
||||||
(?t (insert v-t))
|
|
||||||
(?T (insert v-T))
|
|
||||||
(?u (insert v-u))
|
|
||||||
(?U (insert v-U))
|
|
||||||
(?x (insert v-x)))
|
|
||||||
(set-marker pos nil)
|
|
||||||
(set-marker end nil)))))
|
|
||||||
|
|
||||||
;; Replace %n escapes with nth %^{...} string.
|
|
||||||
(setq strings (nreverse strings))
|
|
||||||
(save-excursion
|
|
||||||
(while (re-search-forward "%\\\\\\([1-9][0-9]*\\)" nil t)
|
|
||||||
(unless (org-capture-escaped-%)
|
|
||||||
(replace-match
|
|
||||||
(nth (1- (string-to-number (match-string 1))) strings)
|
|
||||||
nil t))))
|
|
||||||
|
|
||||||
;; Expand %() embedded Elisp. Limit to Sexp originally marked.
|
;; Expand %() embedded Elisp. Limit to Sexp originally marked.
|
||||||
(org-capture--expand-embedded-elisp)
|
(org-capture--expand-embedded-elisp)
|
||||||
|
|
||||||
|
;; Expand interactive templates. This is the last step so that
|
||||||
|
;; template is mostly expanded when prompting happens.
|
||||||
|
(let ((org-inhibit-startup t)) (org-mode))
|
||||||
|
(let (strings) ; Stores interactive answers.
|
||||||
|
(save-excursion
|
||||||
|
(let ((regexp "%\\^\\(?:{\\([^}]*\\)}\\)?\\([CgGLptTuU]\\)?"))
|
||||||
|
(while (re-search-forward regexp nil t)
|
||||||
|
(unless (org-capture-escaped-%)
|
||||||
|
(let* ((items
|
||||||
|
(and (match-end 1)
|
||||||
|
(save-match-data
|
||||||
|
(split-string (match-string-no-properties 1)
|
||||||
|
"|"))))
|
||||||
|
(prompt (nth 0 items))
|
||||||
|
(default (nth 1 items))
|
||||||
|
(completions (nthcdr 2 items))
|
||||||
|
(histvar
|
||||||
|
(intern
|
||||||
|
(concat "org-capture-template-prompt-history::"
|
||||||
|
(or prompt ""))))
|
||||||
|
(key (match-string 2)))
|
||||||
|
(delete-region (match-beginning 0) (match-end 0))
|
||||||
|
(pcase key
|
||||||
|
((or `"G" `"g")
|
||||||
|
(let* ((org-last-tags-completion-table
|
||||||
|
(org-global-tags-completion-table
|
||||||
|
(cond ((equal key "G") (org-agenda-files))
|
||||||
|
(file (list file))
|
||||||
|
(t nil))))
|
||||||
|
(org-add-colon-after-tag-completion t)
|
||||||
|
(ins (mapconcat
|
||||||
|
#'identity
|
||||||
|
(org-split-string
|
||||||
|
(completing-read
|
||||||
|
(if prompt (concat prompt ": ") "Tags: ")
|
||||||
|
'org-tags-completion-function nil nil nil
|
||||||
|
'org-tags-history)
|
||||||
|
"[^[:alnum:]_@#%]+")
|
||||||
|
":")))
|
||||||
|
(when (org-string-nw-p ins)
|
||||||
|
(unless (eq (char-before) ?:) (insert ":"))
|
||||||
|
(insert ins)
|
||||||
|
(unless (eq (char-after) ?:) (insert ":"))
|
||||||
|
(and (org-at-heading-p)
|
||||||
|
(let ((org-ignore-region t))
|
||||||
|
(org-set-tags nil 'align))))))
|
||||||
|
(`"C"
|
||||||
|
(cond
|
||||||
|
((= (length clipboards) 1) (insert (car clipboards)))
|
||||||
|
((> (length clipboards) 1)
|
||||||
|
(insert (read-string "Clipboard/kill value: "
|
||||||
|
(car clipboards)
|
||||||
|
'(clipboards . 1)
|
||||||
|
(car clipboards))))))
|
||||||
|
(`"L"
|
||||||
|
(cond ((= (length clipboards) 1)
|
||||||
|
(org-insert-link 0 (car clipboards)))
|
||||||
|
((> (length clipboards) 1)
|
||||||
|
(org-insert-link
|
||||||
|
0
|
||||||
|
(read-string "Clipboard/kill value: "
|
||||||
|
(car clipboards)
|
||||||
|
'(clipboards . 1)
|
||||||
|
(car clipboards))))))
|
||||||
|
(`"p" (org-set-property prompt nil))
|
||||||
|
((guard key)
|
||||||
|
;; These are the date/time related ones.
|
||||||
|
(let* ((upcase? (equal (upcase key) key))
|
||||||
|
(org-time-was-given upcase?)
|
||||||
|
(org-end-time-was-given)
|
||||||
|
(time (org-read-date upcase? t nil prompt)))
|
||||||
|
(org-insert-time-stamp
|
||||||
|
time org-time-was-given
|
||||||
|
(member key '("u" "U"))
|
||||||
|
nil nil (list org-end-time-was-given))))
|
||||||
|
(_
|
||||||
|
(push (org-completing-read-no-i
|
||||||
|
(concat (or prompt "Enter string")
|
||||||
|
(and default (format " [%s]" default))
|
||||||
|
": ")
|
||||||
|
completions nil nil nil histvar default)
|
||||||
|
strings)
|
||||||
|
(insert (car strings)))))))))
|
||||||
|
|
||||||
|
;; Replace %n escapes with nth %^{...} string.
|
||||||
|
(setq strings (nreverse strings))
|
||||||
|
(save-excursion
|
||||||
|
(while (re-search-forward "%\\\\\\([1-9][0-9]*\\)" nil t)
|
||||||
|
(unless (org-capture-escaped-%)
|
||||||
|
(replace-match
|
||||||
|
(nth (1- (string-to-number (match-string 1))) strings)
|
||||||
|
nil t)))))
|
||||||
|
|
||||||
;; Make sure there are no empty lines before the text, and that
|
;; Make sure there are no empty lines before the text, and that
|
||||||
;; it ends with a newline character.
|
;; it ends with a newline character.
|
||||||
(goto-char (point-min))
|
(skip-chars-forward " \t\n")
|
||||||
(while (looking-at "[ \t]*\n") (replace-match ""))
|
(delete-region (point-min) (line-beginning-position))
|
||||||
(when (re-search-forward "[ \t\n]*\\'" nil t) (replace-match "\n"))
|
(goto-char (point-max))
|
||||||
|
(skip-chars-backward " \t\n")
|
||||||
|
(delete-region (point) (point-max))
|
||||||
|
(insert "\n")
|
||||||
|
|
||||||
;; Return the expanded template and kill the temporary buffer.
|
;; Return the expanded template and kill the temporary buffer.
|
||||||
(untabify (point-min) (point-max))
|
(untabify (point-min) (point-max))
|
||||||
(set-buffer-modified-p nil)
|
(set-buffer-modified-p nil)
|
||||||
|
|
Loading…
Reference in a new issue