summaryrefslogtreecommitdiff
path: root/lisp
diff options
context:
space:
mode:
authorSébastien Delafond <sdelafond@gmail.com>2016-12-18 18:15:46 +0100
committerSébastien Delafond <sdelafond@gmail.com>2016-12-18 18:15:46 +0100
commit818c794a1dceed58f42fdbd8595da59c383dabb5 (patch)
tree06f8d269f2791ce9de8c47e1e3016e6ef4b0fef0 /lisp
parentec84430cf4e09ba25ec675debdf802bc28111e06 (diff)
Imported Upstream version 9.0.2
Diffstat (limited to 'lisp')
-rw-r--r--lisp/ob-core.el16
-rw-r--r--lisp/ob-js.el2
-rw-r--r--lisp/ob-tangle.el173
-rw-r--r--lisp/org-agenda.el509
-rw-r--r--lisp/org-archive.el13
-rw-r--r--lisp/org-capture.el32
-rw-r--r--lisp/org-clock.el144
-rw-r--r--lisp/org-colview.el72
-rw-r--r--lisp/org-element.el52
-rw-r--r--lisp/org-list.el2
-rw-r--r--lisp/org-loaddefs.el6
-rw-r--r--lisp/org-pcomplete.el9
-rw-r--r--lisp/org-src.el2
-rw-r--r--lisp/org-table.el3
-rw-r--r--lisp/org-version.el4
-rw-r--r--lisp/org.el553
-rw-r--r--lisp/ox-beamer.el50
-rw-r--r--lisp/ox-html.el37
-rw-r--r--lisp/ox-icalendar.el8
-rw-r--r--lisp/ox-latex.el101
-rw-r--r--lisp/ox-man.el8
-rw-r--r--lisp/ox-odt.el8
-rw-r--r--lisp/ox-publish.el70
-rw-r--r--lisp/ox-texinfo.el11
-rw-r--r--lisp/ox.el125
25 files changed, 1049 insertions, 961 deletions
diff --git a/lisp/ob-core.el b/lisp/ob-core.el
index 3cfe726..7540ba2 100644
--- a/lisp/ob-core.el
+++ b/lisp/ob-core.el
@@ -207,7 +207,7 @@ This string must include a \"%s\" which will be replaced by the results."
(defun org-babel--get-vars (params)
"Return the babel variable assignments in PARAMS.
-PARAMS is a quasi-alist of header args, whcih may contain
+PARAMS is a quasi-alist of header args, which may contain
multiple entries for the key `:var'. This function returns a
list of the cdr of all the `:var' entries."
(mapcar #'cdr
@@ -247,15 +247,15 @@ should be asked whether to allow evaluation."
(defun org-babel-check-evaluate (info)
"Check if code block INFO should be evaluated.
-
Do not query the user, but do display an informative message if
evaluation is blocked. Returns non-nil if evaluation is not blocked."
- (let ((evalp (org-babel-check-confirm-evaluate info)))
- (when (null evalp)
- (message "Evaluation of this %s code-block%sis disabled."
+ (let ((confirmed (org-babel-check-confirm-evaluate info)))
+ (unless confirmed
+ (message "Evaluation of this %s code block%sis disabled."
(nth 0 info)
- (let ((name (nth 4 info))) (if name (format " (%s) " name) ""))))
- evalp))
+ (let ((name (nth 4 info)))
+ (if name (format " (%s) " name) " "))))
+ confirmed))
;; Dynamically scoped for asynchronous export.
(defvar org-babel-confirm-evaluate-answer-no)
@@ -288,7 +288,7 @@ environment, to override this check."
(format "Evaluate this %s code block%son your system? "
lang name-string)))
(progn
- (message "Evaluation of this %s code-block%sis aborted."
+ (message "Evaluation of this %s code block%sis aborted."
lang name-string)
nil)))
(x (error "Unexpected value `%s' from `org-babel-check-confirm-evaluate'" x)))))
diff --git a/lisp/ob-js.el b/lisp/ob-js.el
index 1a20d7e..0cd3b06 100644
--- a/lisp/ob-js.el
+++ b/lisp/ob-js.el
@@ -55,7 +55,7 @@
:type 'string)
(defvar org-babel-js-function-wrapper
- "require('sys').print(require('sys').inspect(function(){%s}()));"
+ "require('sys').print(require('sys').inspect(function(){\n%s\n}()));"
"Javascript code to print value of body.")
(defun org-babel-execute:js (body params)
diff --git a/lisp/ob-tangle.el b/lisp/ob-tangle.el
index 5e1b953..a5e18a8 100644
--- a/lisp/ob-tangle.el
+++ b/lisp/ob-tangle.el
@@ -343,63 +343,42 @@ code file. This function uses `comment-region' which assumes
that the appropriate major-mode is set. SPEC has the form:
(start-line file link source-name params body comment)"
- (let* ((start-line (nth 0 spec))
- (info (nth 4 spec))
- (file (if org-babel-tangle-use-relative-file-links
- (file-relative-name (nth 1 spec))
- (nth 1 spec)))
- (link (let ((link (nth 2 spec)))
- (if org-babel-tangle-use-relative-file-links
- (when (string-match org-link-types-re link)
- (let ((type (match-string 0 link))
- (link (substring link (match-end 0))))
- (concat
- type
- (file-relative-name
- link
- (file-name-directory (cdr (assq :tangle info)))))))
- link)))
- (source-name (nth 3 spec))
- (body (nth 5 spec))
- (comment (nth 6 spec))
- (comments (cdr (assq :comments info)))
- (link-p (or (string= comments "both") (string= comments "link")
- (string= comments "yes") (string= comments "noweb")))
- (link-data `(("start-line" . ,(number-to-string start-line))
- ("file" . ,file)
- ("link" . ,link)
- ("source-name" . ,source-name)))
- (insert-comment (lambda (text)
- (when (and comments
- (not (string= comments "no"))
- (org-string-nw-p text))
- (if org-babel-tangle-uncomment-comments
- ;; Plain comments: no processing.
- (insert text)
- ;; Ensure comments are made to be
- ;; comments, and add a trailing
- ;; newline. Also ignore invisible
- ;; characters when commenting.
- (comment-region
- (point)
- (progn (insert (org-no-properties text))
- (point)))
- (end-of-line)
- (insert "\n"))))))
+ (pcase-let*
+ ((`(,start ,file ,link ,source ,info ,body ,comment) spec)
+ (comments (cdr (assq :comments info)))
+ (link? (or (string= comments "both") (string= comments "link")
+ (string= comments "yes") (string= comments "noweb")))
+ (link-data `(("start-line" . ,(number-to-string start))
+ ("file" . ,file)
+ ("link" . ,link)
+ ("source-name" . ,source)))
+ (insert-comment (lambda (text)
+ (when (and comments
+ (not (string= comments "no"))
+ (org-string-nw-p text))
+ (if org-babel-tangle-uncomment-comments
+ ;; Plain comments: no processing.
+ (insert text)
+ ;; Ensure comments are made to be
+ ;; comments, and add a trailing newline.
+ ;; Also ignore invisible characters when
+ ;; commenting.
+ (comment-region
+ (point)
+ (progn (insert (org-no-properties text))
+ (point)))
+ (end-of-line)
+ (insert "\n"))))))
(when comment (funcall insert-comment comment))
- (when link-p
- (funcall
- insert-comment
- (org-fill-template org-babel-tangle-comment-format-beg link-data)))
- (insert
- (org-unescape-code-in-string
- (if org-src-preserve-indentation (org-trim body t)
- (org-trim (org-remove-indentation body))))
- "\n")
- (when link-p
- (funcall
- insert-comment
- (org-fill-template org-babel-tangle-comment-format-end link-data)))))
+ (when link?
+ (funcall insert-comment
+ (org-fill-template
+ org-babel-tangle-comment-format-beg link-data)))
+ (insert body "\n")
+ (when link?
+ (funcall insert-comment
+ (org-fill-template
+ org-babel-tangle-comment-format-end link-data)))))
(defun org-babel-tangle-collect-blocks (&optional language tangle-file)
"Collect source blocks in the current Org file.
@@ -432,13 +411,12 @@ can be used to limit the collected code blocks by target file."
;; Ensure blocks are in the correct order.
(mapcar (lambda (b) (cons (car b) (nreverse (cdr b)))) blocks)))
-(defun org-babel-tangle-single-block
- (block-counter &optional only-this-block)
+(defun org-babel-tangle-single-block (block-counter &optional only-this-block)
"Collect the tangled source for current block.
Return the list of block attributes needed by
-`org-babel-tangle-collect-blocks'.
-When ONLY-THIS-BLOCK is non-nil, return the full association
-list to be used by `org-babel-tangle' directly."
+`org-babel-tangle-collect-blocks'. When ONLY-THIS-BLOCK is
+non-nil, return the full association list to be used by
+`org-babel-tangle' directly."
(let* ((info (org-babel-get-src-block-info))
(start-line
(save-restriction (widen)
@@ -450,44 +428,39 @@ list to be used by `org-babel-tangle' directly."
(cref-fmt (or (and (string-match "-l \"\\(.+\\)\"" extra)
(match-string 1 extra))
org-coderef-label-format))
- (link (let ((link (org-no-properties
- (org-store-link nil))))
- (and (string-match org-bracket-link-regexp link)
- (match-string 1 link))))
+ (link (let ((l (org-no-properties (org-store-link nil))))
+ (and (string-match org-bracket-link-regexp l)
+ (match-string 1 l))))
(source-name
(or (nth 4 info)
(format "%s:%d"
(or (ignore-errors (nth 4 (org-heading-components)))
"No heading")
block-counter)))
- (expand-cmd
- (intern (concat "org-babel-expand-body:" src-lang)))
+ (expand-cmd (intern (concat "org-babel-expand-body:" src-lang)))
(assignments-cmd
(intern (concat "org-babel-variable-assignments:" src-lang)))
(body
;; Run the tangle-body-hook.
- (let* ((body ;; Expand the body in language specific manner.
- (if (org-babel-noweb-p params :tangle)
- (org-babel-expand-noweb-references info)
- (nth 1 info)))
- (body
- (if (assq :no-expand params)
- body
- (if (fboundp expand-cmd)
- (funcall expand-cmd body params)
- (org-babel-expand-body:generic
- body params
- (and (fboundp assignments-cmd)
- (funcall assignments-cmd params)))))))
- (with-temp-buffer
- (insert body)
- (when (string-match "-r" extra)
- (goto-char (point-min))
- (while (re-search-forward
- (replace-regexp-in-string "%s" ".+" cref-fmt) nil t)
- (replace-match "")))
- (run-hooks 'org-babel-tangle-body-hook)
- (buffer-string))))
+ (let ((body (if (org-babel-noweb-p params :tangle)
+ (org-babel-expand-noweb-references info)
+ (nth 1 info))))
+ (with-temp-buffer
+ (insert
+ ;; Expand body in language specific manner.
+ (cond ((assq :no-expand params) body)
+ ((fboundp expand-cmd) (funcall expand-cmd body params))
+ (t
+ (org-babel-expand-body:generic
+ body params (and (fboundp assignments-cmd)
+ (funcall assignments-cmd params))))))
+ (when (string-match "-r" extra)
+ (goto-char (point-min))
+ (while (re-search-forward
+ (replace-regexp-in-string "%s" ".+" cref-fmt) nil t)
+ (replace-match "")))
+ (run-hooks 'org-babel-tangle-body-hook)
+ (buffer-string))))
(comment
(when (or (string= "both" (cdr (assq :comments params)))
(string= "org" (cdr (assq :comments params))))
@@ -497,7 +470,7 @@ list to be used by `org-babel-tangle' directly."
(buffer-substring
(max (condition-case nil
(save-excursion
- (org-back-to-heading t) ; Sets match data
+ (org-back-to-heading t) ; Sets match data
(match-end 0))
(error (point-min)))
(save-excursion
@@ -507,7 +480,25 @@ list to be used by `org-babel-tangle' directly."
(point-min))))
(point)))))
(result
- (list start-line file link source-name params body comment)))
+ (list start-line
+ (if org-babel-tangle-use-relative-file-links
+ (file-relative-name file)
+ file)
+ (if (and org-babel-tangle-use-relative-file-links
+ (string-match org-link-types-re link)
+ (string= (match-string 0 link) "file"))
+ (concat "file:"
+ (file-relative-name (match-string 1 link)
+ (file-name-directory
+ (cdr (assq :tangle params)))))
+ link)
+ source-name
+ params
+ (org-unescape-code-in-string
+ (if org-src-preserve-indentation
+ (org-trim body t)
+ (org-trim (org-remove-indentation body))))
+ comment)))
(if only-this-block
(list (cons src-lang (list result)))
result)))
diff --git a/lisp/org-agenda.el b/lisp/org-agenda.el
index 7ee721a..da748af 100644
--- a/lisp/org-agenda.el
+++ b/lisp/org-agenda.el
@@ -769,10 +769,12 @@ to make his option also apply to the tags-todo list."
(defcustom org-agenda-todo-ignore-deadlines nil
"Non-nil means ignore some deadline TODO items when making TODO list.
+
There are different motivations for using different values, please think
carefully when configuring this variable.
-This applies when creating the global todo list.
+This applies when creating the global TODO list.
+
Valid values are:
near Don't show near deadline entries. A deadline is near when it is
@@ -780,8 +782,8 @@ near Don't show near deadline entries. A deadline is near when it is
is that such items will appear in the agenda anyway.
far Don't show TODO entries where a deadline has been defined, but
- the deadline is not near. This is useful if you don't want to
- use the todo list to figure out what to do now.
+ is not going to happen anytime soon. This is useful if you want to use
+ the TODO list to figure out what to do now.
past Don't show entries with a deadline timestamp for today or in the past.
@@ -842,10 +844,9 @@ restricted to unfinished TODO entries only."
(defcustom org-agenda-skip-scheduled-if-done nil
"Non-nil means don't show scheduled items in agenda when they are done.
-This is relevant for the daily/weekly agenda, not for the TODO list. And
-it applies only to the actual date of the scheduling. Warnings about
-an item with a past scheduling dates are always turned off when the item
-is DONE."
+This is relevant for the daily/weekly agenda, not for the TODO list. It
+applies only to the actual date of the scheduling. Warnings about an item
+with a past scheduling dates are always turned off when the item is DONE."
:group 'org-agenda-skip
:group 'org-agenda-daily/weekly
:type 'boolean)
@@ -894,8 +895,8 @@ several times."
(defcustom org-agenda-skip-deadline-if-done nil
"Non-nil means don't show deadlines when the corresponding item is done.
When nil, the deadline is still shown and should give you a happy feeling.
-This is relevant for the daily/weekly agenda. And it applied only to the
-actually date of the deadline. Warnings about approaching and past-due
+This is relevant for the daily/weekly agenda. It applies only to the
+actual date of the deadline. Warnings about approaching and past-due
deadlines are always turned off when the item is DONE."
:group 'org-agenda-skip
:group 'org-agenda-daily/weekly
@@ -1789,7 +1790,8 @@ in every agenda.
When this option is set to t (the default), inherited tags are
shown when they are available, i.e. when the value of
-`org-agenda-use-tag-inheritance' has been taken into account.
+`org-agenda-use-tag-inheritance' enables tag inheritance for the
+given agenda type.
This can be set to a list of agenda types in which the agenda
must display the inherited tags. Available types are `todo',
@@ -3246,7 +3248,7 @@ This ensures the export commands can easily use it."
(setq tmp (replace-match "" t t tmp)))
(when (and (setq re (plist-get props 'org-todo-regexp))
(setq re (concat "\\`\\.*" re " ?"))
- (string-match re tmp))
+ (let ((case-fold-search nil)) (string-match re tmp)))
(plist-put props 'todo (match-string 1 tmp))
(setq tmp (replace-match "" t t tmp)))
(plist-put props 'txt tmp)))
@@ -3837,11 +3839,11 @@ FILTER-ALIST is an alist of filters we need to apply when
ov 'face
(let ((special-face
(cond ((org-face-from-face-or-color
- 'priority nil
+ 'priority 'org-priority
(cdr (assoc p org-priority-faces))))
((and (listp org-agenda-fontify-priorities)
(org-face-from-face-or-color
- 'priority nil
+ 'priority 'org-priority
(cdr (assoc p org-agenda-fontify-priorities)))))
((equal p l) 'italic)
((equal p h) 'bold))))
@@ -5438,6 +5440,7 @@ and the timestamp type relevant for the sorting strategy in
'help-echo
(format "mouse-2 or RET jump to org file %s"
(abbreviate-file-name buffer-file-name))))
+ (case-fold-search nil)
(regexp (format org-heading-keyword-regexp-format
(cond
((and org-select-this-todo-keyword
@@ -5579,24 +5582,27 @@ This function is invoked if `org-agenda-todo-ignore-deadlines',
(match-string 1) org-agenda-todo-ignore-timestamp))
(t))))))))))
-(defun org-agenda-get-timestamps (&optional deadline-results)
- "Return the date stamp information for agenda display."
+(defun org-agenda-get-timestamps (&optional deadlines)
+ "Return the date stamp information for agenda display.
+Optional argument DEADLINES is a list of deadline items to be
+displayed in agenda view."
(let* ((props (list 'face 'org-agenda-calendar-event
'org-not-done-regexp org-not-done-regexp
'org-todo-regexp org-todo-regexp
'org-complex-heading-regexp org-complex-heading-regexp
'mouse-face 'highlight
'help-echo
- (format "mouse-2 or RET jump to org file %s"
+ (format "mouse-2 or RET jump to Org file %s"
(abbreviate-file-name buffer-file-name))))
- (d1 (calendar-absolute-from-gregorian date))
- mm
+ (current (calendar-absolute-from-gregorian date))
+ (today (org-today))
(deadline-position-alist
- (mapcar (lambda (a) (and (setq mm (get-text-property
- 0 'org-hd-marker a))
- (cons (marker-position mm) a)))
- deadline-results))
- (remove-re org-ts-regexp)
+ (mapcar (lambda (d)
+ (let ((m (get-text-property 0 'org-hd-marker d)))
+ (and m (marker-position m))))
+ deadlines))
+ ;; Match time-stamps set to current date, time-stamps with
+ ;; a repeater, and S-exp time-stamps.
(regexp
(concat
(if org-agenda-include-inactive-timestamps "[[<]" "<")
@@ -5604,95 +5610,106 @@ This function is invoked if `org-agenda-todo-ignore-deadlines',
(substring
(format-time-string
(car org-time-stamp-formats)
- (apply 'encode-time ; DATE bound by calendar
+ (apply #'encode-time ; DATE bound by calendar
(list 0 0 0 (nth 1 date) (car date) (nth 2 date))))
1 11))
"\\|\\(<[0-9]+-[0-9]+-[0-9]+[^>\n]+?\\+[0-9]+[hdwmy]>\\)"
"\\|\\(<%%\\(([^>\n]+)\\)>\\)"))
- marker hdmarker deadlinep scheduledp clockp closedp inactivep
- donep tmp priority category level ee txt timestr tags
- b0 b3 e3 head todo-state end-of-match show-all warntime habitp
- inherited-tags ts-date)
+ timestamp-items)
(goto-char (point-min))
- (while (setq end-of-match (re-search-forward regexp nil t))
- (setq b0 (match-beginning 0)
- b3 (match-beginning 3) e3 (match-end 3)
- todo-state (save-match-data (ignore-errors (org-get-todo-state)))
- habitp (and (functionp 'org-is-habit-p) (save-match-data (org-is-habit-p)))
- show-all (or (eq org-agenda-repeating-timestamp-show-all t)
- (member todo-state
- org-agenda-repeating-timestamp-show-all)))
+ (while (re-search-forward regexp nil t)
+ ;; Skip date ranges, scheduled and deadlines, which are handled
+ ;; specially. Also skip time-stamps before first headline as
+ ;; there would be no entry to add to the agenda. Eventually,
+ ;; ignore clock entries.
(catch :skip
- (and (org-at-date-range-p) (throw :skip nil))
- (org-agenda-skip)
- (if (and (match-end 1)
- (not (= d1 (org-agenda--timestamp-to-absolute
- (match-string 1) d1 nil show-all
- (current-buffer) b0))))
- (throw :skip nil))
- (if (and e3
- (not (org-diary-sexp-entry (buffer-substring b3 e3) "" date)))
+ (save-match-data
+ (when (or (org-at-date-range-p)
+ (org-at-planning-p)
+ (org-before-first-heading-p)
+ (and org-agenda-include-inactive-timestamps
+ (org-at-clock-log-p)))
(throw :skip nil))
- (setq tmp (buffer-substring (max (point-min)
- (- b0 org-ds-keyword-length))
- b0)
- timestr (if b3 "" (buffer-substring b0 (point-at-eol)))
- inactivep (= (char-after b0) ?\[)
- deadlinep (string-match org-deadline-regexp tmp)
- scheduledp (string-match org-scheduled-regexp tmp)
- closedp (and org-agenda-include-inactive-timestamps
- (string-match org-closed-string tmp))
- clockp (and org-agenda-include-inactive-timestamps
- (or (string-match org-clock-string tmp)
- (string-match "]-+\\'" tmp)))
- warntime (get-text-property (point) 'org-appt-warntime)
- donep (member todo-state org-done-keywords))
- (if (or scheduledp deadlinep closedp clockp
- (and donep org-agenda-skip-timestamp-if-done))
+ (org-agenda-skip))
+ (let* ((pos (match-beginning 0))
+ (repeat (match-string 1))
+ (sexp-entry (match-string 3))
+ (time-stamp (if (or repeat sexp-entry) (match-string 0)
+ (save-excursion
+ (goto-char pos)
+ (looking-at org-ts-regexp-both)
+ (match-string 0))))
+ (todo-state (org-get-todo-state))
+ (show-all (or (eq org-agenda-repeating-timestamp-show-all t)
+ (member todo-state
+ org-agenda-repeating-timestamp-show-all)))
+ (warntime (get-text-property (point) 'org-appt-warntime))
+ (done? (member todo-state org-done-keywords)))
+ ;; Possibly skip done tasks.
+ (when (and done? org-agenda-skip-timestamp-if-done)
(throw :skip t))
- (if (string-match ">" timestr)
- ;; substring should only run to end of time stamp
- (setq timestr (substring timestr 0 (match-end 0))))
- (setq marker (org-agenda-new-marker b0)
- category (org-get-category b0))
- (save-excursion
- (if (not (re-search-backward org-outline-regexp-bol nil t))
- (throw :skip nil)
- (goto-char (match-beginning 0))
- (if (and (eq t org-agenda-skip-timestamp-if-deadline-is-shown)
- (assoc (point) deadline-position-alist))
- (throw :skip nil))
- (setq hdmarker (org-agenda-new-marker)
- inherited-tags
- (or (eq org-agenda-show-inherited-tags 'always)
- (and (listp org-agenda-show-inherited-tags)
- (memq 'agenda org-agenda-show-inherited-tags))
- (and (eq org-agenda-show-inherited-tags t)
- (or (eq org-agenda-use-tag-inheritance t)
- (memq 'agenda org-agenda-use-tag-inheritance))))
- tags (org-get-tags-at nil (not inherited-tags))
- level (make-string (org-reduced-level (org-outline-level)) ? ))
- (looking-at "\\*+[ \t]+\\(.*\\)")
- (setq head (match-string 1))
- (setq txt (org-agenda-format-item
- (if inactivep org-agenda-inactive-leader nil)
- head level category tags timestr
- remove-re habitp)))
- (setq priority (org-get-priority txt))
- (org-add-props txt props 'priority priority
- 'org-marker marker 'org-hd-marker hdmarker
- 'date date
- 'level level
- 'ts-date
- (ignore-errors (org-time-string-to-absolute timestr))
- 'todo-state todo-state
- 'warntime warntime
- 'type "timestamp")
- (push txt ee))
- (if org-agenda-skip-additional-timestamps-same-entry
- (outline-next-heading)
- (goto-char end-of-match))))
- (nreverse ee)))
+ ;; S-exp entry doesn't match current day: skip it.
+ (when (and sexp-entry (not (org-diary-sexp-entry sexp-entry "" date)))
+ (throw :skip nil))
+ ;; When time-stamp doesn't match CURRENT but has a repeater,
+ ;; make sure it repeats on CURRENT. Furthermore, if
+ ;; SHOW-ALL is nil, ensure that repeats are only the first
+ ;; before and the first after today.
+ (when (and repeat
+ (if show-all
+ (/= current
+ (org-agenda--timestamp-to-absolute
+ repeat current 'future (current-buffer) pos))
+ (and (/= current
+ (org-agenda--timestamp-to-absolute
+ repeat today 'past (current-buffer) pos))
+ (/= current
+ (org-agenda--timestamp-to-absolute
+ repeat today 'future (current-buffer) pos)))))
+ (throw :skip nil))
+ (save-excursion
+ (re-search-backward org-outline-regexp-bol nil t)
+ ;; Possibly skip time-stamp when a deadline is set.
+ (when (and org-agenda-skip-timestamp-if-deadline-is-shown
+ (assq (point) deadline-position-alist))
+ (throw :skip nil))
+ (let* ((category (org-get-category pos))
+ (inherited-tags
+ (or (eq org-agenda-show-inherited-tags 'always)
+ (and (consp org-agenda-show-inherited-tags)
+ (memq 'agenda org-agenda-show-inherited-tags))
+ (and (eq org-agenda-show-inherited-tags t)
+ (or (eq org-agenda-use-tag-inheritance t)
+ (memq 'agenda
+ org-agenda-use-tag-inheritance)))))
+ (tags (org-get-tags-at nil (not inherited-tags)))
+ (level (make-string (org-reduced-level (org-outline-level))
+ ?\s))
+ (head (and (looking-at "\\*+[ \t]+\\(.*\\)")
+ (match-string 1)))
+ (inactive? (= (char-after pos) ?\[))
+ (habit? (and (fboundp 'org-is-habit-p) (org-is-habit-p)))
+ (item
+ (org-agenda-format-item
+ (and inactive? org-agenda-inactive-leader)
+ head level category tags time-stamp org-ts-regexp habit?)))
+ (org-add-props item props
+ 'priority (if habit?
+ (org-habit-get-priority (org-habit-parse-todo))
+ (org-get-priority item))
+ 'org-marker (org-agenda-new-marker pos)
+ 'org-hd-marker (org-agenda-new-marker)
+ 'date date
+ 'level level
+ 'ts-date (if repeat (org-agenda--timestamp-to-absolute repeat)
+ current)
+ 'todo-state todo-state
+ 'warntime warntime
+ 'type "timestamp")
+ (push item timestamp-items))))
+ (when org-agenda-skip-additional-timestamps-same-entry
+ (outline-next-heading))))
+ (nreverse timestamp-items)))
(defun org-agenda-get-sexps ()
"Return the sexp information for agenda display."
@@ -6037,7 +6054,8 @@ specification like [h]h:mm."
(regexp (if with-hour
org-deadline-time-hour-regexp
org-deadline-time-regexp))
- (todayp (org-agenda-today-p date)) ; DATE bound by calendar.
+ (today (org-today))
+ (today? (org-agenda-today-p date)) ; DATE bound by calendar.
(current (calendar-absolute-from-gregorian date))
deadline-items)
(goto-char (point-min))
@@ -6048,18 +6066,24 @@ specification like [h]h:mm."
(let* ((s (match-string 1))
(pos (1- (match-beginning 1)))
(todo-state (save-match-data (org-get-todo-state)))
- (donep (member todo-state org-done-keywords))
+ (done? (member todo-state org-done-keywords))
(show-all (or (eq org-agenda-repeating-timestamp-show-all t)
(member todo-state
org-agenda-repeating-timestamp-show-all)))
- ;; DEADLINE is the current scheduled date. When it
- ;; contains a repeater and SHOW-ALL is non-nil,
- ;; LAST-REPEAT is the repeat closest to CURRENT.
- ;; Otherwise, LAST-REPEAT is equal to DEADLINE.
- (last-repeat (org-agenda--timestamp-to-absolute
- s current 'past show-all (current-buffer) pos))
- (deadline (org-agenda--timestamp-to-absolute s current))
- (diff (- last-repeat current))
+ ;; DEADLINE is the bare deadline date, i.e., without
+ ;; any repeater, or the last repeat if SHOW-ALL is
+ ;; non-nil. REPEAT is closest repeat after CURRENT, if
+ ;; all repeated time stamps are to be shown, or after
+ ;; TODAY otherwise. REPEAT only applies to future
+ ;; dates.
+ (deadline (if show-all (org-agenda--timestamp-to-absolute s)
+ (org-agenda--timestamp-to-absolute
+ s today 'past (current-buffer) pos)))
+ (repeat
+ (if (< current today) deadline
+ (org-agenda--timestamp-to-absolute
+ s (if show-all current today) 'future (current-buffer) pos)))
+ (diff (- deadline current))
(suppress-prewarning
(let ((scheduled
(and org-agenda-skip-deadline-prewarning-if-scheduled
@@ -6074,14 +6098,7 @@ specification like [h]h:mm."
((eq org-agenda-skip-deadline-prewarning-if-scheduled
'pre-scheduled)
;; Set pre-warning to no earlier than SCHEDULED.
- (min (- last-repeat
- (org-agenda--timestamp-to-absolute
- scheduled current 'past show-all
- (current-buffer)
- (save-excursion
- (beginning-of-line)
- (1+ (search-forward org-deadline-string)))))
- org-deadline-warning-days))
+ (min (- deadline scheduled) org-deadline-warning-days))
;; Set pre-warning to deadline.
(t 0))))
(wdays (if suppress-prewarning
@@ -6090,14 +6107,17 @@ specification like [h]h:mm."
(org-get-wdays s))))
;; When to show a deadline in the calendar: if the
;; expiration is within WDAYS warning time. Past-due
- ;; deadlines are only shown on the current date
- (unless (or (and (<= diff wdays)
- (and todayp (not org-agenda-only-exact-dates)))
- (= diff 0))
+ ;; deadlines are only shown on today agenda.
+ (when (cond ((= current deadline) nil)
+ ((< deadline today)
+ (and (not today?)
+ (or (< current today) (/= repeat current))))
+ ((> deadline current)
+ (or (not today?) (> diff wdays)))
+ (t (/= repeat current)))
(throw :skip nil))
- ;; Skip done tasks if `org-agenda-skip-deadline-if-done' is
- ;; non-nil or if it isn't applicable to CURRENT deadline.
- (when (and donep
+ ;; Possibly skip done tasks.
+ (when (and done?
(or org-agenda-skip-deadline-if-done
(/= deadline current)))
(throw :skip nil))
@@ -6117,28 +6137,35 @@ specification like [h]h:mm."
(memq 'agenda
org-agenda-use-tag-inheritance)))))
(tags (org-get-tags-at nil (not inherited-tags)))
- (timestr
- (if (string-match " \\([012]?[0-9]:[0-9][0-9]\\)" s)
- (concat (substring s (match-beginning 1)) " ")
- 'time))
+ (time
+ (cond
+ ;; No time of day designation if it is only
+ ;; a reminder.
+ ((and (/= current deadline) (/= current repeat)) nil)
+ ((string-match " \\([012]?[0-9]:[0-9][0-9]\\)" s)
+ (concat (substring s (match-beginning 1)) " "))
+ (t 'time)))
(item
(org-agenda-format-item
- ;; For past deadlines, make sure to report time
- ;; difference since date S, not since closest
- ;; repeater.
- (let ((diff (if (< (org-today) current) diff
- (- deadline current))))
- (if (= diff 0) (car org-agenda-deadline-leaders)
- (let ((future (nth 1 org-agenda-deadline-leaders))
- (past (nth 2 org-agenda-deadline-leaders)))
- (cond ((> diff 0) (format future diff))
- ((string= future past) (format past diff))
- (t (format past (abs diff)))))))
+ ;; Insert appropriate suffixes before deadlines.
+ (pcase-let ((`(,now ,future ,past)
+ org-agenda-deadline-leaders))
+ (cond
+ ;; Future (i.e., repeated) deadlines are
+ ;; displayed as new headlines.
+ ((> current today) now)
+ ;; When SHOW-ALL is nil, prefer repeated
+ ;; deadlines over reminders of past deadlines.
+ ((and (not show-all) (= repeat today)) now)
+ ((= deadline current) now)
+ ((< deadline current) (format past (- diff)))
+ (t (format future diff))))
head level category tags
- (and (= diff 0) timestr)))
+ (and (or (= repeat current) (= deadline current))
+ time)))
(face (org-agenda-deadline-face
(- 1 (/ (float (- deadline current)) (max wdays 1)))))
- (upcomingp (and todayp (> diff 0)))
+ (upcoming? (and today? (> deadline today)))
(warntime (get-text-property (point) 'org-appt-warntime)))
(org-add-props item props
'org-marker (org-agenda-new-marker pos)
@@ -6146,11 +6173,19 @@ specification like [h]h:mm."
'warntime warntime
'level level
'ts-date deadline
- 'priority (- (org-get-priority item) diff)
+ 'priority
+ ;; Adjust priority to today reminders about deadlines.
+ ;; Overdue deadlines get the highest priority
+ ;; increase, then imminent deadlines and eventually
+ ;; more distant deadlines.
+ (let ((adjust (cond ((not today?) 0)
+ ((and (not show-all) (= repeat current)) 0)
+ (t (- diff)))))
+ (+ adjust (org-get-priority item)))
'todo-state todo-state
- 'type (if upcomingp "upcoming-deadline" "deadline")
- 'date (if upcomingp date deadline)
- 'face (if donep 'org-agenda-done face)
+ 'type (if upcoming? "upcoming-deadline" "deadline")
+ 'date (if upcoming? date deadline)
+ 'face (if done? 'org-agenda-done face)
'undone-face face
'done-face 'org-agenda-done)
(push item deadline-items))))))
@@ -6159,10 +6194,7 @@ specification like [h]h:mm."
(defun org-agenda-deadline-face (fraction)
"Return the face to displaying a deadline item.
FRACTION is what fraction of the head-warning time has passed."
- (let ((faces org-agenda-deadline-faces) f)
- (catch 'exit
- (while (setq f (pop faces))
- (if (>= fraction (car f)) (throw 'exit (cdr f)))))))
+ (assoc-default fraction org-agenda-deadline-faces #'<=))
(defun org-agenda-get-scheduled (&optional deadlines with-hour)
"Return the scheduled information for agenda display.
@@ -6175,11 +6207,12 @@ scheduled items with an hour specification like [h]h:mm."
'done-face 'org-agenda-done
'mouse-face 'highlight
'help-echo
- (format "mouse-2 or RET jump to org file %s"
+ (format "mouse-2 or RET jump to Org file %s"
(abbreviate-file-name buffer-file-name))))
(regexp (if with-hour
org-scheduled-time-hour-regexp
org-scheduled-time-regexp))
+ (today (org-today))
(todayp (org-agenda-today-p date)) ; DATE bound by calendar.
(current (calendar-absolute-from-gregorian date))
(deadline-pos
@@ -6200,16 +6233,25 @@ scheduled items with an hour specification like [h]h:mm."
(show-all (or (eq org-agenda-repeating-timestamp-show-all t)
(member todo-state
org-agenda-repeating-timestamp-show-all)))
- ;; SCHEDULE is the current scheduled date. When it
- ;; contains a repeater and SHOW-ALL is non-nil,
- ;; LAST-REPEAT is the repeat closest to CURRENT.
- ;; Otherwise, LAST-REPEAT is equal to SCHEDULE.
- (last-repeat (org-agenda--timestamp-to-absolute
- s current 'past show-all (current-buffer) pos))
- (schedule (org-agenda--timestamp-to-absolute s current))
- (diff (- last-repeat current))
+ ;; SCHEDULE is the bare scheduled date, i.e., without
+ ;; any repeater if non-nil, or last repeat if SHOW-ALL
+ ;; is nil. REPEAT is the closest repeat after CURRENT,
+ ;; if all repeated time stamps are to be shown, or
+ ;; after TODAY otherwise. REPEAT only applies to
+ ;; future dates.
+ (schedule (if show-all (org-agenda--timestamp-to-absolute s)
+ (org-agenda--timestamp-to-absolute
+ s today 'past (current-buffer) pos)))
+ (repeat (cond ((< current today) schedule)
+ (show-all
+ (org-agenda--timestamp-to-absolute
+ s current 'future (current-buffer) pos))
+ (t
+ (org-agenda--timestamp-to-absolute
+ s today 'future (current-buffer) pos))))
+ (diff (- current schedule))
(warntime (get-text-property (point) 'org-appt-warntime))
- (pastschedp (< schedule (org-today)))
+ (pastschedp (< schedule today))
(habitp (and (fboundp 'org-is-habit-p) (org-is-habit-p)))
(suppress-delay
(let ((deadline (and org-agenda-skip-scheduled-delay-if-deadline
@@ -6226,44 +6268,37 @@ scheduled items with an hour specification like [h]h:mm."
;; Set delay to no later than DEADLINE. If
;; DEADLINE has a repeater, compare last schedule
;; repeat and last deadline repeat.
- (min (- last-repeat
- (org-agenda--timestamp-to-absolute
- deadline current 'past show-all
- (current-buffer)
- (save-excursion
- (beginning-of-line)
- (1+ (search-forward org-deadline-string)))))
- org-scheduled-delay-days))
+ (min (- schedule deadline) org-scheduled-delay-days))
(t 0))))
(ddays
(cond
;; Nullify delay when a repeater triggered already
;; and the delay is of the form --Xd.
((and (string-match-p "--[0-9]+[hdwmy]" s)
- (/= schedule last-repeat))
+ (> current schedule))
0)
(suppress-delay
(let ((org-scheduled-delay-days suppress-delay))
(org-get-wdays s t t)))
(t (org-get-wdays s t)))))
- ;; Only show a scheduled item in the calendar if it is on or
- ;; past the current date. Skip it if it has been displayed
- ;; for more than `org-scheduled-past-days'.
- (unless (or (and (>= ddays 0) (= diff (- ddays)))
- (and (< (+ diff ddays) 0)
- (< (abs diff) org-scheduled-past-days)
- (and todayp (not org-agenda-only-exact-dates)))
- (and todayp
- habitp
- (bound-and-true-p org-habit-show-all-today)))
- (throw :skip nil))
- ;; Skip done habits, or tasks if
- ;; `org-agenda-skip-deadline-if-done' is non-nil or if it
- ;; was scheduled in the past anyway.
+ ;; Display scheduled items at base date (SCHEDULE), today if
+ ;; scheduled before the current date, and at any repeat past
+ ;; today. However, skip delayed items and items that have
+ ;; been displayed for more than `org-scheduled-past-days'.
+ (unless (and todayp
+ habitp
+ (bound-and-true-p org-habit-show-all-today))
+ (when (or (and (> ddays 0) (< diff ddays))
+ (> diff org-scheduled-past-days)
+ (> schedule current)
+ (and (< schedule current)
+ (not todayp)
+ (/= repeat current)))
+ (throw :skip nil)))
+ ;; Possibly skip done tasks.
(when (and donep
(or org-agenda-skip-scheduled-if-done
- (/= schedule current)
- habitp))
+ (/= schedule current)))
(throw :skip nil))
;; Skip entry if it already appears as a deadline, per
;; `org-agenda-skip-scheduled-if-deadline-is-shown'. This
@@ -6274,16 +6309,16 @@ scheduled items with an hour specification like [h]h:mm."
habitp))
nil)
(`repeated-after-deadline
- (>= last-repeat
- (time-to-days (org-get-deadline-time (point)))))
+ (>= repeat (time-to-days (org-get-deadline-time (point)))))
(`not-today pastschedp)
(`t t)
(_ nil))
(throw :skip nil))
;; Skip habits if `org-habit-show-habits' is nil, or if we
- ;; only show them for today.
+ ;; only show them for today. Also skip done habits.
(when (and habitp
- (or (not (bound-and-true-p org-habit-show-habits))
+ (or donep
+ (not (bound-and-true-p org-habit-show-habits))
(and (not todayp)
(bound-and-true-p
org-habit-show-habits-only-for-today))))
@@ -6304,22 +6339,32 @@ scheduled items with an hour specification like [h]h:mm."
(level
(make-string (org-reduced-level (org-outline-level)) ?\s))
(head (buffer-substring (point) (line-end-position)))
- (timestr
- (if (string-match " \\([012]?[0-9]:[0-9][0-9]\\)" s)
- (concat (substring s (match-beginning 1)) " ")
- 'time))
- (item (org-agenda-format-item
- ;; For past scheduled dates, make sure to
- ;; report time difference since SCHEDULE,
- ;; not since closest repeater.
- (let ((diff (if (< (org-today) current) diff
- (- schedule current))))
- (if (= diff 0) (car org-agenda-scheduled-leaders)
- (format (nth 1 org-agenda-scheduled-leaders)
- (- 1 diff))))
- head level category tags
- (and (= diff 0) timestr)
- nil habitp))
+ (time
+ (cond
+ ;; No time of day designation if it is only
+ ;; a reminder.
+ ((and (/= current schedule) (/= current repeat)) nil)
+ ((string-match " \\([012]?[0-9]:[0-9][0-9]\\)" s)
+ (concat (substring s (match-beginning 1)) " "))
+ (t 'time)))
+ (item
+ (org-agenda-format-item
+ (pcase-let ((`(,first ,next) org-agenda-scheduled-leaders))
+ (cond
+ ;; If CURRENT is in the future, don't use past
+ ;; scheduled prefix.
+ ((> current today) first)
+ ;; SHOW-ALL focuses on future repeats. If one
+ ;; such repeat happens today, ignore late
+ ;; schedule reminder. However, still report
+ ;; such reminders when repeat happens later.
+ ((and (not show-all) (= repeat today)) first)
+ ;; Initial report.
+ ((= schedule current) first)
+ ;; Subsequent reminders. Count from base
+ ;; schedule.
+ (t (format next (1+ diff)))))
+ head level category tags time nil habitp))
(face (cond ((and (not habitp) pastschedp)
'org-scheduled-previously)
(todayp 'org-scheduled-today)
@@ -6336,7 +6381,7 @@ scheduled items with an hour specification like [h]h:mm."
'warntime warntime
'level level
'priority (if habitp (org-habit-get-priority habitp)
- (+ 94 (- 5 diff) (org-get-priority item)))
+ (+ 99 diff (org-get-priority item)))
'org-habit-p habitp
'todo-state todo-state)
(push item scheduled-items))))))
@@ -6445,7 +6490,7 @@ The flag is set if the currently compiled format contains a `%b'.")
(defun org-agenda-get-category-icon (category)
"Return an image for CATEGORY according to `org-agenda-category-icon-alist'."
- (dolist (entry org-agenda-category-icon-alist)
+ (cl-dolist (entry org-agenda-category-icon-alist)
(when (string-match-p (car entry) category)
(if (listp (cadr entry))
(cl-return (cadr entry))
@@ -7000,7 +7045,8 @@ The optional argument TYPE tells the agenda type."
(let* ((pla (text-property-any 0 (length a) 'org-heading t a))
(plb (text-property-any 0 (length b) 'org-heading t b))
(ta (and pla (substring a pla)))
- (tb (and plb (substring b plb))))
+ (tb (and plb (substring b plb)))
+ (case-fold-search nil))
(when pla
(if (string-match (concat "\\`[ \t]*" (or (get-text-property 0 'org-todo-regexp a) "")
"\\([ \t]*\\[[a-zA-Z0-9]\\]\\)? *") ta)
@@ -7980,41 +8026,48 @@ With prefix ARG, go backward that many times the current span."
"Switch to default view for agenda."
(interactive)
(org-agenda-change-time-span org-agenda-span))
+
(defun org-agenda-day-view (&optional day-of-month)
"Switch to daily view for agenda.
With argument DAY-OF-MONTH, switch to that day of the month."
(interactive "P")
(org-agenda-change-time-span 'day day-of-month))
+
(defun org-agenda-week-view (&optional iso-week)
- "Switch to daily view for agenda.
+ "Switch to weekly view for agenda.
With argument ISO-WEEK, switch to the corresponding ISO week.
-If ISO-WEEK has more then 2 digits, only the last two encode the
-week. Any digits before this encode a year. So 200712 means
-week 12 of year 2007. Years in the range 1938-2037 can also be
-written as 2-digit years."
+If ISO-WEEK has more then 2 digits, only the last two encode
+the week. Any digits before this encode a year. So 200712
+means week 12 of year 2007. Years ranging from 70 years ago
+to 30 years in the future can also be written as 2-digit years."
(interactive "P")
(org-agenda-change-time-span 'week iso-week))
+
(defun org-agenda-fortnight-view (&optional iso-week)
- "Switch to daily view for agenda.
+ "Switch to fortnightly view for agenda.
With argument ISO-WEEK, switch to the corresponding ISO week.
-If ISO-WEEK has more then 2 digits, only the last two encode the
-week. Any digits before this encode a year. So 200712 means
-week 12 of year 2007. Years in the range 1938-2037 can also be
-written as 2-digit years."
+If ISO-WEEK has more then 2 digits, only the last two encode
+the week. Any digits before this encode a year. So 200712
+means week 12 of year 2007. Years ranging from 70 years ago
+to 30 years in the future can also be written as 2-digit years."
(interactive "P")
(org-agenda-change-time-span 'fortnight iso-week))
+
(defun org-agenda-month-view (&optional month)
"Switch to monthly view for agenda.
-With argument MONTH, switch to that month."
+With argument MONTH, switch to that month. If MONTH has more
+then 2 digits, only the last two encode the month. Any digits
+before this encode a year. So 200712 means December year 2007.
+Years ranging from 70 years ago to 30 years in the future can
+also be written as 2-digit years."
(interactive "P")
(org-agenda-change-time-span 'month month))
+
(defun org-agenda-year-view (&optional year)
"Switch to yearly view for agenda.
-With argument YEAR, switch to that year.
-If MONTH has more then 2 digits, only the last two encode the
-month. Any digits before this encode a year. So 200712 means
-December year 2007. Years in the range 1938-2037 can also be
-written as 2-digit years."
+With argument YEAR, switch to that year. Years ranging from 70
+years ago to 30 years in the future can also be written as
+2-digit years."
(interactive "P")
(when year
(setq year (org-small-year-to-year year)))
diff --git a/lisp/org-archive.el b/lisp/org-archive.el
index 6daed74..3ba8bf1 100644
--- a/lisp/org-archive.el
+++ b/lisp/org-archive.el
@@ -356,7 +356,8 @@ this heading."
(org-set-tags-to all-tags))
;; Mark the entry as done
(when (and org-archive-mark-done
- (looking-at org-todo-line-regexp)
+ (let ((case-fold-search nil))
+ (looking-at org-todo-line-regexp))
(or (not (match-end 2))
(not (member (match-string 2) org-done-keywords))))
(let (org-log-done org-todo-log-states)
@@ -395,9 +396,12 @@ this heading."
;;;###autoload
(defun org-archive-to-archive-sibling ()
"Archive the current heading by moving it under the archive sibling.
+
The archive sibling is a sibling of the heading with the heading name
`org-archive-sibling-heading' and an `org-archive-tag' tag. If this
-sibling does not exist, it will be created at the end of the subtree."
+sibling does not exist, it will be created at the end of the subtree.
+
+Archiving time is retained in the ARCHIVE_TIME node property."
(interactive)
(if (and (org-region-active-p) org-loop-over-headlines-in-active-region)
(let ((cl (when (eq org-loop-over-headlines-in-active-region 'start-level)
@@ -469,8 +473,9 @@ it is on a headline, try all direct children.
When TAG is non-nil, don't move trees, but mark them with the ARCHIVE tag."
(org-archive-all-matches
(lambda (_beg end)
- (unless (re-search-forward org-not-done-heading-regexp end t)
- "no open TODO items"))
+ (let ((case-fold-search nil))
+ (unless (re-search-forward org-not-done-heading-regexp end t)
+ "no open TODO items")))
tag))
(defun org-archive-all-old (&optional tag)
diff --git a/lisp/org-capture.el b/lisp/org-capture.el
index ced8399..f757927 100644
--- a/lisp/org-capture.el
+++ b/lisp/org-capture.el
@@ -133,7 +133,7 @@ target Specification of where the captured item should be placed.
(file \"path/to/file\")
Text will be placed at the beginning or end of that file
- (id \"id of existing org entry\")
+ (id \"id of existing Org entry\")
File as child of this entry, or in the body of the entry
(file+headline \"path/to/file\" \"node headline\")
@@ -1007,25 +1007,31 @@ Store them in the capture property list."
:decrypted decrypted-hl-pos))))
(defun org-capture-expand-file (file)
- "Expand functions and symbols for FILE.
-When FILE is a function, call it. When it is a variable,
-retrieve its value. When it is the empty string, return
-`org-default-notes-file'. In any other case, return FILE as-is."
+ "Expand functions, symbols and file names for FILE.
+When FILE is a function, call it. When it is a form, evaluate
+it. When it is a variable, retrieve the value. When it is
+a string, treat it as a file name, possibly expanding it
+according to `org-directory', and return it. If it is the empty
+string, however, return `org-default-notes-file'. In any other
+case, raise an error."
(cond
((equal file "") org-default-notes-file)
+ ((stringp file) (expand-file-name file org-directory))
((functionp file) (funcall file))
((and (symbolp file) (boundp file)) (symbol-value file))
+ ((consp file) (eval file))
(t file)))
(defun org-capture-target-buffer (file)
- "Get a buffer for FILE."
- (setq file (org-capture-expand-file file))
- (setq file (or (org-string-nw-p file)
- org-default-notes-file
- (error "No notes file specified, and no default available")))
- (or (org-find-base-buffer-visiting file)
- (progn (org-capture-put :new-buffer t)
- (find-file-noselect (expand-file-name file org-directory)))))
+ "Get a buffer for FILE.
+FILE is a generalized file location, as handled by
+`org-capture-expand-file'."
+ (let ((file (or (org-string-nw-p (org-capture-expand-file file))
+ org-default-notes-file
+ (error "No notes file specified, and no default available"))))
+ (or (org-find-base-buffer-visiting file)
+ (progn (org-capture-put :new-buffer t)
+ (find-file-noselect file)))))
(defun org-capture-place-template (&optional inhibit-wconf-store)
"Insert the template at the target location, and display the buffer.
diff --git a/lisp/org-clock.el b/lisp/org-clock.el
index b148a08..65c13fd 100644
--- a/lisp/org-clock.el
+++ b/lisp/org-clock.el
@@ -37,8 +37,6 @@
(declare-function org-element-type "org-element" (element))
(declare-function org-table-goto-line "org-table" (n))
-(defvar org-clock-stored-history nil
- "Clock history, populated by `org-clock-load', which see.")
(defvar org-frame-title-format-backup frame-title-format)
(defvar org-time-stamp-formats)
(defvar org-ts-what)
@@ -461,6 +459,11 @@ to add an effort property.")
(defvar org-clock-has-been-used nil
"Has the clock been used during the current Emacs session?")
+(defvar org-clock-stored-history nil
+ "Clock history, populated by `org-clock-load'")
+(defvar org-clock-stored-resume-clock nil
+ "Clock to resume, saved by `org-clock-load'")
+
(defconst org-clock--oldest-date
(let* ((dichotomy
(lambda (min max pred)
@@ -676,7 +679,7 @@ If not, show simply the clocked time like 01:50."
"] (" (replace-regexp-in-string "%" "%%" org-clock-heading) ")")
'face 'org-mode-line-clock)))
(format clockstr work-done-str))
- (propertize (concat "[" (org-minutes-to-clocksum-string clocked-time)
+ (propertize (concat " [" (org-minutes-to-clocksum-string clocked-time)
"]" (format " (%s)" org-clock-heading))
'face 'org-mode-line-clock))))
@@ -2367,6 +2370,7 @@ the currently selected interval size."
(`file-with-archives
(and buffer-file-name
(org-add-archive-files (list buffer-file-name))))
+ ((pred consp) scope)
(_ (or (buffer-file-name) (current-buffer)))))
(block (plist-get params :block))
(ts (plist-get params :tstart))
@@ -2427,8 +2431,7 @@ the currently selected interval size."
;; Even though `file-with-archives' can consist of
;; multiple files, we consider this is one extended file
;; instead.
- (cond ((eq scope 'file-with-archives) nil)
- ((consp files)))))
+ (and (consp files) (not (eq scope 'file-with-archives)))))
(funcall formatter
origin
@@ -2923,85 +2926,66 @@ The details of what will be saved are regulated by the variable
(or org-clock-loaded
org-clock-has-been-used
(not (file-exists-p org-clock-persist-file))))
- (let (b)
- (with-current-buffer (find-file (expand-file-name org-clock-persist-file))
- (progn
- (delete-region (point-min) (point-max))
- ;;Store clock
- (insert (format ";; org-persist.el - %s at %s\n"
- (system-name) (format-time-string
- (cdr org-time-stamp-formats))))
- (if (and (memq org-clock-persist '(t clock))
- (setq b (org-clocking-buffer))
- (setq b (or (buffer-base-buffer b) b))
- (buffer-live-p b)
- (buffer-file-name b)
- (or (not org-clock-persist-query-save)
- (y-or-n-p (concat "Save current clock ("
- org-clock-heading ") "))))
- (insert "(setq resume-clock '(\""
- (buffer-file-name (org-clocking-buffer))
- "\" . " (int-to-string (marker-position org-clock-marker))
- "))\n"))
- ;; Store clocked task history. Tasks are stored reversed to make
- ;; reading simpler
- (when (and (memq org-clock-persist '(t history))
- org-clock-history)
- (insert
- "(setq org-clock-stored-history '("
- (mapconcat
- (lambda (m)
- (when (and (setq b (marker-buffer m))
- (setq b (or (buffer-base-buffer b) b))
- (buffer-live-p b)
- (buffer-file-name b))
- (concat "(\"" (buffer-file-name b)
- "\" . " (int-to-string (marker-position m))
- ")")))
- (reverse org-clock-history) " ") "))\n"))
- (save-buffer)
- (kill-buffer (current-buffer)))))))
+ (with-temp-file org-clock-persist-file
+ (insert (format ";; org-persist.el - %s at %s\n"
+ (system-name)
+ (format-time-string (org-time-stamp-format t))))
+ ;; Store clock to be resumed.
+ (when (and (memq org-clock-persist '(t clock))
+ (let ((b (org-base-buffer (org-clocking-buffer))))
+ (and (buffer-live-p b)
+ (buffer-file-name b)
+ (or (not org-clock-persist-query-save)
+ (y-or-n-p (format "Save current clock (%s) "
+ org-clock-heading))))))
+ (insert
+ (format "(setq org-clock-stored-resume-clock '(%S . %d))\n"
+ (buffer-file-name (org-base-buffer (org-clocking-buffer)))
+ (marker-position org-clock-marker))))
+ ;; Store clocked task history. Tasks are stored reversed to
+ ;; make reading simpler.
+ (when (and (memq org-clock-persist '(t history))
+ org-clock-history)
+ (insert
+ (format "(setq org-clock-stored-history '(%s))\n"
+ (mapconcat
+ (lambda (m)
+ (let ((b (org-base-buffer (marker-buffer m))))
+ (when (and (buffer-live-p b)
+ (buffer-file-name b))
+ (format "(%S . %d)"
+ (buffer-file-name b)
+ (marker-position m)))))
+ (reverse org-clock-history)
+ " ")))))))
(defun org-clock-load ()
"Load clock-related data from disk, maybe resuming a stored clock."
(when (and org-clock-persist (not org-clock-loaded))
- (let ((filename (expand-file-name org-clock-persist-file))
- (org-clock-in-resume 'auto-restart)
- resume-clock)
- (if (not (file-readable-p filename))
- (message "Not restoring clock data; %s not found"
- org-clock-persist-file)
- (message "%s" "Restoring clock data")
- (setq org-clock-loaded t)
- ;; Load history.
- (load-file filename)
- (save-window-excursion
- (dolist (task org-clock-stored-history)
- (when (file-exists-p (car task))
- (org-clock-history-push (cdr task)
- (find-file (car task))))))
- ;; Resume clock.
- (when (and resume-clock org-clock-persist
- (file-exists-p (car resume-clock))
- (or (not org-clock-persist-query-resume)
- (y-or-n-p
- (concat
- "Resume clock ("
- (with-current-buffer (find-file (car resume-clock))
- (save-excursion
- (goto-char (cdr resume-clock))
- (org-back-to-heading t)
- (let ((case-fold-search nil))
- (and (looking-at org-complex-heading-regexp)
- (match-string 4)))))
- ") "))))
- (when (file-exists-p (car resume-clock))
- (with-current-buffer (find-file (car resume-clock))
- (goto-char (cdr resume-clock))
- (let ((org-clock-auto-clock-resolution nil))
- (org-clock-in)
- (if (outline-invisible-p)
- (org-show-context))))))))))
+ (if (file-readable-p org-clock-persist-file)
+ (message "Restoring clock data")
+ (message "Not restoring clock data; %S not found" org-clock-persist-file)
+ ;; Load history.
+ (load-file org-clock-persist-file)
+ (setq org-clock-loaded t)
+ (pcase-dolist (`(,(and file (pred file-exists-p)) . ,position)
+ org-clock-stored-history)
+ (org-clock-history-push position (find-file-noselect file)))
+ ;; Resume clock.
+ (pcase org-clock-stored-resume-clock
+ (`(,(and file (pred file-exists-p)) . ,position)
+ (with-current-buffer (find-file-noselect file)
+ (when (or (not org-clock-persist-query-resume)
+ (y-or-n-p (format "Resume clock (%s) "
+ (save-excursion
+ (goto-char position)
+ (org-get-heading t t)))))
+ (goto-char position)
+ (let ((org-clock-in-resume 'auto-restart)
+ (org-clock-auto-clock-resolution nil))
+ (org-clock-in)
+ (when (outline-invisible-p) (org-show-context))))))
+ (_ nil)))))
;; Suggested bindings
(org-defkey org-mode-map "\C-c\C-x\C-e" 'org-clock-modify-effort-estimate)
diff --git a/lisp/org-colview.el b/lisp/org-colview.el
index d33f505..3e53ccb 100644
--- a/lisp/org-colview.el
+++ b/lisp/org-colview.el
@@ -239,17 +239,15 @@ display, as a string."
(org-columns-compact-links value)))
(value)))
-(defun org-columns--collect-values (&optional agenda)
+(defun org-columns--collect-values (&optional compiled-fmt)
"Collect values for columns on the current line.
-When optional argument AGENDA is non-nil, assume the value is
-meant for the agenda, i.e., caller is `org-agenda-columns'.
-
Return a list of triplets (SPEC VALUE DISPLAYED) suitable for
`org-columns--display-here'.
This function assumes `org-columns-current-fmt-compiled' is
-initialized."
+initialized is set in the current buffer. However, it is
+possible to override it with optional argument COMPILED-FMT."
(let ((summaries (get-text-property (point) 'org-summaries)))
(mapcar
(lambda (spec)
@@ -257,19 +255,18 @@ initialized."
(`(,p . ,_)
(let* ((v (or (cdr (assoc spec summaries))
(org-entry-get (point) p 'selective t)
- (and agenda
+ (and compiled-fmt ;assume `org-agenda-columns'
;; Effort property is not defined. Try
;; to use appointment duration.
org-agenda-columns-add-appointments-to-effort-sum
(string= p (upcase org-effort-property))
(get-text-property (point) 'duration)
- (propertize
- (org-minutes-to-clocksum-string
- (get-text-property (point) 'duration))
- 'face 'org-warning))
+ (propertize (org-minutes-to-clocksum-string
+ (get-text-property (point) 'duration))
+ 'face 'org-warning))
"")))
(list spec v (org-columns--displayed-value spec v))))))
- org-columns-current-fmt-compiled)))
+ (or compiled-fmt org-columns-current-fmt-compiled))))
(defun org-columns--set-widths (cache)
"Compute the maximum column widths from the format and CACHE.
@@ -1068,12 +1065,12 @@ This function updates `org-columns-current-fmt-compiled'."
A time is expressed as HH:MM, HH:MM:SS, or with units defined in
`org-effort-durations'. Plain numbers are considered as hours."
(cond
- ((string-match "\\([0-9]+\\):\\([0-9]+\\)\\(?::\\([0-9]+\\)\\)?" s)
+ ((string-match-p org-columns--duration-re s)
+ (* 60 (org-duration-string-to-minutes s)))
+ ((string-match "\\`\\([0-9]+\\):\\([0-9]+\\)\\(?::\\([0-9]+\\)\\)?\\'" s)
(+ (* 3600 (string-to-number (match-string 1 s)))
(* 60 (string-to-number (match-string 2 s)))
(if (match-end 3) (string-to-number (match-string 3 s)) 0)))
- ((string-match-p org-columns--duration-re s)
- (* 60 (org-duration-string-to-minutes s)))
(t (* 3600 (string-to-number s)))))
(defun org-columns--age-to-seconds (s)
@@ -1507,26 +1504,26 @@ PARAMS is a property list of parameters:
(interactive)
(org-columns-remove-overlays)
(move-marker org-columns-begin-marker (point))
- (let ((org-columns--time (float-time (current-time)))
- (fmt
- (cond
- ((bound-and-true-p org-agenda-overriding-columns-format))
- ((let ((m (org-get-at-bol 'org-hd-marker)))
- (and m
- (or (org-entry-get m "COLUMNS" t)
- (with-current-buffer (marker-buffer m)
- org-columns-default-format)))))
- ((and (local-variable-p 'org-columns-current-fmt)
- org-columns-current-fmt))
- ((let ((m (next-single-property-change (point-min) 'org-hd-marker)))
- (and m
- (let ((m (get-text-property m 'org-hd-marker)))
- (or (org-entry-get m "COLUMNS" t)
- (with-current-buffer (marker-buffer m)
- org-columns-default-format))))))
- (t org-columns-default-format))))
- (setq-local org-columns-current-fmt fmt)
- (org-columns-compile-format fmt)
+ (let* ((org-columns--time (float-time (current-time)))
+ (fmt
+ (cond
+ ((bound-and-true-p org-agenda-overriding-columns-format))
+ ((let ((m (org-get-at-bol 'org-hd-marker)))
+ (and m
+ (or (org-entry-get m "COLUMNS" t)
+ (with-current-buffer (marker-buffer m)
+ org-columns-default-format)))))
+ ((and (local-variable-p 'org-columns-current-fmt)
+ org-columns-current-fmt))
+ ((let ((m (next-single-property-change (point-min) 'org-hd-marker)))
+ (and m
+ (let ((m (get-text-property m 'org-hd-marker)))
+ (or (org-entry-get m "COLUMNS" t)
+ (with-current-buffer (marker-buffer m)
+ org-columns-default-format))))))
+ (t org-columns-default-format)))
+ (compiled-fmt (org-columns-compile-format fmt)))
+ (setq org-columns-current-fmt fmt)
(when org-agenda-columns-compute-summary-properties
(org-agenda-colview-compute org-columns-current-fmt-compiled))
(save-excursion
@@ -1538,8 +1535,13 @@ PARAMS is a property list of parameters:
(org-get-at-bol 'org-marker))))
(when m
(push (cons (line-beginning-position)
+ ;; `org-columns-current-fmt-compiled' is
+ ;; initialized but only set locally to the
+ ;; agenda buffer. Since current buffer is
+ ;; changing, we need to force the original
+ ;; compiled-fmt there.
(org-with-point-at m
- (org-columns--collect-values 'agenda)))
+ (org-columns--collect-values compiled-fmt)))
cache)))
(forward-line))
(when cache
diff --git a/lisp/org-element.el b/lisp/org-element.el
index 027eea4..b86244e 100644
--- a/lisp/org-element.el
+++ b/lisp/org-element.el
@@ -1018,15 +1018,14 @@ Assume point is at beginning of the headline."
(standard-props (org-element--get-node-properties))
(time-props (org-element--get-time-properties))
(end (min (save-excursion (org-end-of-subtree t t)) limit))
- (pos-after-head (progn (forward-line) (point)))
(contents-begin (save-excursion
+ (forward-line)
(skip-chars-forward " \r\t\n" end)
(and (/= (point) end) (line-beginning-position))))
(contents-end (and contents-begin
(progn (goto-char end)
(skip-chars-backward " \r\t\n")
- (forward-line)
- (point)))))
+ (line-beginning-position 2)))))
(let ((headline
(list 'headline
(nconc
@@ -1035,7 +1034,7 @@ Assume point is at beginning of the headline."
:end end
:pre-blank
(if (not contents-begin) 0
- (count-lines pos-after-head contents-begin))
+ (1- (count-lines begin contents-begin)))
:contents-begin contents-begin
:contents-end contents-end
:level level
@@ -1043,9 +1042,10 @@ Assume point is at beginning of the headline."
:tags tags
:todo-keyword todo
:todo-type todo-type
- :post-blank (count-lines
- (or contents-end pos-after-head)
- end)
+ :post-blank
+ (if contents-end
+ (count-lines contents-end end)
+ (1- (count-lines begin end)))
:footnote-section-p footnote-section-p
:archivedp archivedp
:commentedp commentedp
@@ -1116,10 +1116,11 @@ CONTENTS is the contents of the element."
"Parse an inline task.
Return a list whose CAR is `inlinetask' and CDR is a plist
-containing `:title', `:begin', `:end', `:contents-begin' and
-`:contents-end', `:level', `:priority', `:raw-value', `:tags',
-`:todo-keyword', `:todo-type', `:scheduled', `:deadline',
-`:closed', `:post-blank' and `:post-affiliated' keywords.
+containing `:title', `:begin', `:end', `:pre-blank',
+`:contents-begin' and `:contents-end', `:level', `:priority',
+`:raw-value', `:tags', `:todo-keyword', `:todo-type',
+`:scheduled', `:deadline', `:closed', `:post-blank' and
+`:post-affiliated' keywords.
The plist also contains any property set in the property drawer,
with its name in upper cases and colons added at the
@@ -1157,18 +1158,20 @@ Assume point is at beginning of the inline task."
(task-end (save-excursion
(end-of-line)
(and (re-search-forward org-outline-regexp-bol limit t)
- (looking-at-p "END[ \t]*$")
+ (looking-at-p "[ \t]*END[ \t]*$")
(line-beginning-position))))
(standard-props (and task-end (org-element--get-node-properties)))
(time-props (and task-end (org-element--get-time-properties)))
- (contents-begin (progn (forward-line)
- (and task-end (< (point) task-end) (point))))
+ (contents-begin (and task-end
+ (< (point) task-end)
+ (progn
+ (forward-line)
+ (skip-chars-forward " \t\n")
+ (line-beginning-position))))
(contents-end (and contents-begin task-end))
- (before-blank (if (not task-end) (point)
- (goto-char task-end)
- (forward-line)
- (point)))
- (end (progn (skip-chars-forward " \r\t\n" limit)
+ (end (progn (when task-end (goto-char task-end))
+ (forward-line)
+ (skip-chars-forward " \r\t\n" limit)
(if (eobp) (point) (line-beginning-position))))
(inlinetask
(list 'inlinetask
@@ -1176,6 +1179,9 @@ Assume point is at beginning of the inline task."
(list :raw-value raw-value
:begin begin
:end end
+ :pre-blank
+ (if (not contents-begin) 0
+ (1- (count-lines begin contents-begin)))
:contents-begin contents-begin
:contents-end contents-end
:level level
@@ -1183,7 +1189,7 @@ Assume point is at beginning of the inline task."
:tags tags
:todo-keyword todo
:todo-type todo-type
- :post-blank (count-lines before-blank end)
+ :post-blank (1- (count-lines (or task-end begin) end))
:post-affiliated begin)
time-props
standard-props))))
@@ -3839,10 +3845,14 @@ element it has to parse."
(or (save-excursion (org-with-limited-levels (outline-next-heading)))
limit)))
;; Planning.
- ((and (eq mode 'planning) (looking-at org-planning-line-re))
+ ((and (eq mode 'planning)
+ (eq ?* (char-after (line-beginning-position 0)))
+ (looking-at org-planning-line-re))
(org-element-planning-parser limit))
;; Property drawer.
((and (memq mode '(planning property-drawer))
+ (eq ?* (char-after (line-beginning-position
+ (if (eq mode 'planning) 0 -1))))
(looking-at org-property-drawer-re))
(org-element-property-drawer-parser limit))
;; When not at bol, point is at the beginning of an item or
diff --git a/lisp/org-list.el b/lisp/org-list.el
index e8d9aef..bb39b6e 100644
--- a/lisp/org-list.el
+++ b/lisp/org-list.el
@@ -3036,7 +3036,7 @@ With a prefix argument ARG, change the region in a single item."
;; subtrees.
(when (< level ref-level) (setq ref-level level))
;; Remove stars and TODO keyword.
- (looking-at org-todo-line-regexp)
+ (let ((case-fold-search nil)) (looking-at org-todo-line-regexp))
(delete-region (point) (or (match-beginning 3)
(line-end-position)))
(insert bul)
diff --git a/lisp/org-loaddefs.el b/lisp/org-loaddefs.el
index 5bc5fef..1312741 100644
--- a/lisp/org-loaddefs.el
+++ b/lisp/org-loaddefs.el
@@ -979,10 +979,13 @@ this heading.
(autoload 'org-archive-to-archive-sibling "org-archive" "\
Archive the current heading by moving it under the archive sibling.
+
The archive sibling is a sibling of the heading with the heading name
`org-archive-sibling-heading' and an `org-archive-tag' tag. If this
sibling does not exist, it will be created at the end of the subtree.
+Archiving time is retained in the ARCHIVE_TIME node property.
+
\(fn)" t nil)
(autoload 'org-toggle-archive-tag "org-archive" "\
@@ -1815,6 +1818,7 @@ SIZE is a string Columns x Rows like for example \"3x2\".
(autoload 'org-table-convert-region "org-table" "\
Convert region to a table.
+
The region goes from BEG0 to END0, but these borders will be moved
slightly, to make sure a beginning of line in the first line is included.
@@ -1824,7 +1828,7 @@ following values:
\(4) Use the comma as a field separator
\(16) Use a TAB as field separator
\(64) Prompt for a regular expression as field separator
-integer When a number, use that many spaces as field separator
+integer When a number, use that many spaces, or a TAB, as field separator
regexp When a regular expression, use it to match the separator
nil When nil, the command tries to be smart and figure out the
separator in the following way:
diff --git a/lisp/org-pcomplete.el b/lisp/org-pcomplete.el
index f3b498e..5a52491 100644
--- a/lisp/org-pcomplete.el
+++ b/lisp/org-pcomplete.el
@@ -315,10 +315,11 @@ This needs more work, to handle headings with lots of spaces in them."
(save-excursion
(goto-char (point-min))
(let (tbl)
- (while (re-search-forward org-todo-line-regexp nil t)
- (push (org-make-org-heading-search-string
- (match-string-no-properties 3))
- tbl))
+ (let ((case-fold-search nil))
+ (while (re-search-forward org-todo-line-regexp nil t)
+ (push (org-make-org-heading-search-string
+ (match-string-no-properties 3))
+ tbl)))
(pcomplete-uniqify-list tbl)))
(substring pcomplete-stub 1))))
diff --git a/lisp/org-src.el b/lisp/org-src.el
index bcc93ac..89f3238 100644
--- a/lisp/org-src.el
+++ b/lisp/org-src.el
@@ -765,7 +765,7 @@ white spaces. Match group 2 contains the same string without any
surrounding space. Match group 3 contains the label.
A coderef format regexp can only match at the end of a line."
- (format "\\S-\\([ \t]*\\(%s\\)[ \t]*\\)$"
+ (format "\\([ \t]*\\(%s\\)[ \t]*\\)$"
(replace-regexp-in-string
"%s"
(if label (regexp-quote label) "\\([-a-zA-Z0-9_][-a-zA-Z0-9_ ]*\\)")
diff --git a/lisp/org-table.el b/lisp/org-table.el
index e2bbe87..4bd1c89 100644
--- a/lisp/org-table.el
+++ b/lisp/org-table.el
@@ -563,6 +563,7 @@ SIZE is a string Columns x Rows like for example \"3x2\"."
;;;###autoload
(defun org-table-convert-region (beg0 end0 &optional separator)
"Convert region to a table.
+
The region goes from BEG0 to END0, but these borders will be moved
slightly, to make sure a beginning of line in the first line is included.
@@ -572,7 +573,7 @@ following values:
(4) Use the comma as a field separator
(16) Use a TAB as field separator
(64) Prompt for a regular expression as field separator
-integer When a number, use that many spaces as field separator
+integer When a number, use that many spaces, or a TAB, as field separator
regexp When a regular expression, use it to match the separator
nil When nil, the command tries to be smart and figure out the
separator in the following way:
diff --git a/lisp/org-version.el b/lisp/org-version.el
index 12b5274..cd5f875 100644
--- a/lisp/org-version.el
+++ b/lisp/org-version.el
@@ -5,13 +5,13 @@
(defun org-release ()
"The release version of Org.
Inserted by installing Org mode or when a release is made."
- (let ((org-release "9.0"))
+ (let ((org-release "9.0.2"))
org-release))
;;;###autoload
(defun org-git-version ()
"The Git version of org-mode.
Inserted by installing Org or when a release is made."
- (let ((org-git-version "9.0-dist"))
+ (let ((org-git-version "9.0.2-dist"))
org-git-version))
;;;###autoload
(defvar org-odt-data-dir "/usr/share/emacs/etc/org"
diff --git a/lisp/org.el b/lisp/org.el
index e2cc3ab..08b3f3a 100644
--- a/lisp/org.el
+++ b/lisp/org.el
@@ -923,6 +923,7 @@ already archived entries."
(defcustom org-startup-folded t
"Non-nil means entering Org mode will switch to OVERVIEW.
+
This can also be configured on a per-file basis by adding one of
the following lines anywhere in the buffer:
@@ -931,9 +932,9 @@ the following lines anywhere in the buffer:
#+STARTUP: content
#+STARTUP: showeverything
-By default, this option is ignored when Org opens agenda files
-for the first time. If you want the agenda to honor the startup
-option, set `org-agenda-inhibit-startup' to nil."
+Set `org-agenda-inhibit-startup' to a non-nil value if you want
+to ignore this option when Org opens agenda files for the first
+time."
:group 'org-startup
:type '(choice
(const :tag "nofold: show all" nil)
@@ -2083,16 +2084,22 @@ Changing this requires a restart of Emacs to work correctly."
:type 'integer)
(defcustom org-link-search-must-match-exact-headline 'query-to-create
- "Non-nil means internal links in Org files must exactly match a headline.
-When nil, the link search tries to match a phrase with all words
-in the search text."
+ "Non-nil means internal fuzzy links can only match headlines.
+
+When nil, the a fuzzy link may point to a target or a named
+construct in the document. When set to the special value
+`query-to-create', offer to create a new headline when none
+matched.
+
+Spaces and statistics cookies are ignored during heading searches."
:group 'org-link-follow
:version "24.1"
:type '(choice
(const :tag "Use fuzzy text search" nil)
(const :tag "Match only exact headline" t)
(const :tag "Match exact headline or query to create it"
- query-to-create)))
+ query-to-create))
+ :safe #'symbolp)
(defcustom org-link-frame-setup
'((vm . vm-visit-folder-other-frame)
@@ -2244,7 +2251,7 @@ See `org-file-apps'.")
("dvi" . "xdvi %s")
("fig" . "xfig %s")
(t . "open %s"))
- "Default file applications on a MacOS X system.
+ "Default file applications on a macOS system.
The system \"open\" is known as a default, but we use X11 applications
for some files for which the OS does not have a good default.
See `org-file-apps'.")
@@ -2316,7 +2323,7 @@ Possible values for the file identifier are:
will also open html files inside Emacs, unless you add
(\"html\" . default) to the list as well.
`system' The system command to open files, like `open' on Windows
- and Mac OS X, and mailcap under GNU/Linux. This is the command
+ and macOS, and mailcap under GNU/Linux. This is the command
that will be selected if you call `org-open-at-point' with a
double prefix argument (`\\[universal-argument] \
\\[universal-argument] \\[org-open-at-point]').
@@ -3546,7 +3553,7 @@ The value of this variable is an alist. Associations either:
(TAG . SELECT)
(SPECIAL)
-where TAG is a tag as a string, SELECT is a character, used to
+where TAG is a tag as a string, SELECT is character, used to
select that tag through the fast tag selection interface, and
SPECIAL is one of the following keywords: `:startgroup',
`:startgrouptag', `:grouptags', `:engroup', `:endgrouptag' or
@@ -4078,36 +4085,35 @@ All available processes and theirs documents can be found in
(defcustom org-preview-latex-process-alist
'((dvipng
- :programs ("latex" "dvipng" "gs")
+ :programs ("latex" "dvipng")
:description "dvi > png"
- :message "you need to install the programs: latex, dvipng and ghostscript."
+ :message "you need to install the programs: latex and dvipng."
:image-input-type "dvi"
:image-output-type "png"
:image-size-adjust (1.0 . 1.0)
:latex-compiler ("latex -interaction nonstopmode -output-directory %o %f")
- :image-converter ("dvipng -fg %F -bg %B -D %D -T tight -o %b.png %f"))
+ :image-converter ("dvipng -fg %F -bg %B -D %D -T tight -o %O %f"))
(dvisvgm
- :programs ("latex" "dvisvgm" "gs")
+ :programs ("latex" "dvisvgm")
:description "dvi > svg"
- :message "you need to install the programs: latex, dvisvgm and ghostscript."
+ :message "you need to install the programs: latex and dvisvgm."
:use-xcolor t
:image-input-type "dvi"
:image-output-type "svg"
:image-size-adjust (1.7 . 1.5)
:latex-compiler ("latex -interaction nonstopmode -output-directory %o %f")
- :image-converter ("dvisvgm %f -n -b min -c %S -o %b.svg"))
+ :image-converter ("dvisvgm %f -n -b min -c %S -o %O"))
(imagemagick
- :programs ("latex" "convert" "gs")
+ :programs ("latex" "convert")
:description "pdf > png"
- :message
- "you need to install the programs: latex, imagemagick and ghostscript."
+ :message "you need to install the programs: latex and imagemagick."
:use-xcolor t
:image-input-type "pdf"
:image-output-type "png"
:image-size-adjust (1.0 . 1.0)
:latex-compiler ("pdflatex -interaction nonstopmode -output-directory %o %f")
:image-converter
- ("convert -density %D -trim -antialias %f -quality 100 %b.png")))
+ ("convert -density %D -trim -antialias %f -quality 100 %O")))
"Definitions of external processes for LaTeX previewing.
Org mode can use some external commands to generate TeX snippet's images for
previewing or inserting into HTML files, e.g., \"dvipng\". This variable tells
@@ -4150,9 +4156,10 @@ PROPERTIES accepts the following attributes:
Place-holders used by `:image-converter' and `:latex-compiler':
- %f input file name.
- %b base name of input file.
- %o base directory of input file.
+ %f input file name
+ %b base name of input file
+ %o base directory of input file
+ %O absolute output file name
Place-holders only used by `:image-converter':
@@ -4903,29 +4910,43 @@ Otherwise, these types are allowed:
;;; Variables for pre-computed regular expressions, all buffer local
(defvar-local org-todo-regexp nil
- "Matches any of the TODO state keywords.")
+ "Matches any of the TODO state keywords.
+Since TODO keywords are case-sensitive, `case-fold-search' is
+expected to be bound to nil when matching against this regexp.")
+
(defvar-local org-not-done-regexp nil
- "Matches any of the TODO state keywords except the last one.")
+ "Matches any of the TODO state keywords except the last one.
+Since TODO keywords are case-sensitive, `case-fold-search' is
+expected to be bound to nil when matching against this regexp.")
+
(defvar-local org-not-done-heading-regexp nil
- "Matches a TODO headline that is not done.")
+ "Matches a TODO headline that is not done.
+Since TODO keywords are case-sensitive, `case-fold-search' is
+expected to be bound to nil when matching against this regexp.")
+
(defvar-local org-todo-line-regexp nil
- "Matches a headline and puts TODO state into group 2 if present.")
+ "Matches a headline and puts TODO state into group 2 if present.
+Since TODO keywords are case-sensitive, `case-fold-search' is
+expected to be bound to nil when matching against this regexp.")
+
(defvar-local org-complex-heading-regexp nil
"Matches a headline and puts everything into groups:
-group 1: the stars
-group 2: The todo keyword, maybe
+group 1: Stars
+group 2: The TODO keyword, maybe
group 3: Priority cookie
group 4: True headline
group 5: Tags
Since TODO keywords are case-sensitive, `case-fold-search' is
-expected to be bound to nil when matching this regexp.")
+expected to be bound to nil when matching against this regexp.")
+
(defvar-local org-complex-heading-regexp-format nil
"Printf format to make regexp to match an exact headline.
This regexp will match the headline of any node which has the
exact headline text that is put into the format, but may have any
TODO state, priority and tags.")
+
(defvar-local org-todo-line-tags-regexp nil
"Matches a headline and puts TODO state into group 2 if present.
Also put tags into group 4 if tags are present.")
@@ -8197,7 +8218,7 @@ unchecked check box."
(save-excursion
(org-back-to-heading)
(outline-previous-heading)
- (looking-at org-todo-line-regexp))
+ (let ((case-fold-search nil)) (looking-at org-todo-line-regexp)))
(let* ((new-mark-x
(if (or (equal arg '(4))
(not (match-beginning 2))
@@ -8289,12 +8310,12 @@ headings in the region."
"Fix cursor position and indentation after demoting/promoting."
(let ((pos (point)))
(when (save-excursion
- (beginning-of-line 1)
- (looking-at org-todo-line-regexp)
- (or (equal pos (match-end 1)) (equal pos (match-end 2))))
+ (beginning-of-line)
+ (let ((case-fold-search nil)) (looking-at org-todo-line-regexp))
+ (or (eq pos (match-end 1)) (eq pos (match-end 2))))
(cond ((eobp) (insert " "))
((eolp) (insert " "))
- ((equal (char-after) ?\ ) (forward-char 1))))))
+ ((equal (char-after) ?\s) (forward-char 1))))))
(defun org-current-level ()
"Return the level of the current entry, or nil if before the first headline.
@@ -11135,7 +11156,8 @@ of matched result, which is either `dedicated' or `fuzzy'."
(let* ((case-fold-search t)
(origin (point))
(normalized (replace-regexp-in-string "\n[ \t]*" " " s))
- (words (org-split-string s "[ \t\n]+"))
+ (starred (eq (string-to-char normalized) ?*))
+ (words (split-string (if starred (substring s 1) s)))
(s-multi-re (mapconcat #'regexp-quote words "[ \t]+\\(?:\n[ \t]*\\)?"))
(s-single-re (mapconcat #'regexp-quote words "[ \t]+"))
type)
@@ -11177,109 +11199,104 @@ of matched result, which is either `dedicated' or `fuzzy'."
;; Look for a regular expression.
(funcall (if (derived-mode-p 'org-mode) #'org-occur #'org-do-occur)
(match-string 1 s)))
- ;; Fuzzy links.
- (t
- (let ((starred (eq (string-to-char normalized) ?*)))
- (cond
- ;; Look for targets, only if not in a headline search.
- ((and (not starred)
- (let ((target (format "<<%s>>" s-multi-re)))
- (catch :target-match
- (goto-char (point-min))
- (while (re-search-forward target nil t)
- (backward-char)
- (let ((context (org-element-context)))
- (when (eq (org-element-type context) 'target)
- (setq type 'dedicated)
- (goto-char (org-element-property :begin context))
- (throw :target-match t))))
- nil))))
- ;; Look for elements named after S, only if not in a headline
- ;; search.
- ((and (not starred)
- (let ((name (format "^[ \t]*#\\+NAME: +%s[ \t]*$" s-single-re)))
- (catch :name-match
- (goto-char (point-min))
- (while (re-search-forward name nil t)
- (let ((element (org-element-at-point)))
- (when (equal (org-split-string
- (org-element-property :name element)
- "[ \t]+")
- words)
- (setq type 'dedicated)
- (beginning-of-line)
- (throw :name-match t))))
- nil))))
- ;; Regular text search. Prefer headlines in Org mode
- ;; buffers.
- ((and (derived-mode-p 'org-mode)
- (let* ((wspace "[ \t]")
- (wspaceopt (concat wspace "*"))
- (cookie (concat "\\(?:"
- wspaceopt
- "\\[[0-9]*\\(?:%\\|/[0-9]*\\)\\]"
- wspaceopt
- "\\)"))
- (sep (concat "\\(?:\\(?:" wspace "\\|" cookie "\\)+\\)"))
- (re (concat
- org-outline-regexp-bol
- "\\(?:" org-todo-regexp "[ \t]+\\)?"
- "\\(?:\\[#.\\][ \t]+\\)?"
- "\\(?:" org-comment-string "[ \t]+\\)?"
- sep "?"
- (let ((title (mapconcat #'regexp-quote
- words
- sep)))
- (if starred (substring title 1) title))
- sep "?"
- "\\(?:[ \t]+:[[:alnum:]_@#%%:]+:\\)?"
- "[ \t]*$")))
- (goto-char (point-min))
- (re-search-forward re nil t)))
- (goto-char (match-beginning 0))
- (setq type 'dedicated))
- ;; Offer to create non-existent headline depending on
- ;; `org-link-search-must-match-exact-headline'.
- ((and (derived-mode-p 'org-mode)
- (not org-link-search-inhibit-query)
- (eq org-link-search-must-match-exact-headline 'query-to-create)
- (yes-or-no-p "No match - create this as a new heading? "))
- (goto-char (point-max))
- (unless (bolp) (newline))
- (org-insert-heading nil t t)
- (insert s "\n")
- (beginning-of-line 0))
- ;; Only headlines are looked after. No need to process
- ;; further: throw an error.
- ((and (derived-mode-p 'org-mode)
- (or starred org-link-search-must-match-exact-headline))
- (goto-char origin)
- (error "No match for fuzzy expression: %s" normalized))
- ;; Regular text search.
- ((catch :fuzzy-match
- (goto-char (point-min))
- (while (re-search-forward s-multi-re nil t)
- ;; Skip match if it contains AVOID-POS or it is included
- ;; in a link with a description but outside the
- ;; description.
- (unless (or (and avoid-pos
- (<= (match-beginning 0) avoid-pos)
- (> (match-end 0) avoid-pos))
- (and (save-match-data
- (org-in-regexp org-bracket-link-regexp))
- (match-beginning 3)
- (or (> (match-beginning 3) (point))
- (<= (match-end 3) (point)))
- (org-element-lineage
- (save-match-data (org-element-context))
- '(link) t)))
- (goto-char (match-beginning 0))
- (setq type 'fuzzy)
- (throw :fuzzy-match t)))
- nil))
- ;; All failed. Throw an error.
- (t (goto-char origin)
- (error "No match for fuzzy expression: %s" normalized))))))
+ ;; From here, we handle fuzzy links.
+ ;;
+ ;; Look for targets, only if not in a headline search.
+ ((and (not starred)
+ (let ((target (format "<<%s>>" s-multi-re)))
+ (catch :target-match
+ (goto-char (point-min))
+ (while (re-search-forward target nil t)
+ (backward-char)
+ (let ((context (org-element-context)))
+ (when (eq (org-element-type context) 'target)
+ (setq type 'dedicated)
+ (goto-char (org-element-property :begin context))
+ (throw :target-match t))))
+ nil))))
+ ;; Look for elements named after S, only if not in a headline
+ ;; search.
+ ((and (not starred)
+ (let ((name (format "^[ \t]*#\\+NAME: +%s[ \t]*$" s-single-re)))
+ (catch :name-match
+ (goto-char (point-min))
+ (while (re-search-forward name nil t)
+ (let ((element (org-element-at-point)))
+ (when (equal words
+ (split-string
+ (org-element-property :name element)))
+ (setq type 'dedicated)
+ (beginning-of-line)
+ (throw :name-match t))))
+ nil))))
+ ;; Regular text search. Prefer headlines in Org mode buffers.
+ ;; Ignore COMMENT keyword, TODO keywords, priority cookies,
+ ;; statistics cookies and tags.
+ ((and (derived-mode-p 'org-mode)
+ (let ((title-re
+ (format "%s[ \t]*\\(?:%s[ \t]+\\)?.*%s"
+ org-outline-regexp-bol
+ org-comment-string
+ (mapconcat
+ (lambda (w) (format "\\<%s\\>" (regexp-quote w)))
+ words
+ ".+")))
+ (cookie-re "\\[[0-9]*\\(?:%\\|/[0-9]*\\)\\]")
+ (comment-re (format "\\`%s[ \t]+" org-comment-string)))
+ (goto-char (point-min))
+ (catch :found
+ (while (re-search-forward title-re nil t)
+ (when (equal words
+ (split-string
+ (replace-regexp-in-string
+ cookie-re ""
+ (replace-regexp-in-string
+ comment-re "" (org-get-heading t t)))))
+ (throw :found t)))
+ nil)))
+ (beginning-of-line)
+ (setq type 'dedicated))
+ ;; Offer to create non-existent headline depending on
+ ;; `org-link-search-must-match-exact-headline'.
+ ((and (derived-mode-p 'org-mode)
+ (not org-link-search-inhibit-query)
+ (eq org-link-search-must-match-exact-headline 'query-to-create)
+ (yes-or-no-p "No match - create this as a new heading? "))
+ (goto-char (point-max))
+ (unless (bolp) (newline))
+ (org-insert-heading nil t t)
+ (insert s "\n")
+ (beginning-of-line 0))
+ ;; Only headlines are looked after. No need to process
+ ;; further: throw an error.
+ ((and (derived-mode-p 'org-mode)
+ (or starred org-link-search-must-match-exact-headline))
+ (goto-char origin)
+ (error "No match for fuzzy expression: %s" normalized))
+ ;; Regular text search.
+ ((catch :fuzzy-match
+ (goto-char (point-min))
+ (while (re-search-forward s-multi-re nil t)
+ ;; Skip match if it contains AVOID-POS or it is included in
+ ;; a link with a description but outside the description.
+ (unless (or (and avoid-pos
+ (<= (match-beginning 0) avoid-pos)
+ (> (match-end 0) avoid-pos))
+ (and (save-match-data
+ (org-in-regexp org-bracket-link-regexp))
+ (match-beginning 3)
+ (or (> (match-beginning 3) (point))
+ (<= (match-end 3) (point)))
+ (org-element-lineage
+ (save-match-data (org-element-context))
+ '(link) t)))
+ (goto-char (match-beginning 0))
+ (setq type 'fuzzy)
+ (throw :fuzzy-match t)))
+ nil))
+ ;; All failed. Throw an error.
+ (t (goto-char origin)
+ (error "No match for fuzzy expression: %s" normalized)))
;; Disclose surroundings of match, if appropriate.
(when (and (derived-mode-p 'org-mode) (not stealth))
(org-show-context 'link-search))
@@ -12844,7 +12861,8 @@ changes. Such blocking occurs when:
(save-excursion
(org-back-to-heading t)
(let* ((pos (point))
- (parent-pos (and (org-up-heading-safe) (point))))
+ (parent-pos (and (org-up-heading-safe) (point)))
+ (case-fold-search nil))
(unless parent-pos (throw 'dont-block t)) ; no parent
(when (and (org-not-nil (org-entry-get (point) "ORDERED"))
(forward-line 1)
@@ -13225,7 +13243,7 @@ Returns the new TODO keyword, or nil if no state change should occur."
"Return the TODO keyword of the current subtree."
(save-excursion
(org-back-to-heading t)
- (and (looking-at org-todo-line-regexp)
+ (and (let ((case-fold-search nil)) (looking-at org-todo-line-regexp))
(match-end 2)
(match-string 2))))
@@ -13310,77 +13328,81 @@ This function is run automatically after each state change to a DONE state."
org-log-repeat)))
(org-back-to-heading t)
(org-add-planning-info nil nil 'closed)
- (let ((end (save-excursion (outline-next-heading) (point))))
+ (let ((end (save-excursion (outline-next-heading) (point)))
+ (planning-re (regexp-opt
+ (list org-scheduled-string org-deadline-string))))
(while (re-search-forward org-ts-regexp end t)
- (when (save-match-data
- (or (org-at-planning-p)
- (org-at-property-p)
- (eq (org-element-type (save-excursion
- (backward-char)
- (org-element-context)))
- 'timestamp)))
- (let ((type (cond ((match-end 1) org-scheduled-string)
- ((match-end 3) org-deadline-string)
- (t "Plain:")))
- (ts (or (match-string 2) (match-string 4) (match-string 0))))
- (cond
- ((not
- (string-match "\\([.+]\\)?\\(\\+[0-9]+\\)\\([hdwmy]\\)" ts))
- ;; Time-stamps without a repeater are usually skipped.
- ;; However, a SCHEDULED time-stamp without one is
- ;; removed, as it is considered as no longer relevant.
- (when (equal type org-scheduled-string)
- (org-remove-timestamp-with-keyword type)))
- (t
- (let ((n (string-to-number (match-string 2 ts)))
- (what (match-string 3 ts)))
- (when (equal what "w") (setq n (* n 7) what "d"))
- (when (and (equal what "h")
- (not (string-match-p "[0-9]\\{1,2\\}:[0-9]\\{2\\}"
- ts)))
- (user-error
- "Cannot repeat in Repeat in %d hour(s) because no hour \
+ (let* ((ts (match-string 0))
+ (planning? (org-at-planning-p))
+ (type (if (not planning?) "Plain:"
+ (save-excursion
+ (re-search-backward
+ planning-re (line-beginning-position) t)
+ (match-string 0)))))
+ (cond
+ ;; Ignore fake time-stamps (e.g., within comments).
+ ((and (not planning?)
+ (not (org-at-property-p))
+ (not (eq 'timestamp
+ (org-element-type (save-excursion
+ (backward-char)
+ (org-element-context)))))))
+ ;; Time-stamps without a repeater are usually skipped.
+ ;; However, a SCHEDULED time-stamp without one is
+ ;; removed, as it is considered as no longer relevant.
+ ((not (string-match "\\([.+]\\)?\\(\\+[0-9]+\\)\\([hdwmy]\\)" ts))
+ (when (equal type org-scheduled-string)
+ (org-remove-timestamp-with-keyword type)))
+ (t
+ (let ((n (string-to-number (match-string 2 ts)))
+ (what (match-string 3 ts)))
+ (when (equal what "w") (setq n (* n 7) what "d"))
+ (when (and (equal what "h")
+ (not (string-match-p "[0-9]\\{1,2\\}:[0-9]\\{2\\}"
+ ts)))
+ (user-error
+ "Cannot repeat in Repeat in %d hour(s) because no hour \
has been set"
- n))
- ;; Preparation, see if we need to modify the start
- ;; date for the change.
- (when (match-end 1)
- (let ((time (save-match-data (org-time-string-to-time ts))))
- (cond
- ((equal (match-string 1 ts) ".")
- ;; Shift starting date to today
- (org-timestamp-change
- (- (org-today) (time-to-days time))
- 'day))
- ((equal (match-string 1 ts) "+")
- (let ((nshiftmax 10)
- (nshift 0))
- (while (or (= nshift 0)
- (not (time-less-p (current-time) time)))
- (when (= (cl-incf nshift) nshiftmax)
- (or (y-or-n-p
- (format "%d repeater intervals were not \
+ n))
+ ;; Preparation, see if we need to modify the start
+ ;; date for the change.
+ (when (match-end 1)
+ (let ((time (save-match-data (org-time-string-to-time ts))))
+ (cond
+ ((equal (match-string 1 ts) ".")
+ ;; Shift starting date to today
+ (org-timestamp-change
+ (- (org-today) (time-to-days time))
+ 'day))
+ ((equal (match-string 1 ts) "+")
+ (let ((nshiftmax 10)
+ (nshift 0))
+ (while (or (= nshift 0)
+ (not (time-less-p (current-time) time)))
+ (when (= (cl-incf nshift) nshiftmax)
+ (or (y-or-n-p
+ (format "%d repeater intervals were not \
enough to shift date past today. Continue? "
- nshift))
- (user-error "Abort")))
- (org-timestamp-change n (cdr (assoc what whata)))
- (org-at-timestamp-p t)
- (setq ts (match-string 1))
- (setq time
- (save-match-data
- (org-time-string-to-time ts)))))
- (org-timestamp-change (- n) (cdr (assoc what whata)))
- ;; Rematch, so that we have everything in
- ;; place for the real shift.
- (org-at-timestamp-p t)
- (setq ts (match-string 1))
- (string-match "\\([.+]\\)?\\(\\+[0-9]+\\)\\([hdwmy]\\)"
- ts)))))
- (save-excursion
- (org-timestamp-change n (cdr (assoc what whata)) nil t))
- (setq msg
- (concat
- msg type " " org-last-changed-timestamp " ")))))))))
+ nshift))
+ (user-error "Abort")))
+ (org-timestamp-change n (cdr (assoc what whata)))
+ (org-at-timestamp-p t)
+ (setq ts (match-string 1))
+ (setq time
+ (save-match-data
+ (org-time-string-to-time ts)))))
+ (org-timestamp-change (- n) (cdr (assoc what whata)))
+ ;; Rematch, so that we have everything in place
+ ;; for the real shift.
+ (org-at-timestamp-p t)
+ (setq ts (match-string 1))
+ (string-match "\\([.+]\\)?\\(\\+[0-9]+\\)\\([hdwmy]\\)"
+ ts)))))
+ (save-excursion
+ (org-timestamp-change n (cdr (assoc what whata)) nil t))
+ (setq msg
+ (concat
+ msg type " " org-last-changed-timestamp " "))))))))
(setq org-log-post-message msg)
(message "%s" msg))))
@@ -14256,8 +14278,7 @@ ACTION can be `set', `up', `down', or a character."
(replace-match news t t nil 2))
(if remove
(user-error "No priority cookie found in line")
- (let ((case-fold-search nil))
- (looking-at org-todo-line-regexp))
+ (let ((case-fold-search nil)) (looking-at org-todo-line-regexp))
(if (match-end 2)
(progn
(goto-char (match-end 2))
@@ -14505,10 +14526,14 @@ headlines matching this string."
(defun org-match-sparse-tree (&optional todo-only match)
"Create a sparse tree according to tags string MATCH.
-MATCH can contain positive and negative selection of tags, like
-\"+WORK+URGENT-WITHBOSS\".
-If optional argument TODO-ONLY is non-nil, only select lines that are
-also TODO lines."
+
+MATCH is a string with match syntax. It can contain a selection
+of tags (\"+work+urgent-boss\"), properties (\"LEVEL>3\"), and
+TODO keywords (\"TODO=\\\"WAITING\\\"\") or a combination of
+those. See the manual for details.
+
+If optional argument TODO-ONLY is non-nil, only select lines that
+are also TODO tasks."
(interactive "P")
(org-agenda-prepare-buffers (list (current-buffer)))
(let ((org--matcher-tags-todo-only todo-only))
@@ -17778,7 +17803,7 @@ days in order to avoid rounding problems."
(org-define-error 'org-diary-sexp-no-match "Unable to match diary sexp")
-(defun org-time-string-to-absolute (s &optional daynr prefer show-all buffer pos)
+(defun org-time-string-to-absolute (s &optional daynr prefer buffer pos)
"Convert time stamp S to an absolute day number.
If DAYNR in non-nil, and there is a specifier for a cyclic time
@@ -17802,7 +17827,7 @@ signalled."
(match-string 1 s) "" (calendar-gregorian-from-absolute daynr)))
daynr
(signal 'org-diary-sexp-no-match (list s))))
- ((and daynr show-all) (org-closest-date s daynr prefer))
+ (daynr (org-closest-date s daynr prefer))
(t (time-to-days
(condition-case errdata
(apply #'encode-time (org-parse-time-string s))
@@ -18100,7 +18125,7 @@ INACTIVE-OK."
(defun org-at-clock-log-p nil
"Is the cursor on the clock log line?"
(save-excursion
- (move-beginning-of-line 1)
+ (beginning-of-line)
(looking-at org-clock-line-re)))
(defvar org-clock-history) ; defined in org-clock.el
@@ -19361,12 +19386,9 @@ inspection."
(with-current-buffer (find-file-noselect tmp-out-file t)
(goto-char (point-min))
(when (re-search-forward
- (concat
- (regexp-quote
- "<math xmlns=\"http://www.w3.org/1998/Math/MathML\"")
- "[^>]*?>"
- "\\(.\\|\n\\)*"
- "</math>")
+ (format "<math[^>]*?%s[^>]*?>\\(.\\|\n\\)*</math>"
+ (regexp-quote
+ "xmlns=\"http://www.w3.org/1998/Math/MathML\""))
nil t)
(prog1 (match-string 0) (kill-buffer))))))
(cond
@@ -19436,9 +19458,8 @@ inspection."
(defun org--get-display-dpi ()
"Get the DPI of the display.
-
-Assumes that the display has the same pixel width in the
-horizontal and vertical directions."
+The function assumes that the display has the same pixel width in
+the horizontal and vertical directions."
(if (display-graphic-p)
(round (/ (display-pixel-height)
(/ (display-mm-height) 25.4)))
@@ -19481,12 +19502,11 @@ a HTML file."
(texfilebase (make-temp-name
(expand-file-name "orgtex" tmpdir)))
(texfile (concat texfilebase ".tex"))
- (font-height (face-attribute 'default :height nil))
(image-size-adjust (or (plist-get processing-info :image-size-adjust)
'(1.0 . 1.0)))
(scale (* (if buffer (car image-size-adjust) (cdr image-size-adjust))
(or (plist-get options (if buffer :scale :html-scale)) 1.0)))
- (dpi (* scale (floor (if buffer font-height 140.0))))
+ (dpi (* scale (if buffer (org--get-display-dpi) 140.0)))
(fg (or (plist-get options (if buffer :foreground :html-foreground))
"Black"))
(bg (or (plist-get options (if buffer :background :html-background))
@@ -22740,43 +22760,42 @@ If PROCESS is a function, it is called with a single argument:
the SOURCE file.
If it is a list of commands, each of them is called using
-`shell-command'. By default, in each command, %b, %f, %F and %o
-are replaced with, respectively, SOURCE base name, name, full
-name and directory. It is possible, however, to use more
-place-holders by specifying them in optional argument SPEC, as an
-alist following the pattern (CHARACTER . REPLACEMENT-STRING).
+`shell-command'. By default, in each command, %b, %f, %F, %o and
+%O are replaced with, respectively, SOURCE base name, name, full
+name, directory and absolute output file name. It is possible,
+however, to use more place-holders by specifying them in optional
+argument SPEC, as an alist following the pattern
+
+ (CHARACTER . REPLACEMENT-STRING).
When PROCESS is a list of commands, optional argument LOG-BUF can
be set to a buffer or a buffer name. `shell-command' then uses
-it for output.
-
-`default-directory' is set to SOURCE directory during the whole
-process."
- (let* ((source-name (file-name-nondirectory source))
- (base-name (file-name-sans-extension source-name))
+it for output."
+ (let* ((base-name (file-name-base source))
(full-name (file-truename source))
(out-dir (file-name-directory source))
+ (output (expand-file-name (concat base-name "." ext) out-dir))
(time (current-time))
(err-msg (if (stringp err-msg) (concat ". " err-msg) "")))
(save-window-excursion
- (let ((default-directory (file-name-directory full-name)))
- (pcase process
- ((pred functionp) (funcall process (shell-quote-argument source)))
- ((pred consp)
- (let ((log-buf (and log-buf (get-buffer-create log-buf)))
- (spec (append spec
- `((?b . ,(shell-quote-argument base-name))
- (?f . ,(shell-quote-argument source-name))
- (?F . ,(shell-quote-argument full-name))
- (?o . ,(shell-quote-argument out-dir))))))
- (dolist (command process)
- (shell-command (format-spec command spec) log-buf))))
- (_ (error "No valid command to process %S%s" source err-msg)))))
- ;; Check for process failure.
- (let ((output (concat out-dir base-name "." ext)))
- (unless (org-file-newer-than-p output time)
- (error (format "File %S wasn't produced%s" output err-msg)))
- output)))
+ (pcase process
+ ((pred functionp) (funcall process (shell-quote-argument source)))
+ ((pred consp)
+ (let ((log-buf (and log-buf (get-buffer-create log-buf)))
+ (spec (append spec
+ `((?b . ,(shell-quote-argument base-name))
+ (?f . ,(shell-quote-argument source))
+ (?F . ,(shell-quote-argument full-name))
+ (?o . ,(shell-quote-argument out-dir))
+ (?O . ,(shell-quote-argument output))))))
+ (dolist (command process)
+ (shell-command (format-spec command spec) log-buf))))
+ (_ (error "No valid command to process %S%s" source err-msg))))
+ ;; Check for process failure. Output file is expected to be
+ ;; located in the same directory as SOURCE.
+ (unless (org-file-newer-than-p output time)
+ (error (format "File %S wasn't produced%s" output err-msg)))
+ output))
;;; Indentation
@@ -24140,13 +24159,13 @@ unless optional argument NO-INHERITANCE is non-nil."
"If point is at the end of an empty headline, return t, else nil.
If the heading only contains a TODO keyword, it is still still considered
empty."
- (and (looking-at "[ \t]*$")
- (when org-todo-line-regexp
+ (let ((case-fold-search nil))
+ (and (looking-at "[ \t]*$")
+ org-todo-line-regexp
(save-excursion
- (beginning-of-line 1)
- (let ((case-fold-search nil))
- (looking-at org-todo-line-regexp)
- (string= (match-string 3) ""))))))
+ (beginning-of-line)
+ (looking-at org-todo-line-regexp)
+ (string= (match-string 3) "")))))
(defun org-at-heading-or-item-p ()
(or (org-at-heading-p) (org-at-item-p)))
@@ -24669,7 +24688,8 @@ Move to the previous element at the same level, when possible."
"Move backward element at point."
(interactive)
(if (org-with-limited-levels (org-at-heading-p)) (org-move-subtree-up)
- (let* ((elem (org-element-at-point))
+ (let* ((elem (or (org-element-at-point)
+ (user-error "No element at point")))
(prev-elem
(save-excursion
(goto-char (org-element-property :begin elem))
@@ -24695,7 +24715,8 @@ Move to the previous element at the same level, when possible."
"Move forward element at point."
(interactive)
(let* ((pos (point))
- (elem (org-element-at-point)))
+ (elem (or (org-element-at-point)
+ (user-error "No element at point"))))
(when (= (point-max) (org-element-property :end elem))
(user-error "Cannot drag element forward"))
(goto-char (org-element-property :end elem))
diff --git a/lisp/ox-beamer.el b/lisp/ox-beamer.el
index c254c0b..d566516 100644
--- a/lisp/ox-beamer.el
+++ b/lisp/ox-beamer.el
@@ -720,46 +720,16 @@ channel."
"Transcode a LINK object into Beamer code.
CONTENTS is the description part of the link. INFO is a plist
used as a communication channel."
- (let ((type (org-element-property :type link)))
- (cond
- ;; Link type is handled by a special function.
- ((org-export-custom-protocol-maybe link contents 'beamer))
- ;; Use \hyperlink command for all internal links.
- ((equal type "radio")
- (let ((destination (org-export-resolve-radio-link link info)))
- (if (not destination) contents
- (format "\\hyperlink%s{%s}{%s}"
- (or (org-beamer--element-has-overlay-p link) "")
- (org-export-get-reference destination info)
- contents))))
- ((and (member type '("custom-id" "fuzzy" "id"))
- (let ((destination (if (string= type "fuzzy")
- (org-export-resolve-fuzzy-link link info)
- (org-export-resolve-id-link link info))))
- (cl-case (org-element-type destination)
- (headline
- (let ((label
- (format "sec-%s"
- (mapconcat
- 'number-to-string
- (org-export-get-headline-number
- destination info)
- "-"))))
- (if (and (plist-get info :section-numbers) (not contents))
- (format "\\ref{%s}" label)
- (format "\\hyperlink%s{%s}{%s}"
- (or (org-beamer--element-has-overlay-p link) "")
- label
- contents))))
- (target
- (let ((ref (org-export-get-reference destination info)))
- (if (not contents) (format "\\ref{%s}" ref)
- (format "\\hyperlink%s{%s}{%s}"
- (or (org-beamer--element-has-overlay-p link) "")
- ref
- contents))))))))
- ;; Otherwise, use `latex' back-end.
- (t (org-export-with-backend 'latex link contents info)))))
+ (or (org-export-custom-protocol-maybe link contents 'beamer)
+ ;; Fall-back to LaTeX export. However, prefer "\hyperlink" over
+ ;; "\hyperref" since the former handles overlay specifications.
+ (let ((latex-link (org-export-with-backend 'latex link contents info)))
+ (if (string-match "\\`\\\\hyperref\\[\\(.*?\\)\\]" latex-link)
+ (replace-match
+ (format "\\\\hyperlink%s{\\1}"
+ (or (org-beamer--element-has-overlay-p link) ""))
+ nil nil latex-link)
+ latex-link))))
;;;; Plain List
diff --git a/lisp/ox-html.el b/lisp/ox-html.el
index 404b62f..63a8c84 100644
--- a/lisp/ox-html.el
+++ b/lisp/ox-html.el
@@ -1875,25 +1875,24 @@ INFO is a plist used as a communication channel."
(setq template (replace-match val t t template))))))))
(defun org-html-format-spec (info)
- "Return format specification for elements that can be
-used in the preamble or postamble."
- `((?t . ,(org-export-data (plist-get info :title) info))
- (?s . ,(org-export-data (plist-get info :subtitle) info))
- (?d . ,(org-export-data (org-export-get-date info) info))
- (?T . ,(format-time-string
- (plist-get info :html-metadata-timestamp-format)))
- (?a . ,(org-export-data (plist-get info :author) info))
- (?e . ,(mapconcat
- (lambda (e)
- (format "<a href=\"mailto:%s\">%s</a>" e e))
- (split-string (plist-get info :email) ",+ *")
- ", "))
- (?c . ,(plist-get info :creator))
- (?C . ,(let ((file (plist-get info :input-file)))
- (format-time-string
- (plist-get info :html-metadata-timestamp-format)
- (when file (nth 5 (file-attributes file))))))
- (?v . ,(or (plist-get info :html-validation-link) ""))))
+ "Return format specification for preamble and postamble.
+INFO is a plist used as a communication channel."
+ (let ((timestamp-format (plist-get info :html-metadata-timestamp-format)))
+ `((?t . ,(org-export-data (plist-get info :title) info))
+ (?s . ,(org-export-data (plist-get info :subtitle) info))
+ (?d . ,(org-export-data (org-export-get-date info timestamp-format)
+ info))
+ (?T . ,(format-time-string timestamp-format))
+ (?a . ,(org-export-data (plist-get info :author) info))
+ (?e . ,(mapconcat
+ (lambda (e) (format "<a href=\"mailto:%s\">%s</a>" e e))
+ (split-string (plist-get info :email) ",+ *")
+ ", "))
+ (?c . ,(plist-get info :creator))
+ (?C . ,(let ((file (plist-get info :input-file)))
+ (format-time-string timestamp-format
+ (and file (nth 5 (file-attributes file))))))
+ (?v . ,(or (plist-get info :html-validation-link) "")))))
(defun org-html--build-pre/postamble (type info)
"Return document preamble or postamble as a string, or nil.
diff --git a/lisp/ox-icalendar.el b/lisp/ox-icalendar.el
index c22866a..8c9fba6 100644
--- a/lisp/ox-icalendar.el
+++ b/lisp/ox-icalendar.el
@@ -458,7 +458,7 @@ or subject for the event."
(mapconcat
(lambda (line)
;; Limit each line to a maximum of 75 characters. If it is
- ;; longer, fold it by using "\n " as a continuation marker.
+ ;; longer, fold it by using "\r\n " as a continuation marker.
(let ((len (length line)))
(if (<= len 75) line
(let ((folded-line (substring line 0 75))
@@ -468,11 +468,11 @@ or subject for the event."
;; line, real contents must be split at 74 chars.
(while (< (setq chunk-end (+ chunk-start 74)) len)
(setq folded-line
- (concat folded-line "\n "
+ (concat folded-line "\r\n "
(substring line chunk-start chunk-end))
chunk-start chunk-end))
- (concat folded-line "\n " (substring line chunk-start))))))
- (org-split-string s "\n") "\n")))
+ (concat folded-line "\r\n " (substring line chunk-start))))))
+ (org-split-string s "\n") "\r\n")))
diff --git a/lisp/ox-latex.el b/lisp/ox-latex.el
index 57ec1d2..0b51f15 100644
--- a/lisp/ox-latex.el
+++ b/lisp/ox-latex.el
@@ -1021,7 +1021,7 @@ be a list containing two strings: the name of the option, and the
value. For example,
(setq org-latex-minted-options
- '((\"bgcolor\" \"bg\") (\"frame\" \"lines\")))
+ \\='((\"bgcolor\" \"bg\") (\"frame\" \"lines\")))
will result in src blocks being exported with
@@ -1060,7 +1060,7 @@ exported. This format string may contain these elements:
For example,
(setq org-latex-custom-lang-environments
- '((python \"pythoncode\")
+ \\='((python \"pythoncode\")
(ocaml \"\\\\begin{listing}
\\\\begin{minted}[%o]{ocaml}
%s\\\\end{minted}
@@ -1145,12 +1145,15 @@ A better approach is to use a compiler suit such as `latexmk'."
"%latex -interaction nonstopmode -output-directory %o %f"
"%latex -interaction nonstopmode -output-directory %o %f")
"Commands to process a LaTeX file to a PDF file.
+
This is a list of strings, each of them will be given to the
shell as a command. %f in the command will be replaced by the
-full file name, %b by the file base name (i.e. without directory
-and extension parts), %o by the base directory of the file,
-%latex is the LaTeX compiler (see `org-latex-compiler'), and %bib
-is the BibTeX-like compiler (see `org-latex-bib-compiler').
+relative file name, %F by the absolute file name, %b by the file
+base name (i.e. without directory and extension parts), %o by the
+base directory of the file, %O by the absolute file name of the
+output file, %latex is the LaTeX compiler (see
+`org-latex-compiler'), and %bib is the BibTeX-like compiler (see
+`org-latex-bib-compiler').
The reason why this is a list is that it usually takes several
runs of `pdflatex', maybe mixed with a call to `bibtex'. Org
@@ -1182,9 +1185,9 @@ file name as its single argument."
"%latex -interaction nonstopmode -output-directory %o %f"
"%latex -interaction nonstopmode -output-directory %o %f"))
(const :tag "texi2dvi"
- ("LATEX=\"%latex\" texi2dvi -p -b -V %f"))
+ ("cd %o; LATEX=\"%latex\" texi2dvi -p -b -V %b.tex"))
(const :tag "latexmk"
- ("latexmk -g -pdflatex=\"%latex\" %f"))
+ ("latexmk -g -pdf -pdflatex=\"%latex\" -outdir=%o %f"))
(function)))
(defcustom org-latex-logfiles-extensions
@@ -1483,15 +1486,7 @@ should not be used for floats. See
(defun org-latex--protect-text (text)
"Protect special characters in string TEXT and return it."
- (replace-regexp-in-string
- "--\\|[\\{}$%&_#~^]"
- (lambda (m)
- (cond ((equal m "--") "-{}-")
- ((equal m "\\") "\\textbackslash{}")
- ((equal m "~") "\\textasciitilde{}")
- ((equal m "^") "\\textasciicircum{}")
- (t (concat "\\" m))))
- text nil t))
+ (replace-regexp-in-string "[\\{}$%&_#~^]" "\\\\\\&" text))
(defun org-latex--text-markup (text markup info)
"Format TEXT depending on MARKUP text markup.
@@ -1505,13 +1500,23 @@ INFO is a plist used as a communication channel. See
;; and use "\\verb" command.
(verb
(let ((separator (org-latex--find-verb-separator text)))
- (concat "\\verb" separator
+ (concat "\\verb"
+ separator
(replace-regexp-in-string "\n" " " text)
separator)))
;; Handle the `protectedtexttt' special case: Protect some
;; special chars and use "\texttt{%s}" format string.
(protectedtexttt
- (format "\\texttt{%s}" (org-latex--protect-text text)))
+ (format "\\texttt{%s}"
+ (replace-regexp-in-string
+ "--\\|[\\{}$%&_#~^]"
+ (lambda (m)
+ (cond ((equal m "--") "-{}-")
+ ((equal m "\\") "\\textbackslash{}")
+ ((equal m "~") "\\textasciitilde{}")
+ ((equal m "^") "\\textasciicircum{}")
+ (t (org-latex--protect-text m))))
+ text nil t)))
;; Else use format string.
(t (format fmt text)))))
@@ -2040,7 +2045,7 @@ contextual information."
(separator (org-latex--find-verb-separator code)))
(cl-case (plist-get info :latex-listings)
;; Do not use a special package: transcode it verbatim.
- ((nil) (format "\\texttt{%s}" (org-latex--protect-text code)))
+ ((nil) (format "\\texttt{%s}" (org-latex--text-markup code 'code info)))
;; Use minted package.
(minted
(let* ((org-lang (org-element-property :language inline-src-block))
@@ -2416,17 +2421,16 @@ DESC is the description part of the link, or the empty string.
INFO is a plist holding contextual information. See
`org-export-data'."
(let* ((type (org-element-property :type link))
- (raw-path (replace-regexp-in-string
- "%" "\\%" (org-element-property :path link) nil t))
+ (raw-path (org-element-property :path link))
;; Ensure DESC really exists, or set it to nil.
(desc (and (not (string= desc "")) desc))
(imagep (org-export-inline-image-p
link (plist-get info :latex-inline-image-rules)))
- (path (cond
- ((member type '("http" "https" "ftp" "mailto" "doi"))
- (concat type ":" raw-path))
- ((string= type "file") (org-export-file-uri raw-path))
- (t raw-path))))
+ (path (org-latex--protect-text
+ (cond ((member type '("http" "https" "ftp" "mailto" "doi"))
+ (concat type ":" raw-path))
+ ((string= type "file") (org-export-file-uri raw-path))
+ (t raw-path)))))
(cond
;; Link type is handled by a special function.
((org-export-custom-protocol-maybe link desc 'latex))
@@ -2695,22 +2699,24 @@ channel."
DATA is a parse tree or a secondary string. INFO is a plist
containing export options. Modify DATA by side-effect and return it."
(let ((valid-object-p
- ;; Non-nil when OBJ can be added to the latex math block.
- (lambda (obj)
+ ;; Non-nil when OBJ can be added to the latex math block B.
+ (lambda (obj b)
(pcase (org-element-type obj)
(`entity (org-element-property :latex-math-p obj))
(`latex-fragment
(let ((value (org-element-property :value obj)))
(or (string-prefix-p "\\(" value)
(string-match-p "\\`\\$[^$]" value))))
- ((or `subscript `superscript) t)))))
+ ((and type (or `subscript `superscript))
+ (not (memq type (mapcar #'org-element-type
+ (org-element-contents b)))))))))
(org-element-map data '(entity latex-fragment subscript superscript)
(lambda (object)
;; Skip objects already wrapped.
(when (and (not (eq (org-element-type
(org-element-property :parent object))
'latex-math-block))
- (funcall valid-object-p object))
+ (funcall valid-object-p object nil))
(let ((math-block (list 'latex-math-block nil))
(next-elements (org-export-get-next-element object info t))
(last object))
@@ -2722,16 +2728,17 @@ containing export options. Modify DATA by side-effect and return it."
;; MATH-BLOCK swallows consecutive math objects.
(catch 'exit
(dolist (next next-elements)
- (if (not (funcall valid-object-p next)) (throw 'exit nil)
- (org-element-extract-element next)
- (org-element-adopt-elements math-block next)
- ;; Eschew the case: \beta$x$ -> \(\betax\).
- (unless (memq (org-element-type next)
- '(subscript superscript))
- (org-element-put-property last :post-blank 1))
- (setq last next)
- (when (> (or (org-element-property :post-blank next) 0) 0)
- (throw 'exit nil))))))
+ (unless (funcall valid-object-p next math-block)
+ (throw 'exit nil))
+ (org-element-extract-element next)
+ (org-element-adopt-elements math-block next)
+ ;; Eschew the case: \beta$x$ -> \(\betax\).
+ (unless (memq (org-element-type next)
+ '(subscript superscript))
+ (org-element-put-property last :post-blank 1))
+ (setq last next)
+ (when (> (or (org-element-property :post-blank next) 0) 0)
+ (throw 'exit nil)))))
(org-element-put-property
math-block :post-blank (org-element-property :post-blank last)))))
info nil '(subscript superscript latex-math-block) t)
@@ -3287,8 +3294,10 @@ This function assumes TABLE has `org' as its `:type' property and
(plist-get attr :math-prefix)
;; Environment. Also treat special cases.
(cond ((member env '("array" "tabular"))
- (let ((align (make-string
- (cdr (org-export-table-dimensions table info)) ?c)))
+ ;; Make sure cells are always centered while preserving
+ ;; vertical separators.
+ (let ((align (replace-regexp-in-string
+ "[lr]" "c" (org-latex--align-string table info))))
(format "\\begin{%s}{%s}\n%s\\end{%s}" env align contents env)))
((assoc env org-latex-table-matrix-macros)
(format "\\%s%s{\n%s}"
@@ -3610,10 +3619,12 @@ produced."
(when org-latex-remove-logfiles
(mapc #'delete-file
(directory-files
- (file-name-directory texfile) t
+ (file-name-directory outfile)
+ t
(concat (regexp-quote (file-name-base outfile))
"\\(?:\\.[0-9]+\\)?\\."
- (regexp-opt org-latex-logfiles-extensions)))))
+ (regexp-opt org-latex-logfiles-extensions))
+ t)))
(let ((warnings (org-latex--collect-warnings log-buf)))
(message (concat "PDF file produced"
(cond
diff --git a/lisp/ox-man.el b/lisp/ox-man.el
index 4e2bfc7..324d5a7 100644
--- a/lisp/ox-man.el
+++ b/lisp/ox-man.el
@@ -208,11 +208,13 @@ in this list - but it does not hurt if it is present."
"tbl %f | eqn | groff -man | ps2pdf - > %b.pdf")
"Commands to process a Man file to a PDF file.
+
This is a list of strings, each of them will be given to the
shell as a command. %f in the command will be replaced by the
-full file name, %b by the file base name (i.e. without directory
-and extension parts) and %o by the base directory of the file.
-
+relative file name, %F by the absolute file name, %b by the file
+base name (i.e. without directory and extension parts), %o by the
+base directory of the file and %O by the absolute file name of
+the output file.
By default, Org uses 3 runs of to do the processing.
diff --git a/lisp/ox-odt.el b/lisp/ox-odt.el
index 05d86bf..2465836 100644
--- a/lisp/ox-odt.el
+++ b/lisp/ox-odt.el
@@ -847,7 +847,7 @@ ON-OR-OFF := t | nil
For example, with the following configuration
\(setq org-odt-table-styles
- '((\"TableWithHeaderRowsAndColumns\" \"Custom\"
+ \\='((\"TableWithHeaderRowsAndColumns\" \"Custom\"
((use-first-row-styles . t)
(use-first-column-styles . t)))
(\"TableWithHeaderColumns\" \"Custom\"
@@ -3741,9 +3741,9 @@ contextual information."
(org-link
(let ((link (with-temp-buffer
(insert latex-frag)
- (org-format-latex cache-subdir cache-dir
- nil display-msg
- nil processing-type)
+ (org-format-latex cache-subdir nil nil cache-dir
+ nil display-msg nil
+ processing-type)
(buffer-substring-no-properties
(point-min) (point-max)))))
(if (string-match-p "file:\\([^]]*\\)" link) link
diff --git a/lisp/ox-publish.el b/lisp/ox-publish.el
index 102f460..e8271f6 100644
--- a/lisp/ox-publish.el
+++ b/lisp/ox-publish.el
@@ -1199,39 +1199,38 @@ the file including them will be republished as well."
(unless org-publish-cache
(error
"`org-publish-cache-file-needs-publishing' called, but no cache present"))
- (let* ((case-fold-search t)
- (key (org-publish-timestamp-filename filename pub-dir pub-func))
+ (let* ((key (org-publish-timestamp-filename filename pub-dir pub-func))
(pstamp (org-publish-cache-get key))
(org-inhibit-startup t)
- (visiting (find-buffer-visiting filename))
- (buf (find-file-noselect (expand-file-name filename)))
included-files-ctime)
(when (equal (file-name-extension filename) "org")
- (unwind-protect
- (with-current-buffer buf
- (goto-char (point-min))
- (while (re-search-forward "^[ \t]*#\\+INCLUDE:" nil t)
- (let* ((element (org-element-at-point))
- (included-file
- (and (eq (org-element-type element) 'keyword)
- (let ((value (org-element-property :value element)))
- (and value
- (string-match
- "\\`\\(\".+?\"\\|\\S-+\\)\\(?:\\s-+\\|$\\)"
- value)
- (let ((m (match-string 1 value)))
- (org-unbracket-string
- "\"" "\""
- ;; Ignore search suffix.
- (if (string-match "\\(::\\(.*?\\)\\)\"?\\'"
- m)
- (substring m 0 (match-beginning 0))
- m))))))))
- (when included-file
- (push (org-publish-cache-ctime-of-src
- (expand-file-name included-file))
- included-files-ctime)))))
- (unless visiting (kill-buffer buf))))
+ (let ((visiting (find-buffer-visiting filename))
+ (buf (find-file-noselect filename))
+ (case-fold-search t))
+ (unwind-protect
+ (with-current-buffer buf
+ (goto-char (point-min))
+ (while (re-search-forward "^[ \t]*#\\+INCLUDE:" nil t)
+ (let* ((element (org-element-at-point))
+ (included-file
+ (and (eq (org-element-type element) 'keyword)
+ (let ((value (org-element-property :value element)))
+ (and value
+ (string-match
+ "\\`\\(\".+?\"\\|\\S-+\\)\\(?:\\s-+\\|$\\)"
+ value)
+ (let ((m (match-string 1 value)))
+ (org-unbracket-string
+ "\"" "\""
+ ;; Ignore search suffix.
+ (if (string-match "::.*?\"?\\'" m)
+ (substring m 0 (match-beginning 0))
+ m))))))))
+ (when included-file
+ (push (org-publish-cache-ctime-of-src
+ (expand-file-name included-file))
+ included-files-ctime)))))
+ (unless visiting (kill-buffer buf)))))
(or (null pstamp)
(let ((ctime (org-publish-cache-ctime-of-src filename)))
(or (< pstamp ctime)
@@ -1252,9 +1251,9 @@ will be created. Return VALUE."
(defun org-publish-cache-get-file-property
(filename property &optional default no-create project-name)
"Return the value for a PROPERTY of file FILENAME in publishing cache.
-Use cache file of PROJECT-NAME. Return the value of that
-PROPERTY or DEFAULT, if the value does not yet exist. If the
-entry will be created, unless NO-CREATE is not nil."
+Use cache file of PROJECT-NAME. Return the value of that PROPERTY,
+or DEFAULT, if the value does not yet exist. Create the entry,
+if necessary, unless NO-CREATE is non-nil."
;; Evtl. load the requested cache file:
(if project-name (org-publish-initialize-cache project-name))
(let ((pl (org-publish-cache-get filename)) retval)
@@ -1270,15 +1269,16 @@ entry will be created, unless NO-CREATE is not nil."
(defun org-publish-cache-get (key)
"Return the value stored in `org-publish-cache' for key KEY.
-Returns nil, if no value or nil is found, or the cache does not
-exist."
+Return nil, if no value or nil is found. Raise an error if the
+cache does not exist."
(unless org-publish-cache
(error "`org-publish-cache-get' called, but no cache present"))
(gethash key org-publish-cache))
(defun org-publish-cache-set (key value)
"Store KEY VALUE pair in `org-publish-cache'.
-Returns value on success, else nil."
+Returns value on success, else nil. Raise an error if the cache
+does not exist."
(unless org-publish-cache
(error "`org-publish-cache-set' called, but no cache present"))
(puthash key value org-publish-cache))
diff --git a/lisp/ox-texinfo.el b/lisp/ox-texinfo.el
index cf9cc2f..ab61b6b 100644
--- a/lisp/ox-texinfo.el
+++ b/lisp/ox-texinfo.el
@@ -346,10 +346,13 @@ The function should return the string to be exported."
(defcustom org-texinfo-info-process '("makeinfo %f")
"Commands to process a Texinfo file to an INFO file.
-This is list of strings, each of them will be given to the shell
-as a command. %f in the command will be replaced by the full
-file name, %b by the file base name (i.e without extension) and
-%o by the base directory of the file."
+
+This is a list of strings, each of them will be given to the
+shell as a command. %f in the command will be replaced by the
+relative file name, %F by the absolute file name, %b by the file
+base name (i.e. without directory and extension parts), %o by the
+base directory of the file and %O by the absolute file name of
+the output file."
:group 'org-export-texinfo
:type '(repeat :tag "Shell command sequence"
(string :tag "Shell command")))
diff --git a/lisp/ox.el b/lisp/ox.el
index d3d1a0e..5c72fb5 100644
--- a/lisp/ox.el
+++ b/lisp/ox.el
@@ -2007,18 +2007,24 @@ channel.
Unlike to `org-export-with-backend', this function will
recursively convert DATA using BACKEND translation table."
(when (symbolp backend) (setq backend (org-export-get-backend backend)))
- (org-export-data
- data
- ;; Set-up a new communication channel with translations defined in
- ;; BACKEND as the translate table and a new hash table for
- ;; memoization.
- (org-combine-plists
- info
- (list :back-end backend
- :translate-alist (org-export-get-all-transcoders backend)
- ;; Size of the hash table is reduced since this function
- ;; will probably be used on small trees.
- :exported-data (make-hash-table :test 'eq :size 401)))))
+ ;; Set-up a new communication channel with translations defined in
+ ;; BACKEND as the translate table and a new hash table for
+ ;; memoization.
+ (let ((new-info
+ (org-combine-plists
+ info
+ (list :back-end backend
+ :translate-alist (org-export-get-all-transcoders backend)
+ ;; Size of the hash table is reduced since this
+ ;; function will probably be used on small trees.
+ :exported-data (make-hash-table :test 'eq :size 401)))))
+ (prog1 (org-export-data data new-info)
+ ;; Preserve `:internal-references', as those do not depend on
+ ;; the back-end used; we need to make sure that any new
+ ;; reference when the temporary back-end was active gets through
+ ;; the default one.
+ (plist-put info :internal-references
+ (plist-get new-info :internal-references)))))
(defun org-export-expand (blob contents &optional with-affiliated)
"Expand a parsed element or object to its original state.
@@ -2472,20 +2478,24 @@ channel, as a plist. It must return a string or nil.")
(defun org-export-filter-apply-functions (filters value info)
"Call every function in FILTERS.
-Functions are called with arguments VALUE, current export
-back-end's name and INFO. A function returning a nil value will
-be skipped. If it returns the empty string, the process ends and
-VALUE is ignored.
+Functions are called with three arguments: a value, the export
+back-end name and the communication channel. First function in
+FILTERS is called with VALUE as its first argument. Second
+function in FILTERS is called with the previous result as its
+value, etc.
+
+Functions returning nil are skipped. Any function returning the
+empty string ends the process, which returns the empty string.
Call is done in a LIFO fashion, to be sure that developer
specified filters, if any, are called first."
- (catch 'exit
+ (catch :exit
(let* ((backend (plist-get info :back-end))
(backend-name (and backend (org-export-backend-name backend))))
(dolist (filter filters value)
(let ((result (funcall filter value backend-name info)))
- (cond ((not result) value)
- ((equal value "") (throw 'exit nil))
+ (cond ((not result))
+ ((equal result "") (throw :exit ""))
(t (setq value result))))))))
(defun org-export-install-filters (info)
@@ -3003,14 +3013,14 @@ Return code as a string."
(save-excursion
(save-restriction
;; Narrow buffer to an appropriate region or subtree for
- ;; parsing. If parsing subtree, be sure to remove main headline
- ;; too.
+ ;; parsing. If parsing subtree, be sure to remove main
+ ;; headline, planning data and property drawer.
(cond ((org-region-active-p)
(narrow-to-region (region-beginning) (region-end)))
(subtreep
(org-narrow-to-subtree)
(goto-char (point-min))
- (forward-line)
+ (org-end-of-meta-data)
(narrow-to-region (point) (point-max))))
;; Initialize communication channel with original buffer
;; attributes, unavailable in its copy.
@@ -3672,18 +3682,20 @@ the communication channel used for export, as a plist."
(when (symbolp backend) (setq backend (org-export-get-backend backend)))
(org-export-barf-if-invalid-backend backend)
(let ((type (org-element-type data)))
- (if (memq type '(nil org-data)) (error "No foreign transcoder available")
- (let* ((all-transcoders (org-export-get-all-transcoders backend))
- (transcoder (cdr (assq type all-transcoders))))
- (if (not (functionp transcoder))
- (error "No foreign transcoder available")
- (funcall
- transcoder data contents
- (org-combine-plists
- info (list
- :back-end backend
- :translate-alist all-transcoders
- :exported-data (make-hash-table :test #'eq :size 401)))))))))
+ (when (memq type '(nil org-data)) (error "No foreign transcoder available"))
+ (let* ((all-transcoders (org-export-get-all-transcoders backend))
+ (transcoder (cdr (assq type all-transcoders))))
+ (unless (functionp transcoder) (error "No foreign transcoder available"))
+ (let ((new-info
+ (org-combine-plists
+ info (list
+ :back-end backend
+ :translate-alist all-transcoders
+ :exported-data (make-hash-table :test #'eq :size 401)))))
+ ;; `:internal-references' are shared across back-ends.
+ (prog1 (funcall transcoder data contents new-info)
+ (plist-put info :internal-references
+ (plist-get new-info :internal-references)))))))
;;;; For Export Snippets
@@ -4167,18 +4179,15 @@ error if no block contains REF."
(lambda (el)
(with-temp-buffer
(insert (org-trim (org-element-property :value el)))
- (let* ((label-fmt (regexp-quote
- (or (org-element-property :label-fmt el)
- org-coderef-label-format)))
- (ref-re
- (format "^.*?\\S-.*?\\([ \t]*\\(%s\\)\\)[ \t]*$"
- (format label-fmt ref))))
+ (let* ((label-fmt (or (org-element-property :label-fmt el)
+ org-coderef-label-format))
+ (ref-re (org-src-coderef-regexp label-fmt ref)))
;; Element containing REF is found. Resolve it to
;; either a label or a line number, as needed.
(when (re-search-backward ref-re nil t)
- (cond
- ((org-element-property :use-labels el) ref)
- (t (+ (or (org-export-get-loc el info) 0) (line-number-at-pos))))))))
+ (if (org-element-property :use-labels el) ref
+ (+ (or (org-export-get-loc el info) 0)
+ (line-number-at-pos)))))))
info 'first-match)
(signal 'org-link-broken (list ref))))
@@ -4385,19 +4394,35 @@ reference consists of alphanumeric characters only."
(or (car (rassq datum cache))
(let* ((crossrefs (plist-get info :crossrefs))
(cells (org-export-search-cells datum))
- ;; If any other published document relies on an
- ;; association between a search cell and a reference,
- ;; make sure to preserve it. See
- ;; `org-publish-resolve-external-link' for details.
- (new (or (cdr (cl-some (lambda (c) (assoc c crossrefs)) cells))
+ ;; Preserve any pre-existing association between
+ ;; a search cell and a reference, i.e., when some
+ ;; previously published document referenced a location
+ ;; within current file (see
+ ;; `org-publish-resolve-external-link').
+ ;;
+ ;; However, there is no guarantee that search cells are
+ ;; unique, e.g., there might be duplicate custom ID or
+ ;; two headings with the same title in the file.
+ ;;
+ ;; As a consequence, before re-using any reference to
+ ;; an element or object, we check that it doesn't refer
+ ;; to a previous element or object.
+ (new (or (cl-some
+ (lambda (cell)
+ (let ((stored (cdr (assoc cell crossrefs))))
+ (when stored
+ (let ((old (org-export-format-reference stored)))
+ (and (not (assoc old cache)) stored)))))
+ cells)
(org-export-new-reference cache)))
(reference-string (org-export-format-reference new)))
;; Cache contains both data already associated to
;; a reference and in-use internal references, so as to make
;; unique references.
(dolist (cell cells) (push (cons cell new) cache))
- ;; Keep an associated related to DATUM as not every object
- ;; and element can be associated to a search cell.
+ ;; Retain a direct association between reference string and
+ ;; DATUM since (1) not every object or element can be given
+ ;; a search cell (2) it permits quick lookup.
(push (cons reference-string datum) cache)
(plist-put info :internal-references cache)
reference-string))))