0
0
Fork 1
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:
Nicolas Goaziou 2015-12-03 23:27:07 +01:00
parent 11291ffcd0
commit 5c13a6b765

View file

@ -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)