|
@@ -1111,8 +1111,10 @@ may have been stored before."
|
|
|
|
|
|
|
|
(defun org-capture-place-entry ()
|
|
(defun org-capture-place-entry ()
|
|
|
"Place the template as a new Org entry."
|
|
"Place the template as a new Org entry."
|
|
|
- (let ((reversed? (org-capture-get :prepend))
|
|
|
|
|
|
|
+ (let ((template (org-capture-get :template))
|
|
|
|
|
+ (reversed? (org-capture-get :prepend))
|
|
|
(level 1))
|
|
(level 1))
|
|
|
|
|
+ (org-capture-verify-tree template)
|
|
|
(when (org-capture-get :exact-position)
|
|
(when (org-capture-get :exact-position)
|
|
|
(goto-char (org-capture-get :exact-position)))
|
|
(goto-char (org-capture-get :exact-position)))
|
|
|
(cond
|
|
(cond
|
|
@@ -1128,81 +1130,126 @@ may have been stored before."
|
|
|
(unless (org-at-heading-p) (outline-next-heading)))
|
|
(unless (org-at-heading-p) (outline-next-heading)))
|
|
|
;; Otherwise, insert as a top-level entry at the end of the file.
|
|
;; Otherwise, insert as a top-level entry at the end of the file.
|
|
|
(t (goto-char (point-max))))
|
|
(t (goto-char (point-max))))
|
|
|
- (unless (bolp) (insert "\n"))
|
|
|
|
|
- (org-capture-empty-lines-before)
|
|
|
|
|
- (let ((beg (point))
|
|
|
|
|
- (template (org-capture-get :template)))
|
|
|
|
|
- (org-capture-verify-tree template)
|
|
|
|
|
- (org-paste-subtree level template 'for-yank)
|
|
|
|
|
- (org-capture-empty-lines-after)
|
|
|
|
|
- (org-capture-position-for-last-stored beg)
|
|
|
|
|
- (unless (org-at-heading-p) (outline-next-heading))
|
|
|
|
|
- (let ((end (point)))
|
|
|
|
|
- (org-capture-mark-kill-region beg end)
|
|
|
|
|
- (org-capture-narrow beg end)
|
|
|
|
|
- (when (or (re-search-backward "%\\?" beg t)
|
|
|
|
|
- (re-search-forward "%\\?" end t))
|
|
|
|
|
- (replace-match ""))))))
|
|
|
|
|
|
|
+ (let ((origin (point)))
|
|
|
|
|
+ (unless (bolp) (insert "\n"))
|
|
|
|
|
+ (org-capture-empty-lines-before)
|
|
|
|
|
+ (org-capture-position-for-last-stored (point))
|
|
|
|
|
+ (let ((beg (point)))
|
|
|
|
|
+ (org-paste-subtree level template 'for-yank)
|
|
|
|
|
+ (let ((end (if (org-at-heading-p) (line-end-position 0) (point))))
|
|
|
|
|
+ (org-capture-empty-lines-after)
|
|
|
|
|
+ (unless (org-at-heading-p) (outline-next-heading))
|
|
|
|
|
+ (org-capture-mark-kill-region origin (point))
|
|
|
|
|
+ (org-capture-narrow beg end)
|
|
|
|
|
+ (when (or (search-backward "%?" beg t)
|
|
|
|
|
+ (search-forward "%?" end t))
|
|
|
|
|
+ (replace-match "")))))))
|
|
|
|
|
|
|
|
(defun org-capture-place-item ()
|
|
(defun org-capture-place-item ()
|
|
|
"Place the template as a new plain list item."
|
|
"Place the template as a new plain list item."
|
|
|
- (let* ((txt (org-capture-get :template))
|
|
|
|
|
- (target-entry-p (org-capture-get :target-entry-p))
|
|
|
|
|
- (ind 0)
|
|
|
|
|
- beg end)
|
|
|
|
|
- (if (org-capture-get :exact-position)
|
|
|
|
|
- (goto-char (org-capture-get :exact-position))
|
|
|
|
|
- (cond
|
|
|
|
|
- ((not target-entry-p)
|
|
|
|
|
- ;; Insert as top-level entry, either at beginning or at end of file
|
|
|
|
|
- (setq beg (point-min) end (point-max)))
|
|
|
|
|
- (t
|
|
|
|
|
- (setq beg (1+ (point-at-eol))
|
|
|
|
|
- end (save-excursion (outline-next-heading) (point)))))
|
|
|
|
|
- (setq ind nil)
|
|
|
|
|
- (if (org-capture-get :prepend)
|
|
|
|
|
- (progn
|
|
|
|
|
- (goto-char beg)
|
|
|
|
|
- (when (org-list-search-forward (org-item-beginning-re) end t)
|
|
|
|
|
- (goto-char (match-beginning 0))
|
|
|
|
|
- (setq ind (current-indentation))))
|
|
|
|
|
- (goto-char end)
|
|
|
|
|
- (when (org-list-search-backward (org-item-beginning-re) beg t)
|
|
|
|
|
- (setq ind (current-indentation))
|
|
|
|
|
- (org-end-of-item)))
|
|
|
|
|
- (unless ind (goto-char end)))
|
|
|
|
|
- ;; Remove common indentation
|
|
|
|
|
- (setq txt (org-remove-indentation txt))
|
|
|
|
|
- ;; Make sure this is indeed an item
|
|
|
|
|
- (unless (string-match (concat "\\`" (org-item-re)) txt)
|
|
|
|
|
- (setq txt (concat "- "
|
|
|
|
|
- (mapconcat 'identity (split-string txt "\n")
|
|
|
|
|
- "\n "))))
|
|
|
|
|
- ;; Prepare surrounding empty lines.
|
|
|
|
|
- (unless (bolp) (insert "\n"))
|
|
|
|
|
- (org-capture-empty-lines-before)
|
|
|
|
|
- (setq beg (point))
|
|
|
|
|
- (unless (eolp) (save-excursion (insert "\n")))
|
|
|
|
|
- (unless ind
|
|
|
|
|
- (org-indent-line)
|
|
|
|
|
- (setq ind (current-indentation))
|
|
|
|
|
- (delete-region beg (point)))
|
|
|
|
|
- ;; Set the correct indentation, depending on context
|
|
|
|
|
- (setq ind (make-string ind ?\ ))
|
|
|
|
|
- (setq txt (concat ind
|
|
|
|
|
- (mapconcat 'identity (split-string txt "\n")
|
|
|
|
|
- (concat "\n" ind))
|
|
|
|
|
- "\n"))
|
|
|
|
|
- ;; Insert item.
|
|
|
|
|
- (insert txt)
|
|
|
|
|
- (org-capture-empty-lines-after)
|
|
|
|
|
- (org-capture-position-for-last-stored beg)
|
|
|
|
|
- (setq end (point))
|
|
|
|
|
- (org-capture-mark-kill-region beg end)
|
|
|
|
|
- (org-capture-narrow beg end)
|
|
|
|
|
- (when (or (re-search-backward "%\\?" beg t)
|
|
|
|
|
- (re-search-forward "%\\?" end t))
|
|
|
|
|
- (replace-match ""))))
|
|
|
|
|
|
|
+ (let ((prepend? (org-capture-get :prepend))
|
|
|
|
|
+ (template (org-remove-indentation (org-capture-get :template)))
|
|
|
|
|
+ item)
|
|
|
|
|
+ ;; Make template suitable for insertion. In particular, add
|
|
|
|
|
+ ;; a main bullet if it is missing.
|
|
|
|
|
+ (unless (string-match-p (concat "\\`" (org-item-re)) template)
|
|
|
|
|
+ (setq template (concat "- " (mapconcat #'identity
|
|
|
|
|
+ (split-string template "\n")
|
|
|
|
|
+ "\n "))))
|
|
|
|
|
+ ;; Delimit the area where we should look for a plain list.
|
|
|
|
|
+ (pcase-let ((`(,beg . ,end)
|
|
|
|
|
+ (cond ((org-capture-get :exact-position)
|
|
|
|
|
+ ;; User gave a specific position. Start
|
|
|
|
|
+ ;; looking for lists from here.
|
|
|
|
|
+ (cons (save-excursion
|
|
|
|
|
+ (goto-char (org-capture-get :exact-position))
|
|
|
|
|
+ (line-beginning-position))
|
|
|
|
|
+ (org-entry-end-position)))
|
|
|
|
|
+ ((org-capture-get :target-entry-p)
|
|
|
|
|
+ ;; At a heading, limit search to its body.
|
|
|
|
|
+ (cons (line-beginning-position 2)
|
|
|
|
|
+ (org-entry-end-position)))
|
|
|
|
|
+ (t
|
|
|
|
|
+ ;; Table is not necessarily under a heading.
|
|
|
|
|
+ ;; Search whole buffer.
|
|
|
|
|
+ (cons (point-min) (point-max))))))
|
|
|
|
|
+ ;; Find the first plain list in the delimited area.
|
|
|
|
|
+ (goto-char beg)
|
|
|
|
|
+ (let ((item-regexp (org-item-beginning-re)))
|
|
|
|
|
+ (catch :found
|
|
|
|
|
+ (while (re-search-forward item-regexp end t)
|
|
|
|
|
+ (when (setq item (org-element-lineage
|
|
|
|
|
+ (org-element-at-point) '(plain-list) t))
|
|
|
|
|
+ (goto-char (org-element-property (if prepend? :post-affiliated
|
|
|
|
|
+ :contents-end)
|
|
|
|
|
+ item))
|
|
|
|
|
+ (throw :found t)))
|
|
|
|
|
+ ;; No list found. Move to the location when to insert
|
|
|
|
|
+ ;; template.
|
|
|
|
|
+ (goto-char (if prepend? beg end)))))
|
|
|
|
|
+ ;; Insert template.
|
|
|
|
|
+ (let ((origin (point)))
|
|
|
|
|
+ (unless (bolp) (insert "\n"))
|
|
|
|
|
+ ;; When a new list is created, always obey to `:empty-lines' and
|
|
|
|
|
+ ;; friends.
|
|
|
|
|
+ ;;
|
|
|
|
|
+ ;; When capturing in an existing list, do not change blank lines
|
|
|
|
|
+ ;; above or below the list; consider it to be a stable
|
|
|
|
|
+ ;; structure. However, we can control how many blank lines
|
|
|
|
|
+ ;; separate items. So obey to `:empty-lines' between items as
|
|
|
|
|
+ ;; long as it does not insert more than one empty line. In the
|
|
|
|
|
+ ;; specific case of empty lines above, it means we only obey the
|
|
|
|
|
+ ;; parameter when appending an item.
|
|
|
|
|
+ (unless (and item prepend?)
|
|
|
|
|
+ (org-capture-empty-lines-before
|
|
|
|
|
+ (and item
|
|
|
|
|
+ (not prepend?)
|
|
|
|
|
+ (min 1 (or (org-capture-get :empty-lines-before)
|
|
|
|
|
+ (org-capture-get :empty-lines)
|
|
|
|
|
+ 0)))))
|
|
|
|
|
+ (org-capture-position-for-last-stored (point))
|
|
|
|
|
+ (let ((beg (line-beginning-position))
|
|
|
|
|
+ (end (progn
|
|
|
|
|
+ (insert (org-trim template) "\n")
|
|
|
|
|
+ (point-marker))))
|
|
|
|
|
+ (when item
|
|
|
|
|
+ (let ((i (save-excursion
|
|
|
|
|
+ (goto-char (org-element-property :post-affiliated item))
|
|
|
|
|
+ (current-indentation))))
|
|
|
|
|
+ (save-excursion
|
|
|
|
|
+ (goto-char beg)
|
|
|
|
|
+ (save-excursion
|
|
|
|
|
+ (while (< (point) end)
|
|
|
|
|
+ (indent-to i)
|
|
|
|
|
+ (forward-line)))
|
|
|
|
|
+ ;; Pre-pending an item could change the type of the list
|
|
|
|
|
+ ;; if there is a mismatch. In this situation,
|
|
|
|
|
+ ;; prioritize the existing list.
|
|
|
|
|
+ (when prepend?
|
|
|
|
|
+ (let ((ordered? (eq 'ordered (org-element-property :type item))))
|
|
|
|
|
+ (when (org-xor ordered?
|
|
|
|
|
+ (string-match-p "\\`[A-Za-z0-9]\\([.)]\\)"
|
|
|
|
|
+ template))
|
|
|
|
|
+ (org-cycle-list-bullet (if ordered? "1." "-")))))
|
|
|
|
|
+ ;; Eventually repair the list for proper indentation and
|
|
|
|
|
+ ;; bullets.
|
|
|
|
|
+ (org-list-repair))))
|
|
|
|
|
+ ;; Limit number of empty lines. See above for details.
|
|
|
|
|
+ (unless (and item (not prepend?))
|
|
|
|
|
+ (org-capture-empty-lines-after
|
|
|
|
|
+ (and item
|
|
|
|
|
+ prepend?
|
|
|
|
|
+ (min 1 (or (org-capture-get :empty-lines-after)
|
|
|
|
|
+ (org-capture-get :empty-lines)
|
|
|
|
|
+ 0)))))
|
|
|
|
|
+ (org-capture-mark-kill-region origin (point))
|
|
|
|
|
+ ;; ITEM always end with a newline character. Make sure we do
|
|
|
|
|
+ ;; not narrow at the beginning of the next line, possibly
|
|
|
|
|
+ ;; altering its structure (e.g., when it is a headline).
|
|
|
|
|
+ (org-capture-narrow beg (1- end))
|
|
|
|
|
+ (when (or (search-backward "%?" beg t)
|
|
|
|
|
+ (search-forward "%?" end t))
|
|
|
|
|
+ (replace-match ""))))))
|
|
|
|
|
|
|
|
(defun org-capture-place-table-line ()
|
|
(defun org-capture-place-table-line ()
|
|
|
"Place the template as a table line."
|
|
"Place the template as a table line."
|
|
@@ -1270,18 +1317,21 @@ may have been stored before."
|
|
|
(t
|
|
(t
|
|
|
(goto-char (org-table-end))))
|
|
(goto-char (org-table-end))))
|
|
|
;; Insert text and position point according to template.
|
|
;; Insert text and position point according to template.
|
|
|
- (unless (bolp) (insert "\n"))
|
|
|
|
|
- (let ((beg (point))
|
|
|
|
|
- (end (save-excursion
|
|
|
|
|
- (insert text)
|
|
|
|
|
- (point))))
|
|
|
|
|
- (org-capture-position-for-last-stored 'table-line)
|
|
|
|
|
- (org-capture-mark-kill-region beg end)
|
|
|
|
|
- (org-capture-narrow beg end)
|
|
|
|
|
- (when (or (re-search-backward "%\\?" beg t)
|
|
|
|
|
- (re-search-forward "%\\?" end t))
|
|
|
|
|
- (replace-match "")))
|
|
|
|
|
- (org-table-align)))
|
|
|
|
|
|
|
+ (let ((origin (point)))
|
|
|
|
|
+ (unless (bolp) (insert "\n"))
|
|
|
|
|
+ (let ((beg (point))
|
|
|
|
|
+ (end (save-excursion
|
|
|
|
|
+ (insert text)
|
|
|
|
|
+ (point))))
|
|
|
|
|
+ (org-capture-position-for-last-stored 'table-line)
|
|
|
|
|
+ (org-capture-mark-kill-region origin end)
|
|
|
|
|
+ ;; TEXT is guaranteed to end with a newline character. Ignore
|
|
|
|
|
+ ;; it when narrowing so as to not alter data on the next line.
|
|
|
|
|
+ (org-capture-narrow beg (1- end))
|
|
|
|
|
+ (when (or (search-backward "%?" beg t)
|
|
|
|
|
+ (search-forward "%?" end t))
|
|
|
|
|
+ (replace-match "")))
|
|
|
|
|
+ (org-table-align))))
|
|
|
|
|
|
|
|
(defun org-capture-place-plain-text ()
|
|
(defun org-capture-place-plain-text ()
|
|
|
"Place the template plainly.
|
|
"Place the template plainly.
|
|
@@ -1289,35 +1339,36 @@ If the target locator points at an Org node, place the template into
|
|
|
the text of the entry, before the first child. If not, place the
|
|
the text of the entry, before the first child. If not, place the
|
|
|
template at the beginning or end of the file.
|
|
template at the beginning or end of the file.
|
|
|
Of course, if exact position has been required, just put it there."
|
|
Of course, if exact position has been required, just put it there."
|
|
|
- (let* ((txt (org-capture-get :template))
|
|
|
|
|
- beg end)
|
|
|
|
|
- (cond
|
|
|
|
|
- ((org-capture-get :exact-position)
|
|
|
|
|
- (goto-char (org-capture-get :exact-position)))
|
|
|
|
|
- ((and (org-capture-get :target-entry-p)
|
|
|
|
|
- (bolp)
|
|
|
|
|
- (looking-at org-outline-regexp))
|
|
|
|
|
- ;; we should place the text into this entry
|
|
|
|
|
- (if (org-capture-get :prepend)
|
|
|
|
|
- ;; Skip meta data and drawers
|
|
|
|
|
- (org-end-of-meta-data t)
|
|
|
|
|
- ;; go to ent of the entry text, before the next headline
|
|
|
|
|
- (outline-next-heading)))
|
|
|
|
|
- (t
|
|
|
|
|
- ;; beginning or end of file
|
|
|
|
|
- (goto-char (if (org-capture-get :prepend) (point-min) (point-max)))))
|
|
|
|
|
- (or (bolp) (newline))
|
|
|
|
|
|
|
+ (cond
|
|
|
|
|
+ ((org-capture-get :exact-position)
|
|
|
|
|
+ (goto-char (org-capture-get :exact-position)))
|
|
|
|
|
+ ((org-capture-get :target-entry-p)
|
|
|
|
|
+ ;; Place the text into this entry.
|
|
|
|
|
+ (if (org-capture-get :prepend)
|
|
|
|
|
+ ;; Skip meta data and drawers.
|
|
|
|
|
+ (org-end-of-meta-data t)
|
|
|
|
|
+ ;; Go to end of the entry text, before the next headline.
|
|
|
|
|
+ (outline-next-heading)))
|
|
|
|
|
+ (t
|
|
|
|
|
+ ;; Beginning or end of file.
|
|
|
|
|
+ (goto-char (if (org-capture-get :prepend) (point-min) (point-max)))))
|
|
|
|
|
+ (let ((origin (point)))
|
|
|
|
|
+ (unless (bolp) (insert "\n"))
|
|
|
(org-capture-empty-lines-before)
|
|
(org-capture-empty-lines-before)
|
|
|
- (setq beg (point))
|
|
|
|
|
- (insert txt)
|
|
|
|
|
- (org-capture-empty-lines-after)
|
|
|
|
|
- (org-capture-position-for-last-stored beg)
|
|
|
|
|
- (setq end (point))
|
|
|
|
|
- (org-capture-mark-kill-region beg (1- end))
|
|
|
|
|
- (org-capture-narrow beg (1- end))
|
|
|
|
|
- (when (or (re-search-backward "%\\?" beg t)
|
|
|
|
|
- (re-search-forward "%\\?" end t))
|
|
|
|
|
- (replace-match ""))))
|
|
|
|
|
|
|
+ (org-capture-position-for-last-stored (point))
|
|
|
|
|
+ (let ((beg (point)))
|
|
|
|
|
+ (insert (org-capture-get :template))
|
|
|
|
|
+ (unless (bolp) (insert "\n"))
|
|
|
|
|
+ ;; Ignore the final newline character so as to not alter data
|
|
|
|
|
+ ;; after inserted text. Yet, if the template is empty, make
|
|
|
|
|
+ ;; sure END matches BEG instead of pointing before it.
|
|
|
|
|
+ (let ((end (max beg (1- (point)))))
|
|
|
|
|
+ (org-capture-empty-lines-after)
|
|
|
|
|
+ (org-capture-mark-kill-region origin (point))
|
|
|
|
|
+ (org-capture-narrow beg end)
|
|
|
|
|
+ (when (or (search-backward "%?" beg t)
|
|
|
|
|
+ (search-forward "%?" end t))
|
|
|
|
|
+ (replace-match ""))))))
|
|
|
|
|
|
|
|
(defun org-capture-mark-kill-region (beg end)
|
|
(defun org-capture-mark-kill-region (beg end)
|
|
|
"Mark the region that will have to be killed when aborting capture."
|
|
"Mark the region that will have to be killed when aborting capture."
|