summaryrefslogtreecommitdiff
path: root/lisp/org/org.el
diff options
context:
space:
mode:
authorBastien Guerry <bzg@gnu.org>2020-12-13 13:44:15 +0100
committerBastien Guerry <bzg@gnu.org>2020-12-13 13:44:15 +0100
commitf22856a5c54d99867cd24c08a14bbda23d5c6229 (patch)
treeb6bd688963531eccb8b9d18195df0edfc34ba59d /lisp/org/org.el
parent6aa9fe3e1b4052b2acde86404a90e35893ebfa00 (diff)
downloademacs-f22856a5c54d99867cd24c08a14bbda23d5c6229.tar.gz
emacs-f22856a5c54d99867cd24c08a14bbda23d5c6229.tar.bz2
emacs-f22856a5c54d99867cd24c08a14bbda23d5c6229.zip
Update to Org 9.4.1
Diffstat (limited to 'lisp/org/org.el')
-rw-r--r--lisp/org/org.el4570
1 files changed, 2278 insertions, 2292 deletions
diff --git a/lisp/org/org.el b/lisp/org/org.el
index a7502d188e2..3db07cd89b3 100644
--- a/lisp/org/org.el
+++ b/lisp/org/org.el
@@ -4,10 +4,12 @@
;; Copyright (C) 2004-2020 Free Software Foundation, Inc.
;;
;; Author: Carsten Dominik <carsten at orgmode dot org>
+;; Maintainer: Bastien Guerry <bzg@gnu.org>
;; Keywords: outlines, hypermedia, calendar, wp
;; Homepage: https://orgmode.org
-;; Version: 9.3
-;;
+
+;; Version: 9.4.1
+
;; This file is part of GNU Emacs.
;;
;; GNU Emacs is free software: you can redistribute it and/or modify
@@ -121,9 +123,12 @@ Stars are put in group 1 and the trimmed body in group 2.")
(declare-function org-archive-subtree-default "org-archive" ())
(declare-function org-archive-to-archive-sibling "org-archive" ())
(declare-function org-attach "org-attach" ())
+(declare-function org-attach-dir "org-attach"
+ (&optional create-if-not-exists-p no-fs-check))
(declare-function org-babel-do-in-edit-buffer "ob-core" (&rest body) t)
(declare-function org-babel-tangle-file "ob-tangle" (file &optional target-file lang))
(declare-function org-beamer-mode "ox-beamer" (&optional prefix) t)
+(declare-function org-clock-auto-clockout "org-clock" ())
(declare-function org-clock-cancel "org-clock" ())
(declare-function org-clock-display "org-clock" (&optional arg))
(declare-function org-clock-get-last-clock-out-time "org-clock" ())
@@ -141,6 +146,7 @@ Stars are put in group 1 and the trimmed body in group 2.")
(declare-function org-clock-update-time-maybe "org-clock" ())
(declare-function org-clocking-buffer "org-clock" ())
(declare-function org-clocktable-shift "org-clock" (dir n))
+(declare-function org-columns-quit "org-colview" ())
(declare-function org-columns-insert-dblock "org-colview" ())
(declare-function org-duration-from-minutes "org-duration" (minutes &optional fmt canonical))
(declare-function org-element-at-point "org-element" ())
@@ -172,6 +178,7 @@ Stars are put in group 1 and the trimmed body in group 2.")
(declare-function org-inlinetask-outline-regexp "org-inlinetask" ())
(declare-function org-inlinetask-toggle-visibility "org-inlinetask" ())
(declare-function org-latex-make-preamble "ox-latex" (info &optional template snippet?))
+(declare-function org-num-mode "org-num" (&optional arg))
(declare-function org-plot/gnuplot "org-plot" (&optional params))
(declare-function org-tags-view "org-agenda" (&optional todo-only match))
(declare-function org-timer "org-timer" (&optional restart no-insert))
@@ -189,6 +196,7 @@ Stars are put in group 1 and the trimmed body in group 2.")
(defvar org-radio-target-regexp)
(defvar org-target-link-regexp)
(defvar org-target-regexp)
+(defvar org-id-overriding-file-name)
;; load languages based on value of `org-babel-load-languages'
(defvar org-babel-load-languages)
@@ -215,15 +223,17 @@ and then loads the resulting file using `load-file'. With
optional prefix argument COMPILE, the tangled Emacs Lisp file is
byte-compiled before it is loaded."
(interactive "fFile to load: \nP")
- (let* ((tangled-file (concat (file-name-sans-extension file) ".el")))
+ (let ((tangled-file (concat (file-name-sans-extension file) ".el")))
;; Tangle only if the Org file is newer than the Elisp file.
(unless (org-file-newer-than-p
tangled-file
- (file-attribute-modification-time (file-attributes file)))
- (org-babel-tangle-file file tangled-file "emacs-lisp"))
+ (file-attribute-modification-time
+ (file-attributes (file-truename file))))
+ (org-babel-tangle-file file tangled-file "emacs-lisp\\|elisp"))
(if compile
(progn
- (byte-compile-file tangled-file 'load)
+ (byte-compile-file tangled-file)
+ (load tangled-file)
(message "Compiled and loaded %s" tangled-file))
(load-file tangled-file)
(message "Loaded %s" tangled-file))))
@@ -348,6 +358,14 @@ FULL is given."
;;; Syntax Constants
+;;;; Comments
+(defconst org-comment-regexp
+ (rx (seq bol (zero-or-more (any "\t ")) "#" (or " " eol)))
+ "Regular expression for comment lines.")
+
+;;;; Keyword
+(defconst org-keyword-regexp "^[ \t]*#\\+\\(\\S-+?\\):[ \t]*\\(.*\\)$"
+ "Regular expression for keyword-lines.")
;;;; Block
@@ -362,6 +380,65 @@ FULL is given."
(defconst org-dblock-end-re "^[ \t]*#\\+\\(?:END\\|end\\)\\([: \t\r\n]\\|$\\)"
"Matches the end of a dynamic block.")
+;;;; Timestamp
+
+(defconst org-ts--internal-regexp
+ (rx (seq
+ (= 4 digit) "-" (= 2 digit) "-" (= 2 digit)
+ (optional " " (*? nonl))))
+ "Regular expression matching the innards of a time stamp.")
+
+(defconst org-ts-regexp (format "<\\(%s\\)>" org-ts--internal-regexp)
+ "Regular expression for fast time stamp matching.")
+
+(defconst org-ts-regexp-inactive
+ (format "\\[\\(%s\\)\\]" org-ts--internal-regexp)
+ "Regular expression for fast inactive time stamp matching.")
+
+(defconst org-ts-regexp-both (format "[[<]\\(%s\\)[]>]" org-ts--internal-regexp)
+ "Regular expression for fast time stamp matching.")
+
+(defconst org-ts-regexp0
+ "\\(\\([0-9]\\{4\\}\\)-\\([0-9]\\{2\\}\\)-\\([0-9]\\{2\\}\\)\\( +[^]+0-9>\r\n -]+\\)?\\( +\\([0-9]\\{1,2\\}\\):\\([0-9]\\{2\\}\\)\\)?\\)"
+ "Regular expression matching time strings for analysis.
+This one does not require the space after the date, so it can be used
+on a string that terminates immediately after the date.")
+
+(defconst org-ts-regexp1 "\\(\\([0-9]\\{4\\}\\)-\\([0-9]\\{2\\}\\)-\\([0-9]\\{2\\}\\) *\\([^]+0-9>\r\n -]*\\)\\( \\([0-9]\\{1,2\\}\\):\\([0-9]\\{2\\}\\)\\)?\\)"
+ "Regular expression matching time strings for analysis.")
+
+(defconst org-ts-regexp2 (concat "<" org-ts-regexp1 "[^>\n]\\{0,16\\}>")
+ "Regular expression matching time stamps, with groups.")
+
+(defconst org-ts-regexp3 (concat "[[<]" org-ts-regexp1 "[^]>\n]\\{0,16\\}[]>]")
+ "Regular expression matching time stamps (also [..]), with groups.")
+
+(defconst org-tr-regexp (concat org-ts-regexp "--?-?" org-ts-regexp)
+ "Regular expression matching a time stamp range.")
+
+(defconst org-tr-regexp-both
+ (concat org-ts-regexp-both "--?-?" org-ts-regexp-both)
+ "Regular expression matching a time stamp range.")
+
+(defconst org-tsr-regexp (concat org-ts-regexp "\\(--?-?"
+ org-ts-regexp "\\)?")
+ "Regular expression matching a time stamp or time stamp range.")
+
+(defconst org-tsr-regexp-both
+ (concat org-ts-regexp-both "\\(--?-?"
+ org-ts-regexp-both "\\)?")
+ "Regular expression matching a time stamp or time stamp range.
+The time stamps may be either active or inactive.")
+
+(defconst org-repeat-re
+ "<[0-9]\\{4\\}-[0-9][0-9]-[0-9][0-9] [^>\n]*?\
+\\([.+]?\\+[0-9]+[hdwmy]\\(/[0-9]+[hdwmy]\\)?\\)"
+ "Regular expression for specifying repeated events.
+After a match, group 1 contains the repeat expression.")
+
+(defconst org-time-stamp-formats '("<%Y-%m-%d %a>" . "<%Y-%m-%d %a %H:%M>")
+ "Formats for `format-time-string' which are used for time stamps.")
+
;;;; Clock and Planning
(defconst org-clock-string "CLOCK:"
@@ -413,7 +490,7 @@ Matched keyword is in group 1.")
(defconst org-deadline-time-hour-regexp
(concat "\\<" org-deadline-string
- " *<\\([^>]+[0-9]\\{1,2\\}:[0-9]\\{2\\}[0-9+:hdwmy \t.-]*\\)>")
+ " *<\\([^>]+[0-9]\\{1,2\\}:[0-9]\\{2\\}[0-9+:hdwmy/ \t.-]*\\)>")
"Matches the DEADLINE keyword together with a time-and-hour stamp.")
(defconst org-deadline-line-regexp
@@ -429,7 +506,7 @@ Matched keyword is in group 1.")
(defconst org-scheduled-time-hour-regexp
(concat "\\<" org-scheduled-string
- " *<\\([^>]+[0-9]\\{1,2\\}:[0-9]\\{2\\}[0-9+:hdwmy \t.-]*\\)>")
+ " *<\\([^>]+[0-9]\\{1,2\\}:[0-9]\\{2\\}[0-9+:hdwmy/ \t.-]*\\)>")
"Matches the SCHEDULED keyword together with a time-and-hour stamp.")
(defconst org-closed-time-regexp
@@ -453,18 +530,6 @@ Matched keyword is in group 1.")
" *[[<]\\([^]>]+\\)[]>]")
"Matches any of the 3 keywords, together with the time stamp.")
-(defconst org-maybe-keyword-time-regexp
- (concat "\\(\\<"
- (regexp-opt
- (list org-scheduled-string org-deadline-string org-closed-string
- org-clock-string)
- t)
- "\\)?"
- " *\\([[<][0-9]\\{4\\}-[0-9]\\{2\\}-[0-9]\\{2\\} ?[^]\r\n>]*?[]>]"
- "\\|"
- "<%%([^\r\n>]*>\\)")
- "Matches a timestamp, possibly preceded by a keyword.")
-
(defconst org-all-time-keywords
(mapcar (lambda (w) (substring w 0 -1))
(list org-scheduled-string org-deadline-string
@@ -489,6 +554,12 @@ Group 1 contains drawer's name or \"END\".")
(defconst org-clock-drawer-end-re "^[ \t]*:END:[ \t]*$"
"Regular expression matching the last line of a clock drawer.")
+(defconst org-logbook-drawer-re
+ (rx (seq bol (0+ (any "\t ")) ":LOGBOOK:" (0+ (any "\t ")) "\n"
+ (*? (0+ nonl) "\n")
+ (0+ (any "\t ")) ":END:" (0+ (any "\t ")) eol))
+ "Matches an entire LOGBOOK drawer.")
+
(defconst org-property-drawer-re
(concat "^[ \t]*:PROPERTIES:[ \t]*\n"
"\\(?:[ \t]*:\\S-+:\\(?: .*\\)?[ \t]*\n\\)*?"
@@ -560,60 +631,8 @@ An entry can be toggled between COMMENT and normal with
(defconst org-effort-property "Effort"
"The property that is being used to keep track of effort estimates.
-Effort estimates given in this property need to have the format H:MM.")
-
-;;;; Timestamp
-
-(defconst org-ts-regexp "<\\([0-9]\\{4\\}-[0-9]\\{2\\}-[0-9]\\{2\\} ?[^\r\n>]*?\\)>"
- "Regular expression for fast time stamp matching.")
-
-(defconst org-ts-regexp-inactive
- "\\[\\([0-9]\\{4\\}-[0-9]\\{2\\}-[0-9]\\{2\\} ?[^\r\n>]*?\\)\\]"
- "Regular expression for fast inactive time stamp matching.")
-
-(defconst org-ts-regexp-both "[[<]\\([0-9]\\{4\\}-[0-9]\\{2\\}-[0-9]\\{2\\} ?[^]\r\n>]*?\\)[]>]"
- "Regular expression for fast time stamp matching.")
-
-(defconst org-ts-regexp0
- "\\(\\([0-9]\\{4\\}\\)-\\([0-9]\\{2\\}\\)-\\([0-9]\\{2\\}\\)\\( +[^]+0-9>\r\n -]+\\)?\\( +\\([0-9]\\{1,2\\}\\):\\([0-9]\\{2\\}\\)\\)?\\)"
- "Regular expression matching time strings for analysis.
-This one does not require the space after the date, so it can be used
-on a string that terminates immediately after the date.")
-
-(defconst org-ts-regexp1 "\\(\\([0-9]\\{4\\}\\)-\\([0-9]\\{2\\}\\)-\\([0-9]\\{2\\}\\) *\\([^]+0-9>\r\n -]*\\)\\( \\([0-9]\\{1,2\\}\\):\\([0-9]\\{2\\}\\)\\)?\\)"
- "Regular expression matching time strings for analysis.")
-
-(defconst org-ts-regexp2 (concat "<" org-ts-regexp1 "[^>\n]\\{0,16\\}>")
- "Regular expression matching time stamps, with groups.")
-
-(defconst org-ts-regexp3 (concat "[[<]" org-ts-regexp1 "[^]>\n]\\{0,16\\}[]>]")
- "Regular expression matching time stamps (also [..]), with groups.")
-
-(defconst org-tr-regexp (concat org-ts-regexp "--?-?" org-ts-regexp)
- "Regular expression matching a time stamp range.")
-
-(defconst org-tr-regexp-both
- (concat org-ts-regexp-both "--?-?" org-ts-regexp-both)
- "Regular expression matching a time stamp range.")
-
-(defconst org-tsr-regexp (concat org-ts-regexp "\\(--?-?"
- org-ts-regexp "\\)?")
- "Regular expression matching a time stamp or time stamp range.")
-
-(defconst org-tsr-regexp-both
- (concat org-ts-regexp-both "\\(--?-?"
- org-ts-regexp-both "\\)?")
- "Regular expression matching a time stamp or time stamp range.
-The time stamps may be either active or inactive.")
-
-(defconst org-repeat-re
- "<[0-9]\\{4\\}-[0-9][0-9]-[0-9][0-9] [^>\n]*?\
-\\([.+]?\\+[0-9]+[hdwmy]\\(/[0-9]+[hdwmy]\\)?\\)"
- "Regular expression for specifying repeated events.
-After a match, group 1 contains the repeat expression.")
-
-(defconst org-time-stamp-formats '("<%Y-%m-%d %a>" . "<%Y-%m-%d %a %H:%M>")
- "Formats for `format-time-string' which are used for time stamps.")
+Effort estimates given in this property need to be in the format
+defined in org-duration.el.")
;;; The custom variables
@@ -644,6 +663,7 @@ After a match, group 1 contains the repeat expression.")
(defvar org-modules-loaded nil
"Have the modules been loaded already?")
+;;;###autoload
(defun org-load-modules-maybe (&optional force)
"Load all extensions listed in `org-modules'."
(when (or force (not org-modules-loaded))
@@ -852,6 +872,7 @@ cursor keys will then execute Org commands in the following contexts:
- in a plain list item, changing the bullet type
- in a property definition line, switching between allowed values
- in the BEGIN line of a clock table (changing the time block).
+- in a table, moving the cell in the specified direction.
Outside these contexts, the commands will throw an error.
When this variable is t and the cursor is not in a special
@@ -861,9 +882,9 @@ cycling will no longer happen anywhere in an item line, but only
if the cursor is exactly on the bullet.
If you set this variable to the symbol `always', then the keys
-will not be special in headlines, property lines, and item lines,
-to make shift selection work there as well. If this is what you
-want, you can use the following alternative commands:
+will not be special in headlines, property lines, item lines, and
+table cells, to make shift selection work there as well. If this is
+what you want, you can use the following alternative commands:
`\\[org-todo]' and `\\[org-priority]' \
to change TODO state and priority,
`\\[universal-argument] \\[universal-argument] \\[org-todo]' \
@@ -879,7 +900,7 @@ will still edit the time stamp - this is just too good to give up."
(const :tag "When outside special context" t)
(const :tag "Everywhere except timestamps" always)))
-(defcustom org-loop-over-headlines-in-active-region nil
+(defcustom org-loop-over-headlines-in-active-region t
"Shall some commands act upon headlines in the active region?
When set to t, some commands will be performed in all headlines
@@ -897,16 +918,19 @@ The list of commands is: `org-schedule', `org-deadline',
`org-todo', `org-set-tags-command', `org-archive-subtree',
`org-archive-set-tag', `org-toggle-archive-tag' and
`org-archive-to-archive-sibling'. The archiving commands skip
-already archived entries."
+already archived entries.
+
+See `org-agenda-loop-over-headlines-in-active-region' for the
+equivalent option for agenda views."
:type '(choice (const :tag "Don't loop" nil)
(const :tag "All headlines in active region" t)
(const :tag "In active region, headlines at the same level than the first one" start-level)
(string :tag "Tags/Property/Todo matcher"))
- :version "24.1"
+ :package-version '(Org . "9.4")
:group 'org-todo
:group 'org-archive)
-(defcustom org-startup-folded t
+(defcustom org-startup-folded 'showeverything
"Non-nil means entering Org mode will switch to OVERVIEW.
This can also be configured on a per-file basis by adding one of
@@ -921,6 +945,7 @@ 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
+ :package-version '(Org . "9.4")
:type '(choice
(const :tag "nofold: show all" nil)
(const :tag "fold: overview" t)
@@ -937,7 +962,7 @@ truncation for Org mode different to the other modes that use the
variable `truncate-lines' and as a shortcut instead of putting
the variable `truncate-lines' into the `org-mode-hook'. If one
wants to configure truncation for Org mode not statically but
-dynamically e. g. in a hook like `ediff-prepare-buffer-hook' then
+dynamically e.g. in a hook like `ediff-prepare-buffer-hook' then
the variable `truncate-lines' has to be used because in such a
case it is too late to set the variable `org-startup-truncated'."
:group 'org-startup
@@ -955,13 +980,24 @@ the following lines anywhere in the buffer:
(const :tag "Not" nil)
(const :tag "Globally (slow on startup in large files)" t)))
+(defcustom org-startup-numerated nil
+ "Non-nil means turn on `org-num-mode' on startup.
+This can also be configured on a per-file basis by adding one of
+the following lines anywhere in the buffer:
+
+ #+STARTUP: num
+ #+STARTUP: nonum"
+ :group 'org-structure
+ :package-version '(Org . "9.4")
+ :type '(choice
+ (const :tag "Not" nil)
+ (const :tag "Globally" t)))
+
(defcustom org-use-sub-superscripts t
"Non-nil means interpret \"_\" and \"^\" for display.
If you want to control how Org exports those characters, see
-`org-export-with-sub-superscripts'. `org-use-sub-superscripts'
-used to be an alias for `org-export-with-sub-superscripts' in
-Org <8.0, it is not anymore.
+`org-export-with-sub-superscripts'.
When this option is turned on, you can use TeX-like syntax for
sub- and superscripts within the buffer. Several characters after
@@ -1058,15 +1094,51 @@ use that string instead.
The change affects only Org mode (which will then use its own display table).
Changing this requires executing `\\[org-mode]' in a buffer to become
-effective."
+effective. It cannot be set as a local variable."
:group 'org-startup
:type '(choice (const :tag "Default" nil)
- (string :tag "String" :value "...#"))
- :safe (lambda (v) (and (string-or-null-p v) (not (equal "" v)))))
+ (string :tag "String" :value "...#")))
(defvar org-display-table nil
"The display table for Org mode, in case `org-ellipsis' is non-nil.")
+(defcustom org-directory "~/org"
+ "Directory with Org files.
+This is just a default location to look for Org files. There is no need
+at all to put your files into this directory. It is used in the
+following situations:
+
+1. When a capture template specifies a target file that is not an
+ absolute path. The path will then be interpreted relative to
+ `org-directory'
+2. When the value of variable `org-agenda-files' is a single file, any
+ relative paths in this file will be taken as relative to
+ `org-directory'."
+ :group 'org-refile
+ :group 'org-capture
+ :type 'directory)
+
+(defcustom org-default-notes-file (convert-standard-filename "~/.notes")
+ "Default target for storing notes.
+Used as a fall back file for org-capture.el, for templates that
+do not specify a target file."
+ :group 'org-refile
+ :group 'org-capture
+ :type 'file)
+
+(defcustom org-reverse-note-order nil
+ "Non-nil means store new notes at the beginning of a file or entry.
+When nil, new notes will be filed to the end of a file or entry.
+This can also be a list with cons cells of regular expressions that
+are matched against file names, and values."
+ :group 'org-capture
+ :group 'org-refile
+ :type '(choice
+ (const :tag "Reverse always" t)
+ (const :tag "Reverse never" nil)
+ (repeat :tag "By file name regexp"
+ (cons regexp boolean))))
+
(defgroup org-keywords nil
"Keywords in Org mode."
:tag "Org Keywords"
@@ -1097,7 +1169,7 @@ effective."
"Alist between context and visibility span when revealing a location.
\\<org-mode-map>Some actions may move point into invisible
-locations. As a consequence, Org always expose a neighborhood
+locations. As a consequence, Org always exposes a neighborhood
around point. How much is shown depends on the initial action,
or context. Valid contexts are
@@ -1219,16 +1291,17 @@ See `org-file-apps'.")
(defcustom org-file-apps
'((auto-mode . emacs)
+ (directory . emacs)
("\\.mm\\'" . default)
("\\.x?html?\\'" . default)
("\\.pdf\\'" . default))
- "External applications for opening `file:path' items in a document.
+ "Applications for opening `file:path' items in a document.
\\<org-mode-map>
-Org mode uses system defaults for different file types, but
-you can use this variable to set the application for a given file
-extension. The entries in this list are cons cells where the car identifies
-files and the cdr the corresponding command.
+Org mode uses system defaults for different file types, but you
+can use this variable to set the application for a given file
+extension. The entries in this list are cons cells where the car
+identifies files and the cdr the corresponding command.
Possible values for the file identifier are:
@@ -1304,6 +1377,7 @@ For more examples, see the system specific constants
`org-file-apps-windowsnt'
`org-file-apps-gnu'."
:group 'org
+ :package-version '(Org . "9.4")
:type '(repeat
(cons (choice :value ""
(string :tag "Extension")
@@ -1466,6 +1540,7 @@ the values `folded', `children', or `subtree'."
:type 'hook)
(defcustom org-cycle-hook '(org-cycle-hide-archived-subtrees
+ org-cycle-hide-drawers
org-cycle-show-empty-lines
org-optimize-window-after-visibility-change)
"Hook that is run after `org-cycle' has changed the buffer visibility.
@@ -1475,9 +1550,8 @@ argument is a symbol. After a global state change, it can have the values
`overview', `contents', or `all'. After a local state change, it can have
the values `folded', `children', or `subtree'."
:group 'org-cycle
- :type 'hook
- :version "26.1"
- :package-version '(Org . "8.3"))
+ :package-version '(Org . "9.4")
+ :type 'hook)
(defgroup org-edit-structure nil
"Options concerning structure editing in Org mode."
@@ -1503,9 +1577,15 @@ lines to the buffer:
(defcustom org-adapt-indentation t
"Non-nil means adapt indentation to outline node level.
-When this variable is set, Org assumes that you write outlines by
-indenting text in each node to align with the headline (after the
-stars). The following issues are influenced by this variable:
+When this variable is set to t, Org assumes that you write
+outlines by indenting text in each node to align with the
+headline (after the stars).
+
+When this variable is set to 'headline-data, only adapt the
+indentation of the data lines right below the headline, such as
+planning/clock lines and property/logbook drawers.
+
+The following issues are influenced by this variable:
- The indentation is increased by one space in a demotion
command, and decreased by one in a promotion command. However,
@@ -1517,14 +1597,18 @@ stars). The following issues are influenced by this variable:
when this variable is set. When nil, they will not be indented.
- TAB indents a line relative to current level. The lines below
- a headline will be indented when this variable is set.
+ a headline will be indented when this variable is set to t.
Note that this is all about true indentation, by adding and
removing space characters. See also \"org-indent.el\" which does
level-dependent indentation in a virtual way, i.e. at display
time in Emacs."
:group 'org-edit-structure
- :type 'boolean
+ :type '(choice
+ (const :tag "Adapt indentation for all lines" t)
+ (const :tag "Adapt indentation for headline data lines"
+ 'headline-data)
+ (const :tag "Do not adapt indentation at all" nil))
:safe #'booleanp)
(defvaralias 'org-special-ctrl-a 'org-special-ctrl-a/e)
@@ -1572,16 +1656,15 @@ This may also be a cons cell where the behavior for `C-a' and
When nil, `C-k' will call the default `kill-line' command.
When t, the following will happen while the cursor is in the headline:
-- When the cursor is at the beginning of a headline, kill the entire
- line and possible the folded subtree below the line.
-- When in the middle of the headline text, kill the headline up to the tags.
-- When after the headline text, kill the tags."
+- When at the beginning of a headline, kill the entire subtree.
+- When in the middle of the headline text, kill the text up to the tags.
+- When after the headline text and before the tags, kill all the tags."
:group 'org-edit-structure
:type 'boolean)
(defcustom org-ctrl-k-protect-subtree nil
- "Non-nil means, do not delete a hidden subtree with C-k.
-When set to the symbol `error', simply throw an error when C-k is
+ "Non-nil means, do not delete a hidden subtree with `C-k'.
+When set to the symbol `error', simply throw an error when `C-k' is
used to kill (part-of) a headline that has hidden text behind it.
Any other non-nil value will result in a query to the user, if it is
OK to kill that hidden subtree. When nil, kill without remorse."
@@ -1786,213 +1869,6 @@ Changing this requires a restart of Emacs to work correctly."
:group 'org-link-follow
:type 'integer)
-(defgroup org-refile nil
- "Options concerning refiling entries in Org mode."
- :tag "Org Refile"
- :group 'org)
-
-(defcustom org-directory "~/org"
- "Directory with Org files.
-This is just a default location to look for Org files. There is no need
-at all to put your files into this directory. It is used in the
-following situations:
-
-1. When a capture template specifies a target file that is not an
- absolute path. The path will then be interpreted relative to
- `org-directory'
-2. When the value of variable `org-agenda-files' is a single file, any
- relative paths in this file will be taken as relative to
- `org-directory'."
- :group 'org-refile
- :group 'org-capture
- :type 'directory)
-
-(defcustom org-default-notes-file (convert-standard-filename "~/.notes")
- "Default target for storing notes.
-Used as a fall back file for org-capture.el, for templates that
-do not specify a target file."
- :group 'org-refile
- :group 'org-capture
- :type 'file)
-
-(defcustom org-reverse-note-order nil
- "Non-nil means store new notes at the beginning of a file or entry.
-When nil, new notes will be filed to the end of a file or entry.
-This can also be a list with cons cells of regular expressions that
-are matched against file names, and values."
- :group 'org-capture
- :group 'org-refile
- :type '(choice
- (const :tag "Reverse always" t)
- (const :tag "Reverse never" nil)
- (repeat :tag "By file name regexp"
- (cons regexp boolean))))
-
-(defcustom org-log-refile nil
- "Information to record when a task is refiled.
-
-Possible values are:
-
-nil Don't add anything
-time Add a time stamp to the task
-note Prompt for a note and add it with template `org-log-note-headings'
-
-This option can also be set with on a per-file-basis with
-
- #+STARTUP: nologrefile
- #+STARTUP: logrefile
- #+STARTUP: lognoterefile
-
-You can have local logging settings for a subtree by setting the LOGGING
-property to one or more of these keywords.
-
-When bulk-refiling, e.g., from the agenda, the value `note' is
-forbidden and will temporarily be changed to `time'."
- :group 'org-refile
- :group 'org-progress
- :version "24.1"
- :type '(choice
- (const :tag "No logging" nil)
- (const :tag "Record timestamp" time)
- (const :tag "Record timestamp with note." note)))
-
-(defcustom org-refile-targets nil
- "Targets for refiling entries with `\\[org-refile]'.
-This is a list of cons cells. Each cell contains:
-- a specification of the files to be considered, either a list of files,
- or a symbol whose function or variable value will be used to retrieve
- a file name or a list of file names. If you use `org-agenda-files' for
- that, all agenda files will be scanned for targets. Nil means consider
- headings in the current buffer.
-- A specification of how to find candidate refile targets. This may be
- any of:
- - a cons cell (:tag . \"TAG\") to identify refile targets by a tag.
- This tag has to be present in all target headlines, inheritance will
- not be considered.
- - a cons cell (:todo . \"KEYWORD\") to identify refile targets by
- todo keyword.
- - a cons cell (:regexp . \"REGEXP\") with a regular expression matching
- headlines that are refiling targets.
- - a cons cell (:level . N). Any headline of level N is considered a target.
- Note that, when `org-odd-levels-only' is set, level corresponds to
- order in hierarchy, not to the number of stars.
- - a cons cell (:maxlevel . N). Any headline with level <= N is a target.
- Note that, when `org-odd-levels-only' is set, level corresponds to
- order in hierarchy, not to the number of stars.
-
-Each element of this list generates a set of possible targets.
-The union of these sets is presented (with completion) to
-the user by `org-refile'.
-
-You can set the variable `org-refile-target-verify-function' to a function
-to verify each headline found by the simple criteria above.
-
-When this variable is nil, all top-level headlines in the current buffer
-are used, equivalent to the value `((nil . (:level . 1))'."
- :group 'org-refile
- :type '(repeat
- (cons
- (choice :value org-agenda-files
- (const :tag "All agenda files" org-agenda-files)
- (const :tag "Current buffer" nil)
- (function) (variable) (file))
- (choice :tag "Identify target headline by"
- (cons :tag "Specific tag" (const :value :tag) (string))
- (cons :tag "TODO keyword" (const :value :todo) (string))
- (cons :tag "Regular expression" (const :value :regexp) (regexp))
- (cons :tag "Level number" (const :value :level) (integer))
- (cons :tag "Max Level number" (const :value :maxlevel) (integer))))))
-
-(defcustom org-refile-target-verify-function nil
- "Function to verify if the headline at point should be a refile target.
-The function will be called without arguments, with point at the
-beginning of the headline. It should return t and leave point
-where it is if the headline is a valid target for refiling.
-
-If the target should not be selected, the function must return nil.
-In addition to this, it may move point to a place from where the search
-should be continued. For example, the function may decide that the entire
-subtree of the current entry should be excluded and move point to the end
-of the subtree."
- :group 'org-refile
- :type '(choice
- (const nil)
- (function)))
-
-(defcustom org-refile-use-cache nil
- "Non-nil means cache refile targets to speed up the process.
-\\<org-mode-map>\
-The cache for a particular file will be updated automatically when
-the buffer has been killed, or when any of the marker used for flagging
-refile targets no longer points at a live buffer.
-If you have added new entries to a buffer that might themselves be targets,
-you need to clear the cache manually by pressing `C-0 \\[org-refile]' or,
-if you find that easier, \
-`\\[universal-argument] \\[universal-argument] \\[universal-argument] \
-\\[org-refile]'."
- :group 'org-refile
- :version "24.1"
- :type 'boolean)
-
-(defcustom org-refile-use-outline-path nil
- "Non-nil means provide refile targets as paths.
-So a level 3 headline will be available as level1/level2/level3.
-
-When the value is `file', also include the file name (without directory)
-into the path. In this case, you can also stop the completion after
-the file name, to get entries inserted as top level in the file.
-
-When `full-file-path', include the full file path.
-
-When `buffer-name', use the buffer name."
- :group 'org-refile
- :type '(choice
- (const :tag "Not" nil)
- (const :tag "Yes" t)
- (const :tag "Start with file name" file)
- (const :tag "Start with full file path" full-file-path)
- (const :tag "Start with buffer name" buffer-name)))
-
-(defcustom org-outline-path-complete-in-steps t
- "Non-nil means complete the outline path in hierarchical steps.
-When Org uses the refile interface to select an outline path (see
-`org-refile-use-outline-path'), the completion of the path can be
-done in a single go, or it can be done in steps down the headline
-hierarchy. Going in steps is probably the best if you do not use
-a special completion package like `ido' or `icicles'. However,
-when using these packages, going in one step can be very fast,
-while still showing the whole path to the entry."
- :group 'org-refile
- :type 'boolean)
-
-(defcustom org-refile-allow-creating-parent-nodes nil
- "Non-nil means allow the creation of new nodes as refile targets.
-New nodes are then created by adding \"/new node name\" to the completion
-of an existing node. When the value of this variable is `confirm',
-new node creation must be confirmed by the user (recommended).
-When nil, the completion must match an existing entry.
-
-Note that, if the new heading is not seen by the criteria
-listed in `org-refile-targets', multiple instances of the same
-heading would be created by trying again to file under the new
-heading."
- :group 'org-refile
- :type '(choice
- (const :tag "Never" nil)
- (const :tag "Always" t)
- (const :tag "Prompt for confirmation" confirm)))
-
-(defcustom org-refile-active-region-within-subtree nil
- "Non-nil means also refile active region within a subtree.
-
-By default `org-refile' doesn't allow refiling regions if they
-don't contain a set of subtrees, but it might be convenient to
-do so sometimes: in that case, the first line of the region is
-converted to a headline before refiling."
- :group 'org-refile
- :version "24.1"
- :type 'boolean)
-
(defgroup org-todo nil
"Options concerning TODO items in Org mode."
:tag "Org TODO"
@@ -2548,53 +2424,69 @@ property to one or more of these keywords."
:tag "Org Priorities"
:group 'org-todo)
-(defcustom org-enable-priority-commands t
+(defvaralias 'org-enable-priority-commands 'org-priority-enable-commands)
+(defcustom org-priority-enable-commands t
"Non-nil means priority commands are active.
When nil, these commands will be disabled, so that you never accidentally
set a priority."
:group 'org-priorities
:type 'boolean)
-(defcustom org-highest-priority ?A
- "The highest priority of TODO items. A character like ?A, ?B etc.
-Must have a smaller ASCII number than `org-lowest-priority'."
- :group 'org-priorities
- :type 'character)
+(defvaralias 'org-highest-priority 'org-priority-highest)
-(defcustom org-lowest-priority ?C
- "The lowest priority of TODO items. A character like ?A, ?B etc.
-Must have a larger ASCII number than `org-highest-priority'."
+(defcustom org-priority-highest ?A
+ "The highest priority of TODO items.
+A character like ?A, ?B, etc., or a numeric value like 1, 2, etc.
+Must be smaller than `org-priority-lowest'."
+ :group 'org-priorities
+ :type '(choice
+ (character :tag "Character")
+ (integer :tag "Integer (< 65)")))
+
+(defvaralias 'org-lowest-priority 'org-priority-lowest)
+(defcustom org-priority-lowest ?C
+ "The lowest priority of TODO items.
+A character like ?A, ?B, etc., or a numeric value like 1, 2, etc.
+Must be higher than `org-priority-highest'."
:group 'org-priorities
- :type 'character)
+ :type '(choice
+ (character :tag "Character")
+ (integer :tag "Integer (< 65)")))
-(defcustom org-default-priority ?B
+(defvaralias 'org-default-priority 'org-priority-default)
+(defcustom org-priority-default ?B
"The default priority of TODO items.
This is the priority an item gets if no explicit priority is given.
When starting to cycle on an empty priority the first step in the cycle
depends on `org-priority-start-cycle-with-default'. The resulting first
-step priority must not exceed the range from `org-highest-priority' to
-`org-lowest-priority' which means that `org-default-priority' has to be
-in this range exclusive or inclusive the range boundaries. Else the
-first step refuses to set the default and the second will fall back
-to (depending on the command used) the highest or lowest priority."
+step priority must not exceed the range from `org-priority-highest' to
+`org-priority-lowest' which means that `org-priority-default' has to be
+in this range exclusive or inclusive to the range boundaries. Else the
+first step refuses to set the default and the second will fall back on
+\(depending on the command used) the highest or lowest priority."
:group 'org-priorities
- :type 'character)
+ :type '(choice
+ (character :tag "Character")
+ (integer :tag "Integer (< 65)")))
(defcustom org-priority-start-cycle-with-default t
"Non-nil means start with default priority when starting to cycle.
When this is nil, the first step in the cycle will be (depending on the
command used) one higher or lower than the default priority.
-See also `org-default-priority'."
+See also `org-priority-default'."
:group 'org-priorities
:type 'boolean)
-(defcustom org-get-priority-function nil
+(defvaralias 'org-get-priority-function 'org-priority-get-priority-function)
+(defcustom org-priority-get-priority-function nil
"Function to extract the priority from a string.
-The string is normally the headline. If this is nil Org computes the
-priority from the priority cookie like [#A] in the headline. It returns
-an integer, increasing by 1000 for each priority level.
-The user can set a different function here, which should take a string
-as an argument and return the numeric priority."
+The string is normally the headline. If this is nil, Org
+computes the priority from the priority cookie like [#A] in the
+headline. It returns an integer, increasing by 1000 for each
+priority level.
+
+The user can set a different function here, which should take a
+string as an argument and return the numeric priority."
:group 'org-priorities
:version "24.1"
:type '(choice
@@ -2767,7 +2659,9 @@ stamps outside of this range."
(defcustom org-read-date-display-live t
"Non-nil means display current interpretation of date prompt live.
-This display will be in an overlay, in the minibuffer."
+This display will be in an overlay, in the minibuffer. Note that
+live display is only active when `org-read-date-popup-calendar'
+is non-nil."
:group 'org-time
:type 'boolean)
@@ -2944,7 +2838,7 @@ automatically if necessary."
When nil, you have to press RET to exit it.
During fast tag selection, you can toggle this flag with `C-c'.
This variable can also have the value `expert'. In this case, the window
-displaying the tags menu is not even shown, until you press C-c again."
+displaying the tags menu is not even shown, until you press `C-c' again."
:group 'org-tags
:type '(choice
(const :tag "No" nil)
@@ -3180,8 +3074,13 @@ This list will be combined with the constant `org-global-properties-fixed'.
The entries in this list are cons cells where the car is a property
name and cdr is a string with the value.
-You can set buffer-local values for the same purpose in the variable
-`org-file-properties' this by adding lines like
+Buffer local properties are added either by a document property drawer
+
+:PROPERTIES:
+:NAME: VALUE
+:END:
+
+or by adding lines like
#+PROPERTY: NAME VALUE"
:group 'org-properties
@@ -3189,10 +3088,15 @@ You can set buffer-local values for the same purpose in the variable
(cons (string :tag "Property")
(string :tag "Value"))))
-(defvar-local org-file-properties nil
- "List of property/value pairs that can be inherited by any entry.
-Valid for the current buffer.
-This variable is populated from #+PROPERTY lines.")
+(defvar-local org-keyword-properties nil
+ "List of property/value pairs inherited by any entry.
+
+Valid for the current buffer. This variable is populated from
+PROPERTY keywords.
+
+Note that properties are defined also in property drawers.
+Properties defined there take precedence over properties defined
+as keywords.")
(defgroup org-agenda nil
"Options concerning agenda views in Org mode."
@@ -3201,11 +3105,18 @@ This variable is populated from #+PROPERTY lines.")
(defvar-local org-category nil
"Variable used by Org files to set a category for agenda display.
-Such files should use a file variable to set it, for example
+There are multiple ways to set the category. One way is to set
+it in the document property drawer. For example:
+
+:PROPERTIES:
+:CATEGORY: ELisp
+:END:
+
+Other ways to define it is as an emacs file variable, for example
# -*- mode: org; org-category: \"ELisp\"
-or contain a special line
+or for the file to contain a special line:
#+CATEGORY: ELisp
@@ -3266,16 +3177,6 @@ A nil value means to remove them, after a query, from the list."
:group 'org-agenda
:type 'boolean)
-(defcustom org-agenda-diary-file 'diary-file
- "File to which to add new entries with the `i' key in agenda and calendar.
-When this is the symbol `diary-file', the functionality in the Emacs
-calendar will be used to add entries to the `diary-file'. But when this
-points to a file, `org-agenda-diary-entry' will be used instead."
- :group 'org-agenda
- :type '(choice
- (const :tag "The standard Emacs diary file" diary-file)
- (file :tag "Special Org file diary entries")))
-
(defgroup org-latex nil
"Options for embedding LaTeX code into Org mode."
:tag "Org LaTeX"
@@ -3349,6 +3250,22 @@ When using LaTeXML set this option to
(const :tag "None" nil)
(string :tag "\nShell command")))
+(defcustom org-latex-to-html-convert-command nil
+ "Command to convert LaTeX fragments to HTML.
+This command is very open-ended: the output of the command will
+directly replace the LaTeX fragment in the resulting HTML.
+Replace format-specifiers in the command as noted below and use
+`shell-command' to convert LaTeX to HTML.
+%i: The LaTeX fragment to be converted.
+
+For example, this could be used with LaTeXML as
+\"latexmlc 'literal:%i' --profile=math --preload=siunitx.sty 2>/dev/null\"."
+ :group 'org-latex
+ :package-version '(Org . "9.4")
+ :type '(choice
+ (const :tag "None" nil)
+ (string :tag "Shell command")))
+
(defcustom org-preview-latex-default-process 'dvipng
"The default process to convert LaTeX fragments to image files.
All available processes and theirs documents can be found in
@@ -3667,12 +3584,23 @@ hide them with `org-toggle-custom-properties-visibility'."
:version "24.3"
:type '(repeat (string :tag "Property Name")))
-(defcustom org-fontify-done-headline nil
+(defcustom org-fontify-todo-headline nil
+ "Non-nil means change the face of a headline if it is marked as TODO.
+Normally, only the TODO/DONE keyword indicates the state of a headline.
+When this is non-nil, the headline after the keyword is set to the
+`org-headline-todo' as an additional indication."
+ :group 'org-appearance
+ :package-version '(Org . "9.4")
+ :type 'boolean
+ :safe t)
+
+(defcustom org-fontify-done-headline t
"Non-nil means change the face of a headline if it is marked DONE.
Normally, only the TODO/DONE keyword indicates the state of a headline.
When this is non-nil, the headline after the keyword is set to the
`org-headline-done' as an additional indication."
:group 'org-appearance
+ :package-version '(Org . "9.4")
:type 'boolean)
(defcustom org-fontify-emphasized-text t
@@ -3774,7 +3702,7 @@ After a match, the match groups contain these elements:
;; This used to be a defcustom (Org <8.0) but allowing the users to
;; set this option proved cumbersome. See this message/thread:
-;; http://article.gmane.org/gmane.emacs.orgmode/68681
+;; https://orgmode.org/list/B72CDC2B-72F6-43A8-AC70-E6E6295766EC@gmail.com
(defvar org-emphasis-regexp-components
'("-[:space:]('\"{" "-[:space:].,:!?;'\")}\\[" "[:space:]" "." 1)
"Components used to build the regular expression for emphasis.
@@ -3920,6 +3848,14 @@ If yes, offer to stop it and to save the buffer with the changes."
(add-hook 'org-mode-hook 'org-clock-load)
(add-hook 'kill-emacs-hook 'org-clock-save))
+(defun org-clock-auto-clockout-insinuate ()
+ "Set up hook for auto clocking out when Emacs is idle.
+See `org-clock-auto-clockout-timer'.
+
+This function is meant to be added to the user configuration."
+ (require 'org-clock)
+ (add-hook 'org-clock-in-hook #'org-clock-auto-clockout t))
+
(defgroup org-archive nil
"Options concerning archiving in Org mode."
:tag "Org Archive"
@@ -3973,14 +3909,13 @@ Here are a few examples:
Archive in file ./basement (relative path), as level 3 trees
below the level 2 heading \"** Finished Tasks\".
-You may set this option on a per-file basis by adding to the buffer a
-line like
+You may define it locally by setting an ARCHIVE property. If
+such a property is found in the file or in an entry, and anywhere
+up the hierarchy, it will be used.
-#+ARCHIVE: basement::** Finished Tasks
+You can also set it for the whole file using the keyword-syntax:
-You may also define it locally for a subtree by setting an ARCHIVE property
-in the entry. If such a property is found in an entry, or anywhere up
-the hierarchy, it will be used."
+#+ARCHIVE: basement::** Finished Tasks"
:group 'org-archive
:type 'string)
@@ -4189,6 +4124,8 @@ After a match, the following groups carry important information:
("content" org-startup-folded content)
("indent" org-startup-indented t)
("noindent" org-startup-indented nil)
+ ("num" org-startup-numerated t)
+ ("nonum" org-startup-numerated nil)
("hidestars" org-hide-leading-stars t)
("showstars" org-hide-leading-stars nil)
("odd" org-odd-levels-only t)
@@ -4302,72 +4239,112 @@ See `org-tag-alist' for their structure."
;; Preserve order of ALIST1.
(append (nreverse to-add) alist2)))))
+(defun org-priority-to-value (s)
+ "Convert priority string S to its numeric value."
+ (or (save-match-data
+ (and (string-match "\\([0-9]+\\)" s)
+ (string-to-number (match-string 1 s))))
+ (string-to-char s)))
+
(defun org-set-regexps-and-options (&optional tags-only)
"Precompute regular expressions used in the current buffer.
When optional argument TAGS-ONLY is non-nil, only compute tags
related expressions."
(when (derived-mode-p 'org-mode)
- (let ((alist (org--setup-collect-keywords
- (org-make-options-regexp
- (append '("FILETAGS" "TAGS" "SETUPFILE")
- (and (not tags-only)
- '("ARCHIVE" "CATEGORY" "COLUMNS" "CONSTANTS"
- "LINK" "OPTIONS" "PRIORITIES" "PROPERTY"
- "SEQ_TODO" "STARTUP" "TODO" "TYP_TODO")))))))
+ (let ((alist (org-collect-keywords
+ (append '("FILETAGS" "TAGS")
+ (and (not tags-only)
+ '("ARCHIVE" "CATEGORY" "COLUMNS" "CONSTANTS"
+ "LINK" "OPTIONS" "PRIORITIES" "PROPERTY"
+ "SEQ_TODO" "STARTUP" "TODO" "TYP_TODO")))
+ '("ARCHIVE" "CATEGORY" "COLUMNS" "PRIORITIES"))))
;; Startup options. Get this early since it does change
;; behavior for other options (e.g., tags).
- (let ((startup (cdr (assq 'startup alist))))
+ (let ((startup (cl-mapcan (lambda (value) (split-string value))
+ (cdr (assoc "STARTUP" alist)))))
(dolist (option startup)
- (let ((entry (assoc-string option org-startup-options t)))
- (when entry
- (let ((var (nth 1 entry))
- (val (nth 2 entry)))
- (if (not (nth 3 entry)) (set (make-local-variable var) val)
- (unless (listp (symbol-value var))
- (set (make-local-variable var) nil))
- (add-to-list var val)))))))
+ (pcase (assoc-string option org-startup-options t)
+ (`(,_ ,variable ,value t)
+ (unless (listp (symbol-value variable))
+ (set (make-local-variable variable) nil))
+ (add-to-list variable value))
+ (`(,_ ,variable ,value . ,_)
+ (set (make-local-variable variable) value))
+ (_ nil))))
(setq-local org-file-tags
(mapcar #'org-add-prop-inherited
- (cdr (assq 'filetags alist))))
+ (cl-mapcan (lambda (value)
+ (cl-mapcan
+ (lambda (k) (org-split-string k ":"))
+ (split-string value)))
+ (cdr (assoc "FILETAGS" alist)))))
(setq org-current-tag-alist
(org--tag-add-to-alist
org-tag-persistent-alist
- (let ((tags (cdr (assq 'tags alist))))
- (if tags (org-tag-string-to-alist tags)
+ (let ((tags (cdr (assoc "TAGS" alist))))
+ (if tags
+ (org-tag-string-to-alist
+ (mapconcat #'identity tags "\n"))
org-tag-alist))))
(setq org-tag-groups-alist
(org-tag-alist-to-groups org-current-tag-alist))
(unless tags-only
- ;; File properties.
- (setq-local org-file-properties (cdr (assq 'property alist)))
+ ;; Properties.
+ (let ((properties nil))
+ (dolist (value (cdr (assoc "PROPERTY" alist)))
+ (when (string-match "\\(\\S-+\\)[ \t]+\\(.*\\)" value)
+ (setq properties (org--update-property-plist
+ (match-string-no-properties 1 value)
+ (match-string-no-properties 2 value)
+ properties))))
+ (setq-local org-keyword-properties properties))
;; Archive location.
- (let ((archive (cdr (assq 'archive alist))))
+ (let ((archive (cdr (assoc "ARCHIVE" alist))))
(when archive (setq-local org-archive-location archive)))
;; Category.
- (let ((cat (org-string-nw-p (cdr (assq 'category alist)))))
- (when cat
- (setq-local org-category (intern cat))
- (setq-local org-file-properties
+ (let ((category (cdr (assoc "CATEGORY" alist))))
+ (when category
+ (setq-local org-category (intern category))
+ (setq-local org-keyword-properties
(org--update-property-plist
- "CATEGORY" cat org-file-properties))))
+ "CATEGORY" category org-keyword-properties))))
;; Columns.
- (let ((column (cdr (assq 'columns alist))))
+ (let ((column (cdr (assoc "COLUMNS" alist))))
(when column (setq-local org-columns-default-format column)))
;; Constants.
- (setq org-table-formula-constants-local (cdr (assq 'constants alist)))
+ (let ((store nil))
+ (dolist (pair (cl-mapcan #'split-string
+ (cdr (assoc "CONSTANTS" alist))))
+ (when (string-match "^\\([a-zA-Z0][_a-zA-Z0-9]*\\)=\\(.*\\)" pair)
+ (let* ((name (match-string 1 pair))
+ (value (match-string 2 pair))
+ (old (assoc name store)))
+ (if old (setcdr old value)
+ (push (cons name value) store)))))
+ (setq org-table-formula-constants-local store))
;; Link abbreviations.
- (let ((links (cdr (assq 'link alist))))
+ (let ((links
+ (delq nil
+ (mapcar
+ (lambda (value)
+ (and (string-match "\\`\\(\\S-+\\)[ \t]+\\(.+\\)" value)
+ (cons (match-string-no-properties 1 value)
+ (match-string-no-properties 2 value))))
+ (cdr (assoc "LINK" alist))))))
(when links (setq org-link-abbrev-alist-local (nreverse links))))
;; Priorities.
- (let ((priorities (cdr (assq 'priorities alist))))
- (when priorities
- (setq-local org-highest-priority (nth 0 priorities))
- (setq-local org-lowest-priority (nth 1 priorities))
- (setq-local org-default-priority (nth 2 priorities))))
+ (let ((value (cdr (assoc "PRIORITIES" alist))))
+ (pcase (and value (split-string value))
+ (`(,high ,low ,default . ,_)
+ (setq-local org-priority-highest (org-priority-to-value high))
+ (setq-local org-priority-lowest (org-priority-to-value low))
+ (setq-local org-priority-default (org-priority-to-value default)))))
;; Scripts.
- (let ((scripts (assq 'scripts alist)))
- (when scripts
- (setq-local org-use-sub-superscripts (cdr scripts))))
+ (let ((value (cdr (assoc "OPTIONS" alist))))
+ (dolist (option value)
+ (when (string-match "\\^:\\(t\\|nil\\|{}\\)" option)
+ (setq-local org-use-sub-superscripts
+ (read (match-string 1 option))))))
;; TODO keywords.
(setq-local org-todo-kwd-alist nil)
(setq-local org-todo-key-alist nil)
@@ -4378,7 +4355,13 @@ related expressions."
(setq-local org-todo-sets nil)
(setq-local org-todo-log-states nil)
(let ((todo-sequences
- (or (nreverse (cdr (assq 'todo alist)))
+ (or (append (mapcar (lambda (value)
+ (cons 'type (split-string value)))
+ (cdr (assoc "TYP_TODO" alist)))
+ (mapcar (lambda (value)
+ (cons 'sequence (split-string value)))
+ (append (cdr (assoc "TODO" alist))
+ (cdr (assoc "SEQ_TODO" alist)))))
(let ((d (default-value 'org-todo-keywords)))
(if (not (stringp (car d))) d
;; XXX: Backward compatibility code.
@@ -4463,109 +4446,90 @@ related expressions."
"[ \t]*$"))
(org-compute-latex-and-related-regexp)))))
-(defun org--setup-collect-keywords (regexp &optional files alist)
- "Return setup keywords values as an alist.
+(defun org-collect-keywords (keywords &optional unique directory)
+ "Return values for KEYWORDS in current buffer, as an alist.
-REGEXP matches a subset of setup keywords. FILES is a list of
-file names already visited. It is used to avoid circular setup
-files. ALIST, when non-nil, is the alist computed so far.
+KEYWORDS is a list of strings. Return value is a list of
+elements with the pattern:
-Return value contains the following keys: `archive', `category',
-`columns', `constants', `filetags', `link', `priorities',
-`property', `scripts', `startup', `tags' and `todo'."
- (org-with-wide-buffer
- (goto-char (point-min))
- (let ((case-fold-search t))
- (while (re-search-forward regexp nil t)
- (let ((element (org-element-at-point)))
- (when (eq (org-element-type element) 'keyword)
- (let ((key (org-element-property :key element))
- (value (org-element-property :value element)))
- (cond
- ((equal key "ARCHIVE")
- (when (org-string-nw-p value)
- (push (cons 'archive value) alist)))
- ((equal key "CATEGORY") (push (cons 'category value) alist))
- ((equal key "COLUMNS") (push (cons 'columns value) alist))
- ((equal key "CONSTANTS")
- (let* ((constants (assq 'constants alist))
- (store (cdr constants)))
- (dolist (pair (split-string value))
- (when (string-match "^\\([a-zA-Z0][_a-zA-Z0-9]*\\)=\\(.*\\)"
- pair)
- (let* ((name (match-string 1 pair))
- (value (match-string 2 pair))
- (old (assoc name store)))
- (if old (setcdr old value)
- (push (cons name value) store)))))
- (if constants (setcdr constants store)
- (push (cons 'constants store) alist))))
- ((equal key "FILETAGS")
- (when (org-string-nw-p value)
- (let ((old (assq 'filetags alist))
- (new (apply #'nconc
- (mapcar (lambda (x) (org-split-string x ":"))
- (split-string value)))))
- (if old (setcdr old (append new (cdr old)))
- (push (cons 'filetags new) alist)))))
- ((equal key "LINK")
- (when (string-match "\\`\\(\\S-+\\)[ \t]+\\(.+\\)" value)
- (let ((links (assq 'link alist))
- (pair (cons (match-string-no-properties 1 value)
- (match-string-no-properties 2 value))))
- (if links (push pair (cdr links))
- (push (list 'link pair) alist)))))
- ((equal key "OPTIONS")
- (when (and (org-string-nw-p value)
- (string-match "\\^:\\(t\\|nil\\|{}\\)" value))
- (push (cons 'scripts (read (match-string 1 value))) alist)))
- ((equal key "PRIORITIES")
- (push (cons 'priorities
- (let ((prio (split-string value)))
- (if (< (length prio) 3) '(?A ?C ?B)
- (mapcar #'string-to-char prio))))
- alist))
- ((equal key "PROPERTY")
- (when (string-match "\\(\\S-+\\)[ \t]+\\(.*\\)" value)
- (let* ((property (assq 'property alist))
- (value (org--update-property-plist
- (match-string-no-properties 1 value)
- (match-string-no-properties 2 value)
- (cdr property))))
- (if property (setcdr property value)
- (push (cons 'property value) alist)))))
- ((equal key "STARTUP")
- (let ((startup (assq 'startup alist)))
- (if startup
- (setcdr startup
- (append (cdr startup) (split-string value)))
- (push (cons 'startup (split-string value)) alist))))
- ((equal key "TAGS")
- (let ((tag-cell (assq 'tags alist)))
- (if tag-cell
- (setcdr tag-cell (concat (cdr tag-cell) "\n" value))
- (push (cons 'tags value) alist))))
- ((member key '("TODO" "SEQ_TODO" "TYP_TODO"))
- (let ((todo (assq 'todo alist))
- (value (cons (if (equal key "TYP_TODO") 'type 'sequence)
- (split-string value))))
- (if todo (push value (cdr todo))
- (push (list 'todo value) alist))))
- ((equal key "SETUPFILE")
- (unless buffer-read-only ; Do not check in Gnus messages.
- (let ((f (and (org-string-nw-p value)
- (expand-file-name (org-strip-quotes value)))))
- (when (and f (file-readable-p f) (not (member f files)))
- (with-temp-buffer
- (setq default-directory (file-name-directory f))
- (insert-file-contents f)
- (setq alist
- ;; Fake Org mode to benefit from cache
- ;; without recurring needlessly.
+ (NAME . LIST-OF-VALUES)
+
+where NAME is the upcase name of the keyword, and LIST-OF-VALUES
+is a list of non-empty values, as strings, in order of appearance
+in the buffer.
+
+When KEYWORD appears in UNIQUE list, LIST-OF-VALUE is its first
+value, empty or not, appearing in the buffer, as a string.
+
+When KEYWORD appears in DIRECTORIES, each value is a cons cell:
+
+ (VALUE . DIRECTORY)
+
+where VALUE is the regular value, and DIRECTORY is the variable
+`default-directory' for the buffer containing the keyword. This
+is important for values containing relative file names, since the
+function follows SETUPFILE keywords, and may change its working
+directory."
+ (let* ((keywords (cons "SETUPFILE" (mapcar #'upcase keywords)))
+ (unique (mapcar #'upcase unique))
+ (alist (org--collect-keywords-1
+ keywords unique directory
+ (and buffer-file-name (list buffer-file-name))
+ nil)))
+ ;; Re-order results.
+ (dolist (entry alist)
+ (pcase entry
+ (`(,_ . ,(and value (pred consp)))
+ (setcdr entry (nreverse value)))))
+ (nreverse alist)))
+
+(defun org--collect-keywords-1 (keywords unique directory files alist)
+ (org-with-point-at 1
+ (let ((case-fold-search t)
+ (regexp (org-make-options-regexp keywords)))
+ (while (and keywords (re-search-forward regexp nil t))
+ (let ((element (org-element-at-point)))
+ (when (eq 'keyword (org-element-type element))
+ (let ((value (org-element-property :value element)))
+ (pcase (org-element-property :key element)
+ ("SETUPFILE"
+ (when (and (org-string-nw-p value)
+ (not buffer-read-only)) ;FIXME: bug in Gnus?
+ (let* ((uri (org-strip-quotes value))
+ (uri-is-url (org-file-url-p uri))
+ (uri (if uri-is-url
+ uri
+ (expand-file-name uri))))
+ (unless (member uri files)
+ (with-temp-buffer
+ (unless uri-is-url
+ (setq default-directory (file-name-directory uri)))
+ (let ((contents (org-file-contents uri :noerror)))
+ (when contents
+ (insert contents)
+ ;; Fake Org mode: `org-element-at-point'
+ ;; doesn't need full set-up.
(let ((major-mode 'org-mode))
- (org--setup-collect-keywords
- regexp (cons f files) alist)))))))))))))))
- alist)
+ (setq alist
+ (org--collect-keywords-1
+ keywords unique directory
+ (cons uri files)
+ alist))))))))))
+ (keyword
+ (let ((entry (assoc keyword alist))
+ (final
+ (cond ((not (member keyword directory)) value)
+ (buffer-file-name
+ (cons value
+ (file-name-directory buffer-file-name)))
+ (t (cons value default-directory)))))
+ (cond ((member keyword unique)
+ (push (cons keyword final) alist)
+ (setq keywords (remove keyword keywords))
+ (setq regexp (org-make-options-regexp keywords)))
+ ((null entry) (push (list keyword final) alist))
+ (t (push final (cdr entry)))))))))))
+ alist)))
(defun org-tag-string-to-alist (s)
"Return tag alist associated to string S.
@@ -4677,7 +4641,7 @@ already cached in the `org--file-cache' hash table, the download step
is skipped.
If NOERROR is non-nil, ignore the error when unable to read the FILE
-from file or URL.
+from file or URL, and return nil.
If NOCACHE is non-nil, do a fresh fetch of FILE even if cached version
is available. This option applies only if FILE is a URL."
@@ -4701,7 +4665,8 @@ is available. This option applies only if FILE is a URL."
org--file-cache)
(funcall (if noerror #'message #'user-error)
"Unable to fetch file from %S"
- file))))
+ file)
+ nil)))
(t
(with-temp-buffer
(condition-case nil
@@ -4711,7 +4676,8 @@ is available. This option applies only if FILE is a URL."
(file-error
(funcall (if noerror #'message #'user-error)
"Unable to read file %S"
- file))))))))
+ file)
+ nil)))))))
(defun org-extract-log-state-settings (x)
"Extract the log state setting from a TODO keyword string.
@@ -4790,12 +4756,9 @@ This is for getting out of special buffers like capture.")
(require 'time-date)
(unless (fboundp 'time-subtract) (defalias 'time-subtract 'subtract-time))
(require 'easymenu)
-(autoload 'easy-menu-add "easymenu")
(require 'overlay)
-;; (require 'org-macs) moved higher up in the file before it is first used
(require 'org-entities)
-;; (require 'org-compat) moved higher up in the file before it is first used
(require 'org-faces)
(require 'org-list)
(require 'org-pcomplete)
@@ -4829,7 +4792,6 @@ The following commands are available:
(org-install-agenda-files-menu)
(when org-link-descriptive (add-to-invisibility-spec '(org-link)))
(add-to-invisibility-spec '(org-hide-block . t))
- (add-to-invisibility-spec '(org-hide-drawer . t))
(setq-local outline-regexp org-outline-regexp)
(setq-local outline-level 'org-outline-level)
(setq bidi-paragraph-direction 'left-to-right)
@@ -4905,10 +4867,6 @@ The following commands are available:
(regexp . "^[ \t]*#\\+[A-Z_]+:\\(\\s-*\\)\\S-+")
(modes . '(org-mode)))))
- ;; Make isearch reveal context
- (setq-local outline-isearch-open-invisible-function
- (lambda (&rest _) (org-show-context 'isearch)))
-
;; Setup the pcomplete hooks
(setq-local pcomplete-command-completion-function #'org-pcomplete-initial)
(setq-local pcomplete-command-name-function #'org-command-at-point)
@@ -4940,11 +4898,20 @@ The following commands are available:
(when org-startup-with-latex-preview (org-latex-preview '(16)))
(unless org-inhibit-startup-visibility-stuff (org-set-startup-visibility))
(when org-startup-truncated (setq truncate-lines t))
+ (when org-startup-numerated (require 'org-num) (org-num-mode 1))
(when org-startup-indented (require 'org-indent) (org-indent-mode 1))))
+
+ ;; Activate `org-table-header-line-mode'
+ (when org-table-header-line-p
+ (org-table-header-line-mode 1))
;; Try to set `org-hide' face correctly.
(let ((foreground (org-find-invisible-foreground)))
(when foreground
- (set-face-foreground 'org-hide foreground))))
+ (set-face-foreground 'org-hide foreground)))
+ ;; Set face extension as requested.
+ (org--set-faces-extend '(org-block-begin-line org-block-end-line)
+ org-fontify-whole-block-delimiter-line)
+ (org--set-faces-extend org-level-faces org-fontify-whole-heading-line))
;; Update `customize-package-emacs-version-alist'
(add-to-list 'customize-package-emacs-version-alist
@@ -4955,7 +4922,9 @@ The following commands are available:
("8.3" . "26.1")
("9.0" . "26.1")
("9.1" . "26.1")
- ("9.2" . "27.1")))
+ ("9.2" . "27.1")
+ ("9.3" . "27.1")
+ ("9.4" . "27.2")))
(defvar org-mode-transpose-word-syntax-table
(let ((st (make-syntax-table text-mode-syntax-table)))
@@ -5004,8 +4973,6 @@ the rounding returns a past time."
;;;; Font-Lock stuff, including the activators
-(require 'font-lock)
-
(defconst org-match-sexp-depth 3
"Number of stacked braces for sub/superscript matching.")
@@ -5076,9 +5043,10 @@ stacked delimiters is N. Escaping delimiters is not possible."
;; Do not span over cells in table rows.
(not (and (save-match-data (org-match-line "[ \t]*|"))
(string-match-p "|" (match-string 4))))))
- (pcase-let ((`(,_ ,face ,_) (assoc marker org-emphasis-alist)))
+ (pcase-let ((`(,_ ,face ,_) (assoc marker org-emphasis-alist))
+ (m (if org-hide-emphasis-markers 4 2)))
(font-lock-prepend-text-property
- (match-beginning 2) (match-end 2) 'face face)
+ (match-beginning m) (match-end m) 'face face)
(when verbatim?
(org-remove-flyspell-overlays-in
(match-beginning 0) (match-end 0))
@@ -5086,7 +5054,8 @@ stacked delimiters is N. Escaping delimiters is not possible."
'(display t invisible t intangible t)))
(add-text-properties (match-beginning 2) (match-end 2)
'(font-lock-multiline t org-emphasis t))
- (when org-hide-emphasis-markers
+ (when (and org-hide-emphasis-markers
+ (not (org-at-comment-p)))
(add-text-properties (match-end 4) (match-beginning 5)
'(invisible org-link))
(add-text-properties (match-beginning 3) (match-end 3)
@@ -5249,13 +5218,23 @@ by a #."
"Fontify #+ lines and blocks."
(let ((case-fold-search t))
(when (re-search-forward
- "^\\([ \t]*#\\(\\(\\+[a-zA-Z]+:?\\| \\|$\\)\\(_\\([a-zA-Z]+\\)\\)?\\)[ \t]*\\(\\([^ \t\n]*\\)[ \t]*\\(.*\\)\\)\\)"
+ (rx bol (group (zero-or-more (any " \t")) "#"
+ (group (group (or (seq "+" (one-or-more (any "a-zA-Z")) (optional ":"))
+ (any " \t")
+ eol))
+ (optional (group "_" (group (one-or-more (any "a-zA-Z"))))))
+ (zero-or-more (any " \t"))
+ (group (group (zero-or-more (not (any " \t\n"))))
+ (zero-or-more (any " \t"))
+ (group (zero-or-more any)))))
limit t)
(let ((beg (match-beginning 0))
(end-of-beginline (match-end 0))
- (block-start (match-end 0)) ; includes the \n at end of #+begin line
- (block-end nil) ; will include \n after end of block content
- (lang (match-string 7)) ; the language, if it is an src block
+ ;; Including \n at end of #+begin line will include \n
+ ;; after the end of block content.
+ (block-start (match-end 0))
+ (block-end nil)
+ (lang (match-string 7)) ; The language, if it is a source block.
(bol-after-beginline (line-beginning-position 2))
(dc1 (downcase (match-string 2)))
(dc3 (downcase (match-string 3)))
@@ -5265,15 +5244,22 @@ by a #."
((and (match-end 4) (equal dc3 "+begin"))
;; Truly a block
(setq block-type (downcase (match-string 5))
- quoting (member block-type org-protecting-blocks)) ; src, example, export, maybe more
+ ;; Src, example, export, maybe more.
+ quoting (member block-type org-protecting-blocks))
(when (re-search-forward
- (concat "^[ \t]*#\\+end" (match-string 4) "\\>.*")
- nil t) ;; on purpose, we look further than LIMIT
- ;; We do have a matching #+end line
+ (rx-to-string `(group bol (or (seq (one-or-more "*") space)
+ (seq (zero-or-more (any " \t"))
+ "#+end"
+ ,(match-string 4)
+ word-end
+ (zero-or-more any)))))
+ ;; We look further than LIMIT on purpose.
+ nil t)
+ ;; We do have a matching #+end line.
(setq beg-of-endline (match-beginning 0)
end-of-endline (match-end 0)
nl-before-endline (1- (match-beginning 0)))
- (setq block-end (match-beginning 0)) ; includes the final newline.
+ (setq block-end (match-beginning 0)) ; Include the final newline.
(when quoting
(org-remove-flyspell-overlays-in bol-after-beginline nl-before-endline)
(remove-text-properties beg end-of-endline
@@ -5306,10 +5292,14 @@ by a #."
(add-text-properties
beg (if whole-blockline bol-after-beginline end-of-beginline)
'(face org-block-begin-line))
- (add-text-properties
- beg-of-endline
- (min (point-max) (if whole-blockline (min (point-max) (1+ end-of-endline)) end-of-endline))
- '(face org-block-end-line))
+ (unless (eq (char-after beg-of-endline) ?*)
+ (add-text-properties
+ beg-of-endline
+ (if whole-blockline
+ (let ((beg-of-next-line (1+ end-of-endline)))
+ (min (point-max) beg-of-next-line))
+ (min (point-max) end-of-endline))
+ '(face org-block-end-line)))
t))
((member dc1 '("+title:" "+author:" "+email:" "+date:"))
(org-remove-flyspell-overlays-in
@@ -5329,22 +5319,26 @@ by a #."
(org-remove-flyspell-overlays-in (match-end 2) (match-end 0))
(remove-text-properties (match-beginning 0) (match-end 0)
'(display t invisible t intangible t))
- ;; Handle short captions.
+ ;; Handle short captions
(save-excursion
(beginning-of-line)
- (looking-at "\\([ \t]*#\\+caption\\(?:\\[.*\\]\\)?:\\)[ \t]*"))
+ (looking-at (rx (group (zero-or-more (any " \t"))
+ "#+caption"
+ (optional "[" (zero-or-more any) "]")
+ ":")
+ (zero-or-more (any " \t")))))
(add-text-properties (line-beginning-position) (match-end 1)
'(font-lock-fontified t face org-meta-line))
(add-text-properties (match-end 0) (line-end-position)
'(font-lock-fontified t face org-block))
t)
((member dc3 '(" " ""))
- ; Just a comment, the plus was not there
+ ;; Just a comment, the plus was not there
(org-remove-flyspell-overlays-in beg (match-end 0))
(add-text-properties
beg (match-end 0)
'(font-lock-fontified t face font-lock-comment-face)))
- (t ;; just any other in-buffer setting, but not indented
+ (t ;; Just any other in-buffer setting, but not indented
(org-remove-flyspell-overlays-in (match-beginning 0) (match-end 0))
(remove-text-properties (match-beginning 0) (match-end 0)
'(display t invisible t intangible t))
@@ -5355,9 +5349,8 @@ by a #."
(defun org-fontify-drawers (limit)
"Fontify drawers."
(when (re-search-forward org-drawer-regexp limit t)
- (add-text-properties
- (line-beginning-position) (line-beginning-position 2)
- '(font-lock-fontified t face org-drawer))
+ (add-text-properties (1- (match-beginning 1)) (1+ (match-end 1))
+ '(font-lock-fontified t face org-drawer))
(org-remove-flyspell-overlays-in
(line-beginning-position) (line-beginning-position 2))
t))
@@ -5385,8 +5378,8 @@ by a #."
(end-re "\\(\\\\\\]\\|\\(#\\+end_\\|\\\\end{\\)\\S-+\\)")
(extend (lambda (r1 r2 dir)
(let ((re (replace-regexp-in-string "\\(begin\\|end\\)" r1
- (replace-regexp-in-string "[][]" r2
- (match-string-no-properties 0)))))
+ (replace-regexp-in-string "[][]" r2
+ (match-string-no-properties 0)))))
(re-search-forward (regexp-quote re) nil t dir)))))
(save-match-data
(save-excursion
@@ -5482,33 +5475,46 @@ Result depends on variable `org-highlight-latex-and-related'."
(append re-latex re-entities re-sub)
"\\|"))))
-(defun org-do-latex-and-related (_limit)
+(defun org-do-latex-and-related (limit)
"Highlight LaTeX snippets and environments, entities and sub/superscript.
Stop at first highlighted object, if any. Return t if some
highlighting was done, nil otherwise."
(when (org-string-nw-p org-latex-and-related-regexp)
- (catch 'found
- (while (re-search-forward org-latex-and-related-regexp
- nil t) ;; on purpose, we ignore LIMIT
- (unless (cl-some (lambda (f) (memq f '(org-code org-verbatim underline
- org-special-keyword)))
- (save-excursion
- (goto-char (1+ (match-beginning 0)))
- (face-at-point nil t)))
- (let* ((offset (if (memq (char-after (1+ (match-beginning 0)))
- '(?_ ?^))
- 1
- 0))
- (start (+ offset (match-beginning 0)))
- (end (match-end 0)))
- (if (memq 'native org-highlight-latex-and-related)
- (org-src-font-lock-fontify-block "latex" start end)
- (font-lock-prepend-text-property start end
- 'face 'org-latex-and-related))
- (add-text-properties (+ offset (match-beginning 0)) (match-end 0)
- '(font-lock-multiline t)))
- (throw 'found t)))
- nil)))
+ (let ((latex-prefix-re (rx (or "$" "\\(" "\\[")))
+ (blank-line-re (rx (and "\n" (zero-or-more (or " " "\t")) "\n"))))
+ (catch 'found
+ (while (and (< (point) limit)
+ (re-search-forward org-latex-and-related-regexp nil t))
+ (cond
+ ((cl-some (lambda (f)
+ (memq f '(org-code org-verbatim underline
+ org-special-keyword)))
+ (save-excursion
+ (goto-char (1+ (match-beginning 0)))
+ (face-at-point nil t))))
+ ;; Try to limit false positives. In this case, ignore
+ ;; $$...$$, \(...\), and \[...\] LaTeX constructs if they
+ ;; contain an empty line.
+ ((save-excursion
+ (goto-char (match-beginning 0))
+ (and (looking-at-p latex-prefix-re)
+ (save-match-data
+ (re-search-forward blank-line-re (1- (match-end 0)) t)))))
+ (t
+ (let* ((offset (if (memq (char-after (1+ (match-beginning 0)))
+ '(?_ ?^))
+ 1
+ 0))
+ (start (+ offset (match-beginning 0)))
+ (end (match-end 0)))
+ (if (memq 'native org-highlight-latex-and-related)
+ (org-src-font-lock-fontify-block "latex" start end)
+ (font-lock-prepend-text-property start end
+ 'face 'org-latex-and-related))
+ (add-text-properties (+ offset (match-beginning 0)) (match-end 0)
+ '(font-lock-multiline t))
+ (throw 'found t)))))
+ nil))))
(defun org-restart-font-lock ()
"Restart `font-lock-mode', to force refontification."
@@ -5636,15 +5642,22 @@ needs to be inserted at a specific position in the font-lock sequence.")
(list (format org-heading-keyword-regexp-format
org-todo-regexp)
'(2 (org-get-todo-face 2) t))
+ ;; TODO
+ (when org-fontify-todo-headline
+ (list (format org-heading-keyword-regexp-format
+ (concat
+ "\\(?:"
+ (mapconcat 'regexp-quote org-not-done-keywords "\\|")
+ "\\)"))
+ '(2 'org-headline-todo t)))
;; DONE
- (if org-fontify-done-headline
- (list (format org-heading-keyword-regexp-format
- (concat
- "\\(?:"
- (mapconcat 'regexp-quote org-done-keywords "\\|")
- "\\)"))
- '(2 'org-headline-done t))
- nil)
+ (when org-fontify-done-headline
+ (list (format org-heading-keyword-regexp-format
+ (concat
+ "\\(?:"
+ (mapconcat 'regexp-quote org-done-keywords "\\|")
+ "\\)"))
+ '(2 'org-headline-done t)))
;; Priorities
'(org-font-lock-add-priority-faces)
;; Tags
@@ -5778,20 +5791,17 @@ needs to be inserted at a specific position in the font-lock sequence.")
(org-font-lock-ensure)
(buffer-string))))
-(defvar org-m nil)
-(defvar org-l nil)
-(defvar org-f nil)
(defun org-get-level-face (n)
"Get the right face for match N in font-lock matching of headlines."
- (setq org-l (- (match-end 2) (match-beginning 1) 1))
- (when org-odd-levels-only (setq org-l (1+ (/ org-l 2))))
- (if org-cycle-level-faces
- (setq org-f (nth (% (1- org-l) org-n-level-faces) org-level-faces))
- (setq org-f (nth (1- (min org-l org-n-level-faces)) org-level-faces)))
- (cond
- ((eq n 1) (if org-hide-leading-stars 'org-hide org-f))
- ((eq n 2) org-f)
- (t (unless org-level-color-stars-only org-f))))
+ (let* ((org-l0 (- (match-end 2) (match-beginning 1) 1))
+ (org-l (if org-odd-levels-only (1+ (/ org-l0 2)) org-l0))
+ (org-f (if org-cycle-level-faces
+ (nth (% (1- org-l) org-n-level-faces) org-level-faces)
+ (nth (1- (min org-l org-n-level-faces)) org-level-faces))))
+ (cond
+ ((eq n 1) (if org-hide-leading-stars 'org-hide org-f))
+ ((eq n 2) org-f)
+ (t (unless org-level-color-stars-only org-f)))))
(defun org-face-from-face-or-color (context inherit face-or-color)
"Create a face list that inherits INHERIT, but sets the foreground color.
@@ -5826,11 +5836,13 @@ If TAG is a number, get the corresponding match group."
'tag 'org-tag (cdr (assoc tag org-tag-faces)))
'org-tag)))
+(defvar org-priority-regexp) ; defined later in the file
+
(defun org-font-lock-add-priority-faces (limit)
"Add the special priority faces."
- (while (re-search-forward "^\\*+ .*?\\(\\[#\\(.\\)\\]\\)" limit t)
+ (while (re-search-forward org-priority-regexp limit t)
(add-text-properties
- (match-beginning 1) (match-end 1)
+ (match-beginning 1) (1+ (match-end 2))
(list 'face (org-get-priority-face (string-to-char (match-string 2)))
'font-lock-fontified t))))
@@ -5914,7 +5926,7 @@ and subscripts."
"Remove outline overlays that do not contain non-white stuff."
(dolist (o (overlays-at pos))
(and (eq 'outline (overlay-get o 'invisible))
- (not (string-match "\\S-" (buffer-substring (overlay-start o)
+ (not (string-match-p "\\S-" (buffer-substring (overlay-start o)
(overlay-end o))))
(delete-overlay o))))
@@ -5963,21 +5975,37 @@ open and agenda-wise Org files."
;;;; Headlines visibility
(defun org-show-entry ()
- "Show the body directly following this heading.
+ "Show the body directly following its heading.
Show the heading too, if it is currently invisible."
(interactive)
(save-excursion
- (ignore-errors
- (org-back-to-heading t)
- (org-flag-region
- (line-end-position 0)
- (save-excursion
- (if (re-search-forward
- (concat "[\r\n]\\(" org-outline-regexp "\\)") nil t)
- (match-beginning 1)
- (point-max)))
- nil
- 'outline))))
+ (org-back-to-heading-or-point-min t)
+ (org-flag-region
+ (line-end-position 0)
+ (save-excursion
+ (if (re-search-forward
+ (concat "[\r\n]\\(" org-outline-regexp "\\)") nil t)
+ (match-beginning 1)
+ (point-max)))
+ nil
+ 'outline)
+ (org-cycle-hide-drawers 'children)))
+
+(defun org-hide-entry ()
+ "Hide the body directly following its heading."
+ (interactive)
+ (save-excursion
+ (org-back-to-heading-or-point-min t)
+ (when (org-at-heading-p) (forward-line))
+ (org-flag-region
+ (line-end-position 0)
+ (save-excursion
+ (if (re-search-forward
+ (concat "[\r\n]" org-outline-regexp) nil t)
+ (line-end-position 0)
+ (point-max)))
+ t
+ 'outline)))
(defun org-show-children (&optional level)
"Show all direct subheadings of this heading.
@@ -5985,36 +6013,37 @@ Prefix arg LEVEL is how many levels below the current level
should be shown. Default is enough to cause the following
heading to appear."
(interactive "p")
- (save-excursion
- (org-back-to-heading t)
- (let* ((current-level (funcall outline-level))
- (max-level (org-get-valid-level
- current-level
- (if level (prefix-numeric-value level) 1)))
- (end (save-excursion (org-end-of-subtree t t)))
- (regexp-fmt "^\\*\\{%d,%s\\}\\(?: \\|$\\)")
- (past-first-child nil)
- ;; Make sure to skip inlinetasks.
- (re (format regexp-fmt
- current-level
- (cond
- ((not (featurep 'org-inlinetask)) "")
- (org-odd-levels-only (- (* 2 org-inlinetask-min-level)
- 3))
- (t (1- org-inlinetask-min-level))))))
- ;; Display parent heading.
- (org-flag-heading nil)
- (forward-line)
- ;; Display children. First child may be deeper than expected
- ;; MAX-LEVEL. Since we want to display it anyway, adjust
- ;; MAX-LEVEL accordingly.
- (while (re-search-forward re end t)
- (unless past-first-child
- (setq re (format regexp-fmt
- current-level
- (max (funcall outline-level) max-level)))
- (setq past-first-child t))
- (org-flag-heading nil)))))
+ (unless (org-before-first-heading-p)
+ (save-excursion
+ (org-with-limited-levels (org-back-to-heading t))
+ (let* ((current-level (funcall outline-level))
+ (max-level (org-get-valid-level
+ current-level
+ (if level (prefix-numeric-value level) 1)))
+ (end (save-excursion (org-end-of-subtree t t)))
+ (regexp-fmt "^\\*\\{%d,%s\\}\\(?: \\|$\\)")
+ (past-first-child nil)
+ ;; Make sure to skip inlinetasks.
+ (re (format regexp-fmt
+ current-level
+ (cond
+ ((not (featurep 'org-inlinetask)) "")
+ (org-odd-levels-only (- (* 2 org-inlinetask-min-level)
+ 3))
+ (t (1- org-inlinetask-min-level))))))
+ ;; Display parent heading.
+ (org-flag-heading nil)
+ (forward-line)
+ ;; Display children. First child may be deeper than expected
+ ;; MAX-LEVEL. Since we want to display it anyway, adjust
+ ;; MAX-LEVEL accordingly.
+ (while (re-search-forward re end t)
+ (unless past-first-child
+ (setq re (format regexp-fmt
+ current-level
+ (max (funcall outline-level) max-level)))
+ (setq past-first-child t))
+ (org-flag-heading nil))))))
(defun org-show-subtree ()
"Show everything after this heading at deeper levels."
@@ -6022,117 +6051,135 @@ heading to appear."
(org-flag-region
(point) (save-excursion (org-end-of-subtree t t)) nil 'outline))
-;;;; Blocks visibility
+;;;; Blocks and drawers visibility
-(defun org-hide-block-toggle-maybe ()
- "Toggle visibility of block at point.
-Unlike to `org-hide-block-toggle', this function does not throw
-an error. Return a non-nil value when toggling is successful."
- (interactive)
- (ignore-errors (org-hide-block-toggle)))
+(defun org--hide-wrapper-toggle (element category force no-error)
+ "Toggle visibility for ELEMENT.
+
+ELEMENT is a block or drawer type parsed element. CATEGORY is
+either `block' or `drawer'. When FORCE is `off', show the block
+or drawer. If it is non-nil, hide it unconditionally. Throw an
+error when not at a block or drawer, unless NO-ERROR is non-nil.
+
+Return a non-nil value when toggling is successful."
+ (let ((type (org-element-type element)))
+ (cond
+ ((memq type
+ (pcase category
+ (`drawer '(drawer property-drawer))
+ (`block '(center-block
+ comment-block dynamic-block example-block export-block
+ quote-block special-block src-block verse-block))
+ (_ (error "Unknown category: %S" category))))
+ (let* ((post (org-element-property :post-affiliated element))
+ (start (save-excursion
+ (goto-char post)
+ (line-end-position)))
+ (end (save-excursion
+ (goto-char (org-element-property :end element))
+ (skip-chars-backward " \t\n")
+ (line-end-position))))
+ ;; Do nothing when not before or at the block opening line or
+ ;; at the block closing line.
+ (unless (let ((eol (line-end-position)))
+ (and (> eol start) (/= eol end)))
+ (let* ((spec (if (eq category 'block) 'org-hide-block 'outline))
+ (flag
+ (cond ((eq force 'off) nil)
+ (force t)
+ ((eq spec (get-char-property start 'invisible)) nil)
+ (t t))))
+ (org-flag-region start end flag spec))
+ ;; When the block is hidden away, make sure point is left in
+ ;; a visible part of the buffer.
+ (when (invisible-p (max (1- (point)) (point-min)))
+ (goto-char post))
+ ;; Signal success.
+ t)))
+ (no-error nil)
+ (t
+ (user-error (if (eq category 'drawer)
+ "Not at a drawer"
+ "Not at a block"))))))
-(defun org-hide-block-toggle (&optional force)
+(defun org-hide-block-toggle (&optional force no-error element)
"Toggle the visibility of the current block.
+
When optional argument FORCE is `off', make block visible. If it
is non-nil, hide it unconditionally. Throw an error when not at
-a block. Return a non-nil value when toggling is successful."
+a block, unless NO-ERROR is non-nil. When optional argument
+ELEMENT is provided, consider it instead of the current block.
+
+Return a non-nil value when toggling is successful."
(interactive)
- (let ((element (org-element-at-point)))
- (unless (memq (org-element-type element)
- '(center-block comment-block dynamic-block example-block
- export-block quote-block special-block
- src-block verse-block))
- (user-error "Not at a block"))
- (let* ((post (org-element-property :post-affiliated element))
- (start (save-excursion
- (goto-char post)
- (line-end-position)))
- (end (save-excursion
- (goto-char (org-element-property :end element))
- (skip-chars-backward " \t\n")
- (line-end-position))))
- ;; Do nothing when not before or at the block opening line or at
- ;; the block closing line.
- (unless (let ((eol (line-end-position))) (and (> eol start) (/= eol end)))
- (cond ((eq force 'off)
- (org-flag-region start end nil 'org-hide-block))
- (force
- (org-flag-region start end t 'org-hide-block))
- ((eq (get-char-property start 'invisible) 'org-hide-block)
- (org-flag-region start end nil 'org-hide-block))
- (t
- (org-flag-region start end t 'org-hide-block)))
- ;; When the block is hidden away, make sure point is left in
- ;; a visible part of the buffer.
- (when (invisible-p (max (1- (point)) (point-min)))
- (goto-char post))
- ;; Signal success.
- t))))
+ (org--hide-wrapper-toggle
+ (or element (org-element-at-point)) 'block force no-error))
-(defun org-hide-block-toggle-all ()
- "Toggle the visibility of all blocks in the current buffer."
- (org-block-map 'org-hide-block-toggle))
+(defun org-hide-drawer-toggle (&optional force no-error element)
+ "Toggle the visibility of the current drawer.
+
+When optional argument FORCE is `off', make drawer visible. If
+it is non-nil, hide it unconditionally. Throw an error when not
+at a drawer, unless NO-ERROR is non-nil. When optional argument
+ELEMENT is provided, consider it instead of the current drawer.
+
+Return a non-nil value when toggling is successful."
+ (interactive)
+ (org--hide-wrapper-toggle
+ (or element (org-element-at-point)) 'drawer force no-error))
(defun org-hide-block-all ()
"Fold all blocks in the current buffer."
(interactive)
(org-show-all '(blocks))
- (org-block-map 'org-hide-block-toggle-maybe))
-
-;;;; Drawers visibility
+ (org-block-map 'org-hide-block-toggle))
-(defun org-cycle-hide-drawers (state &optional exceptions)
+(defun org-hide-drawer-all ()
+ "Fold all drawers in the current buffer."
+ (save-excursion
+ (goto-char (point-min))
+ (while (re-search-forward org-drawer-regexp nil t)
+ (let* ((pair (get-char-property-and-overlay (line-beginning-position)
+ 'invisible))
+ (o (cdr-safe pair)))
+ (if (overlayp o) (goto-char (overlay-end o)) ;invisible drawer
+ (pcase (get-char-property-and-overlay (point) 'invisible)
+ (`(outline . ,o) (goto-char (overlay-end o))) ;already folded
+ (_
+ (let* ((drawer (org-element-at-point))
+ (type (org-element-type drawer)))
+ (when (memq type '(drawer property-drawer))
+ (org-hide-drawer-toggle t nil drawer)
+ ;; Make sure to skip drawer entirely or we might flag it
+ ;; another time when matching its ending line with
+ ;; `org-drawer-regexp'.
+ (goto-char (org-element-property :end drawer)))))))))))
+
+(defun org-cycle-hide-drawers (state)
"Re-hide all drawers after a visibility state change.
STATE should be one of the symbols listed in the docstring of
-`org-cycle-hook'. When non-nil, optional argument EXCEPTIONS is
-a list of strings specifying which drawers should not be hidden."
+`org-cycle-hook'."
(when (and (derived-mode-p 'org-mode)
(not (memq state '(overview folded contents))))
- (save-excursion
- (let* ((globalp (eq state 'all))
- (beg (if globalp (point-min) (point)))
- (end (if globalp (point-max)
- (if (eq state 'children)
- (save-excursion (outline-next-heading) (point))
- (org-end-of-subtree t)))))
+ (let* ((global? (eq state 'all))
+ (beg (if global? (point-min) (line-beginning-position)))
+ (end (cond (global? (point-max))
+ ((eq state 'children) (org-entry-end-position))
+ (t (save-excursion (org-end-of-subtree t t))))))
+ (save-excursion
(goto-char beg)
- (while (re-search-forward org-drawer-regexp (max end (point)) t)
- (unless (member-ignore-case (match-string 1) exceptions)
- (let ((drawer (org-element-at-point)))
- (when (memq (org-element-type drawer) '(drawer property-drawer))
- (org-flag-drawer t drawer)
- ;; Make sure to skip drawer entirely or we might flag
- ;; it another time when matching its ending line with
- ;; `org-drawer-regexp'.
- (goto-char (org-element-property :end drawer))))))))))
-
-(defun org-flag-drawer (flag &optional element beg end)
- "When FLAG is non-nil, hide the drawer we are at.
-Otherwise make it visible.
-
-When optional argument ELEMENT is a parsed drawer, as returned by
-`org-element-at-point', hide or show that drawer instead.
-
-When buffer positions BEG and END are provided, hide or show that
-region as a drawer without further ado."
- (if (and beg end) (org-flag-region beg end flag 'org-hide-drawer)
- (let ((drawer (or element
- (and (save-excursion
- (beginning-of-line)
- (looking-at-p org-drawer-regexp))
- (org-element-at-point)))))
- (when (memq (org-element-type drawer) '(drawer property-drawer))
- (let ((post (org-element-property :post-affiliated drawer)))
- (org-flag-region
- (save-excursion (goto-char post) (line-end-position))
- (save-excursion (goto-char (org-element-property :end drawer))
- (skip-chars-backward " \t\n")
- (line-end-position))
- flag 'org-hide-drawer)
- ;; When the drawer is hidden away, make sure point lies in
- ;; a visible part of the buffer.
- (when (invisible-p (max (1- (point)) (point-min)))
- (goto-char post)))))))
+ (while (re-search-forward org-drawer-regexp end t)
+ (pcase (get-char-property-and-overlay (point) 'invisible)
+ ;; Do not fold already folded drawers.
+ (`(outline . ,o) (goto-char (overlay-end o)))
+ (_
+ (let ((drawer (org-element-at-point)))
+ (when (memq (org-element-type drawer) '(drawer property-drawer))
+ (org-hide-drawer-toggle t nil drawer)
+ ;; Make sure to skip drawer entirely or we might flag
+ ;; it another time when matching its ending line with
+ ;; `org-drawer-regexp'.
+ (goto-char (org-element-property :end drawer)))))))))))
;;;; Visibility cycling
@@ -6147,13 +6194,31 @@ By default, the function expands headings, blocks and drawers.
When optional argument TYPE is a list of symbols among `blocks',
`drawers' and `headings', to only expand one specific type."
(interactive)
- (dolist (type (or types '(blocks drawers headings)))
- (org-flag-region (point-min) (point-max) nil
- (pcase type
- (`blocks 'org-hide-block)
- (`drawers 'org-hide-drawer)
- (`headings 'outline)
- (_ (error "Invalid type: %S" type))))))
+ (let ((types (or types '(blocks drawers headings))))
+ (when (memq 'blocks types)
+ (org-flag-region (point-min) (point-max) nil 'org-hide-block))
+ (cond
+ ;; Fast path. Since headings and drawers share the same
+ ;; invisible spec, clear everything in one go.
+ ((and (memq 'headings types)
+ (memq 'drawers types))
+ (org-flag-region (point-min) (point-max) nil 'outline))
+ ((memq 'headings types)
+ (org-flag-region (point-min) (point-max) nil 'outline)
+ (org-cycle-hide-drawers 'all))
+ ((memq 'drawers types)
+ (save-excursion
+ (goto-char (point-min))
+ (while (re-search-forward org-drawer-regexp nil t)
+ (let* ((pair (get-char-property-and-overlay (line-beginning-position)
+ 'invisible))
+ (o (cdr-safe pair)))
+ (if (overlayp o) (goto-char (overlay-end o))
+ (pcase (get-char-property-and-overlay (point) 'invisible)
+ (`(outline . ,o)
+ (goto-char (overlay-end o))
+ (delete-overlay o))
+ (_ nil))))))))))
;;;###autoload
(defun org-cycle (&optional arg)
@@ -6204,11 +6269,11 @@ When point is not at the beginning of a headline, execute the global
binding for `TAB', which is re-indenting the line. See the option
`org-cycle-emulate-tab' for details.
-As a special case, if point is at the beginning of the buffer and there is
-no headline in line 1, this function will act as if called with prefix arg
-\(`\\[universal-argument] TAB', same as `S-TAB') also when called without \
-prefix arg, but only
-if the variable `org-cycle-global-at-bob' is t."
+As a special case, if point is at the very beginning of the buffer, if
+there is no headline there, and if the variable `org-cycle-global-at-bob'
+is non-nil, this function acts as if called with prefix argument \
+\(`\\[universal-argument] TAB',
+same as `S-TAB') also when called without prefix argument."
(interactive "P")
(org-load-modules-maybe)
(unless (or (run-hook-with-args-until-success 'org-tab-first-hook)
@@ -6220,63 +6285,22 @@ if the variable `org-cycle-global-at-bob' is t."
(and (boundp 'org-inlinetask-min-level)
org-inlinetask-min-level
(1- org-inlinetask-min-level))))
- (nstars (and limit-level
- (if org-odd-levels-only
- (and limit-level (1- (* limit-level 2)))
- limit-level)))
+ (nstars
+ (and limit-level
+ (if org-odd-levels-only
+ (1- (* 2 limit-level))
+ limit-level)))
(org-outline-regexp
- (if (not (derived-mode-p 'org-mode))
- outline-regexp
- (concat "\\*" (if nstars (format "\\{1,%d\\} " nstars) "+ "))))
- (bob-special (and org-cycle-global-at-bob (not arg) (bobp)
- (not (looking-at org-outline-regexp))))
- (org-cycle-hook
- (if bob-special
- (delq 'org-optimize-window-after-visibility-change
- (copy-sequence org-cycle-hook))
- org-cycle-hook))
- (pos (point)))
-
+ (format "\\*%s " (if nstars (format "\\{1,%d\\}" nstars) "+"))))
(cond
-
((equal arg '(16))
(setq last-command 'dummy)
(org-set-startup-visibility)
(org-unlogged-message "Startup visibility, plus VISIBILITY properties"))
-
((equal arg '(64))
(org-show-all)
(org-unlogged-message "Entire buffer visible, including drawers"))
-
((equal arg '(4)) (org-cycle-internal-global))
-
- ;; Try hiding block at point.
- ((org-hide-block-toggle-maybe))
-
- ;; Try cdlatex TAB completion
- ((org-try-cdlatex-tab))
-
- ;; Table: enter it or move to the next field.
- ((org-at-table-p 'any)
- (if (org-at-table.el-p)
- (message "%s" (substitute-command-keys "\\<org-mode-map>\
-Use `\\[org-edit-special]' to edit table.el tables"))
- (if arg (org-table-edit-field t)
- (org-table-justify-field-maybe)
- (call-interactively 'org-table-next-field))))
-
- ((run-hook-with-args-until-success 'org-tab-after-check-for-table-hook))
-
- ;; Global cycling: delegate to `org-cycle-internal-global'.
- (bob-special (org-cycle-internal-global))
-
- ;; Drawers: delegate to `org-flag-drawer'.
- ((save-excursion
- (beginning-of-line 1)
- (looking-at org-drawer-regexp))
- (org-flag-drawer ; toggle block visibility
- (not (get-char-property (match-end 0) 'invisible))))
-
;; Show-subtree, ARG levels up from here.
((integerp arg)
(save-excursion
@@ -6284,52 +6308,79 @@ Use `\\[org-edit-special]' to edit table.el tables"))
(outline-up-heading (if (< arg 0) (- arg)
(- (funcall outline-level) arg)))
(org-show-subtree)))
-
+ ;; Global cycling at BOB: delegate to `org-cycle-internal-global'.
+ ((and org-cycle-global-at-bob
+ (bobp)
+ (not (looking-at org-outline-regexp)))
+ (let ((org-cycle-hook
+ (remq 'org-optimize-window-after-visibility-change
+ org-cycle-hook)))
+ (org-cycle-internal-global)))
+ ;; Try CDLaTeX TAB completion.
+ ((org-try-cdlatex-tab))
;; Inline task: delegate to `org-inlinetask-toggle-visibility'.
((and (featurep 'org-inlinetask)
(org-inlinetask-at-task-p)
(or (bolp) (not (eq org-cycle-emulate-tab 'exc-hl-bol))))
(org-inlinetask-toggle-visibility))
-
- ;; At an item/headline: delegate to `org-cycle-internal-local'.
- ((and (or (and org-cycle-include-plain-lists (org-at-item-p))
- (save-excursion (move-beginning-of-line 1)
- (looking-at org-outline-regexp)))
- (or (bolp) (not (eq org-cycle-emulate-tab 'exc-hl-bol))))
- (org-cycle-internal-local))
-
- ;; From there: TAB emulation and template completion.
- (buffer-read-only (org-back-to-heading))
-
- ((run-hook-with-args-until-success
- 'org-tab-after-check-for-cycling-hook))
-
- ((run-hook-with-args-until-success
- 'org-tab-before-tab-emulation-hook))
-
- ((and (eq org-cycle-emulate-tab 'exc-hl-bol)
- (or (not (bolp))
- (not (looking-at org-outline-regexp))))
- (call-interactively (global-key-binding "\t")))
-
- ((if (and (memq org-cycle-emulate-tab '(white whitestart))
- (save-excursion (beginning-of-line 1) (looking-at "[ \t]*"))
- (or (and (eq org-cycle-emulate-tab 'white)
- (= (match-end 0) (point-at-eol)))
- (and (eq org-cycle-emulate-tab 'whitestart)
- (>= (match-end 0) pos))))
- t
- (eq org-cycle-emulate-tab t))
- (call-interactively (global-key-binding "\t")))
-
- (t (save-excursion
- (org-back-to-heading)
- (org-cycle)))))))
+ (t
+ (let ((pos (point))
+ (element (org-element-at-point)))
+ (cond
+ ;; Try toggling visibility for block at point.
+ ((org-hide-block-toggle nil t element))
+ ;; Try toggling visibility for drawer at point.
+ ((org-hide-drawer-toggle nil t element))
+ ;; Table: enter it or move to the next field.
+ ((and (org-match-line "[ \t]*[|+]")
+ (org-element-lineage element '(table) t))
+ (if (and (eq 'table (org-element-type element))
+ (eq 'table.el (org-element-property :type element)))
+ (message (substitute-command-keys "\\<org-mode-map>\
+Use `\\[org-edit-special]' to edit table.el tables"))
+ (org-table-justify-field-maybe)
+ (call-interactively #'org-table-next-field)))
+ ((run-hook-with-args-until-success
+ 'org-tab-after-check-for-table-hook))
+ ;; At an item/headline: delegate to `org-cycle-internal-local'.
+ ((and (or (and org-cycle-include-plain-lists
+ (let ((item (org-element-lineage element
+ '(item plain-list)
+ t)))
+ (and item
+ (= (line-beginning-position)
+ (org-element-property :post-affiliated
+ item)))))
+ (org-match-line org-outline-regexp))
+ (or (bolp) (not (eq org-cycle-emulate-tab 'exc-hl-bol))))
+ (org-cycle-internal-local))
+ ;; From there: TAB emulation and template completion.
+ (buffer-read-only (org-back-to-heading))
+ ((run-hook-with-args-until-success
+ 'org-tab-after-check-for-cycling-hook))
+ ((run-hook-with-args-until-success
+ 'org-tab-before-tab-emulation-hook))
+ ((and (eq org-cycle-emulate-tab 'exc-hl-bol)
+ (or (not (bolp))
+ (not (looking-at org-outline-regexp))))
+ (call-interactively (global-key-binding (kbd "TAB"))))
+ ((or (eq org-cycle-emulate-tab t)
+ (and (memq org-cycle-emulate-tab '(white whitestart))
+ (save-excursion (beginning-of-line 1) (looking-at "[ \t]*"))
+ (or (and (eq org-cycle-emulate-tab 'white)
+ (= (match-end 0) (point-at-eol)))
+ (and (eq org-cycle-emulate-tab 'whitestart)
+ (>= (match-end 0) pos)))))
+ (call-interactively (global-key-binding (kbd "TAB"))))
+ (t
+ (save-excursion
+ (org-back-to-heading)
+ (org-cycle))))))))))
(defun org-cycle-internal-global ()
"Do the global cycling action."
;; Hack to avoid display of messages for .org attachments in Gnus
- (let ((ga (string-match "\\*fontification" (buffer-name))))
+ (let ((ga (string-match-p "\\*fontification" (buffer-name))))
(cond
((and (eq last-command this-command)
(eq org-cycle-global-status 'overview))
@@ -6377,19 +6428,23 @@ Use `\\[org-edit-special]' to edit table.el tables"))
(setq has-children (org-list-has-child-p (point) struct)))
(org-back-to-heading)
(setq eoh (save-excursion (outline-end-of-heading) (point)))
- (setq eos (save-excursion (org-end-of-subtree t t)
- (when (bolp) (backward-char)) (point)))
+ (setq eos (save-excursion
+ (org-end-of-subtree t t)
+ (unless (eobp) (forward-char -1))
+ (point)))
(setq has-children
- (or (save-excursion
- (let ((level (funcall outline-level)))
- (outline-next-heading)
- (and (org-at-heading-p t)
- (> (funcall outline-level) level))))
- (save-excursion
- (org-list-search-forward (org-item-beginning-re) eos t)))))
+ (or
+ (save-excursion
+ (let ((level (funcall outline-level)))
+ (outline-next-heading)
+ (and (org-at-heading-p t)
+ (> (funcall outline-level) level))))
+ (and (eq org-cycle-include-plain-lists 'integrate)
+ (save-excursion
+ (org-list-search-forward (org-item-beginning-re) eos t))))))
;; Determine end invisible part of buffer (EOL)
(beginning-of-line 2)
- (while (and (not (eobp)) ;This is like `next-line'.
+ (while (and (not (eobp)) ;this is like `next-line'
(get-char-property (1- (point)) 'invisible))
(goto-char (next-single-char-property-change (point) 'invisible))
(and (eolp) (beginning-of-line 2)))
@@ -6467,18 +6522,15 @@ Use `\\[org-edit-special]' to edit table.el tables"))
With `\\[universal-argument]' prefix ARG, switch to startup visibility.
With a numeric prefix, show all headlines up to that level."
(interactive "P")
- (let ((org-cycle-include-plain-lists
- (if (derived-mode-p 'org-mode) org-cycle-include-plain-lists nil)))
- (cond
- ((integerp arg)
- (org-show-all '(headings blocks))
- (outline-hide-sublevels arg)
- (setq org-cycle-global-status 'contents))
- ((equal arg '(4))
- (org-set-startup-visibility)
- (org-unlogged-message "Startup visibility, plus VISIBILITY properties."))
- (t
- (org-cycle '(4))))))
+ (cond
+ ((integerp arg)
+ (org-content arg)
+ (setq org-cycle-global-status 'contents))
+ ((equal arg '(4))
+ (org-set-startup-visibility)
+ (org-unlogged-message "Startup visibility, plus VISIBILITY properties."))
+ (t
+ (org-cycle '(4)))))
(defun org-set-startup-visibility ()
"Set the visibility required by startup options and properties."
@@ -6526,51 +6578,60 @@ With a numeric prefix, show all headlines up to that level."
(org-end-of-subtree)))))))
(defun org-overview ()
- "Switch to overview mode, showing only top-level headlines.
-This shows all headlines with a level equal or greater than the level
-of the first headline in the buffer. This is important, because if the
-first headline is not level one, then (hide-sublevels 1) gives confusing
-results."
+ "Switch to overview mode, showing only top-level headlines."
(interactive)
+ (org-show-all '(headings drawers))
(save-excursion
- (let ((level
- (save-excursion
- (goto-char (point-min))
- (when (re-search-forward org-outline-regexp-bol nil t)
- (goto-char (match-beginning 0))
- (funcall outline-level)))))
- (and level (outline-hide-sublevels level)))))
+ (goto-char (point-min))
+ (when (re-search-forward org-outline-regexp-bol nil t)
+ (let* ((last (line-end-position))
+ (level (- (match-end 0) (match-beginning 0) 1))
+ (regexp (format "^\\*\\{1,%d\\} " level)))
+ (while (re-search-forward regexp nil :move)
+ (org-flag-region last (line-end-position 0) t 'outline)
+ (setq last (line-end-position))
+ (setq level (- (match-end 0) (match-beginning 0) 1))
+ (setq regexp (format "^\\*\\{1,%d\\} " level)))
+ (org-flag-region last (point) t 'outline)))))
(defun org-content (&optional arg)
"Show all headlines in the buffer, like a table of contents.
With numerical argument N, show content up to level N."
- (interactive "P")
- (org-overview)
+ (interactive "p")
+ (org-show-all '(headings drawers))
(save-excursion
- ;; Visit all headings and show their offspring
- (and (integerp arg) (org-overview))
(goto-char (point-max))
- (catch 'exit
- (while (and (progn (condition-case nil
- (outline-previous-visible-heading 1)
- (error (goto-char (point-min))))
- t)
- (looking-at org-outline-regexp))
- (if (integerp arg)
- (org-show-children (1- arg))
- (outline-show-branches))
- (when (bobp) (throw 'exit nil))))))
-
+ (let ((regexp (if (and (wholenump arg) (> arg 0))
+ (format "^\\*\\{1,%d\\} " arg)
+ "^\\*+ "))
+ (last (point)))
+ (while (re-search-backward regexp nil t)
+ (org-flag-region (line-end-position) last t 'outline)
+ (setq last (line-end-position 0))))))
+
+(defvar org-scroll-position-to-restore nil
+ "Temporarily store scroll position to restore.")
(defun org-optimize-window-after-visibility-change (state)
"Adjust the window after a change in outline visibility.
This function is the default value of the hook `org-cycle-hook'."
(when (get-buffer-window (current-buffer))
- (cond
- ((eq state 'content) nil)
- ((eq state 'all) nil)
- ((eq state 'folded) nil)
- ((eq state 'children) (or (org-subtree-end-visible-p) (recenter 1)))
- ((eq state 'subtree) (or (org-subtree-end-visible-p) (recenter 1))))))
+ (let ((repeat (eq last-command this-command)))
+ (unless repeat
+ (setq org-scroll-position-to-restore nil))
+ (cond
+ ((eq state 'content) nil)
+ ((eq state 'all) nil)
+ ((and org-scroll-position-to-restore repeat
+ (eq state 'folded))
+ (set-window-start nil org-scroll-position-to-restore))
+ ((eq state 'folded) nil)
+ ((eq state 'children)
+ (setq org-scroll-position-to-restore (window-start))
+ (or (org-subtree-end-visible-p) (recenter 1)))
+ ((eq state 'subtree)
+ (unless repeat
+ (setq org-scroll-position-to-restore (window-start)))
+ (or (org-subtree-end-visible-p) (recenter 1)))))))
(defun org-clean-visibility-after-subtree-move ()
"Fix visibility issues after moving a subtree."
@@ -6671,8 +6732,7 @@ information."
;; If point is hidden within a drawer or a block, make sure to
;; expose it.
(dolist (o (overlays-at (point)))
- (when (memq (overlay-get o 'invisible)
- '(org-hide-block org-hide-drawer outline))
+ (when (memq (overlay-get o 'invisible) '(org-hide-block outline))
(delete-overlay o)))
(unless (org-before-first-heading-p)
(org-with-limited-levels
@@ -6785,7 +6845,7 @@ frame is not changed."
(pop-to-buffer ibuf))
(t (error "Invalid value")))
(narrow-to-region beg end)
- (org-show-all '(headings blocks))
+ (org-show-all '(headings drawers blocks))
(goto-char pos)
(run-hook-with-args 'org-cycle-hook 'all)
(and (window-live-p cwin) (select-window cwin))))
@@ -6812,27 +6872,6 @@ frame is not changed."
;;; Inserting headlines
-(defun org--line-empty-p (n)
- "Is the Nth next line empty?
-
-Counts the current line as N = 1 and the previous line as N = 0;
-see `beginning-of-line'."
- (save-excursion
- (and (not (bobp))
- (or (beginning-of-line n) t)
- (save-match-data
- (looking-at "[ \t]*$")))))
-
-(defun org-previous-line-empty-p ()
- "Is the previous line a blank line?
-When NEXT is non-nil, check the next line instead."
- (org--line-empty-p 0))
-
-(defun org-next-line-empty-p ()
- "Is the previous line a blank line?
-When NEXT is non-nil, check the next line instead."
- (org--line-empty-p 2))
-
(defun org--blank-before-heading-p (&optional parent)
"Non-nil when an empty line should precede a new heading here.
When optional argument PARENT is non-nil, consider parent
@@ -7344,9 +7383,17 @@ Assume point is at a heading or an inlinetask beginning."
(when (looking-at org-property-drawer-re)
(goto-char (match-end 0))
(forward-line)
- (save-excursion (org-indent-region (match-beginning 0) (match-end 0))))
+ (org-indent-region (match-beginning 0) (match-end 0)))
+ (when (looking-at org-logbook-drawer-re)
+ (let ((end-marker (move-marker (make-marker) (match-end 0)))
+ (col (+ (current-indentation) diff)))
+ (when (wholenump col)
+ (while (< (point) end-marker)
+ (indent-line-to col)
+ (forward-line)))))
(catch 'no-shift
- (when (zerop diff) (throw 'no-shift nil))
+ (when (or (zerop diff) (not (eq org-adapt-indentation t)))
+ (throw 'no-shift nil))
;; If DIFF is negative, first check if a shift is possible at all
;; (e.g., it doesn't break structure). This can only happen if
;; some contents are not properly indented.
@@ -7761,8 +7808,9 @@ If yes, remember the marker and the distance to BEG."
"Narrow to the subtree at point or widen a narrowed buffer."
(interactive)
(if (buffer-narrowed-p)
- (widen)
- (org-narrow-to-subtree)))
+ (progn (widen) (message "Buffer widen"))
+ (org-narrow-to-subtree)
+ (message "Buffer narrowed to current subtree")))
(defun org-narrow-to-block ()
"Narrow buffer to the current block."
@@ -7843,7 +7891,8 @@ with the original repeater."
(nmin 1)
(nmax n)
(n-no-remove -1)
- (idprop (org-entry-get nil "ID")))
+ (org-id-overriding-file-name (buffer-file-name (buffer-base-buffer)))
+ (idprop (org-entry-get beg "ID")))
(when (and doshift
(string-match-p "<[^<>\n]+ [.+]?\\+[0-9]+[hdwmy][^<>\n]*>"
template))
@@ -7885,6 +7934,131 @@ with the original repeater."
(buffer-string)))))
(goto-char beg)))
+;;; Outline path
+
+(defvar org-outline-path-cache nil
+ "Alist between buffer positions and outline paths.
+It value is an alist (POSITION . PATH) where POSITION is the
+buffer position at the beginning of an entry and PATH is a list
+of strings describing the outline path for that entry, in reverse
+order.")
+
+(defun org--get-outline-path-1 (&optional use-cache)
+ "Return outline path to current headline.
+
+Outline path is a list of strings, in reverse order. When
+optional argument USE-CACHE is non-nil, make use of a cache. See
+`org-get-outline-path' for details.
+
+Assume buffer is widened and point is on a headline."
+ (or (and use-cache (cdr (assq (point) org-outline-path-cache)))
+ (let ((p (point))
+ (heading (let ((case-fold-search nil))
+ (looking-at org-complex-heading-regexp)
+ (if (not (match-end 4)) ""
+ ;; Remove statistics cookies.
+ (org-trim
+ (org-link-display-format
+ (replace-regexp-in-string
+ "\\[[0-9]+%\\]\\|\\[[0-9]+/[0-9]+\\]" ""
+ (match-string-no-properties 4))))))))
+ (if (org-up-heading-safe)
+ (let ((path (cons heading (org--get-outline-path-1 use-cache))))
+ (when use-cache
+ (push (cons p path) org-outline-path-cache))
+ path)
+ ;; This is a new root node. Since we assume we are moving
+ ;; forward, we can drop previous cache so as to limit number
+ ;; of associations there.
+ (let ((path (list heading)))
+ (when use-cache (setq org-outline-path-cache (list (cons p path))))
+ path)))))
+
+(defun org-get-outline-path (&optional with-self use-cache)
+ "Return the outline path to the current entry.
+
+An outline path is a list of ancestors for current headline, as
+a list of strings. Statistics cookies are removed and links are
+replaced with their description, if any, or their path otherwise.
+
+When optional argument WITH-SELF is non-nil, the path also
+includes the current headline.
+
+When optional argument USE-CACHE is non-nil, cache outline paths
+between calls to this function so as to avoid backtracking. This
+argument is useful when planning to find more than one outline
+path in the same document. In that case, there are two
+conditions to satisfy:
+ - `org-outline-path-cache' is set to nil before starting the
+ process;
+ - outline paths are computed by increasing buffer positions."
+ (org-with-wide-buffer
+ (and (or (and with-self (org-back-to-heading t))
+ (org-up-heading-safe))
+ (reverse (org--get-outline-path-1 use-cache)))))
+
+(defun org-format-outline-path (path &optional width prefix separator)
+ "Format the outline path PATH for display.
+WIDTH is the maximum number of characters that is available.
+PREFIX is a prefix to be included in the returned string,
+such as the file name.
+SEPARATOR is inserted between the different parts of the path,
+the default is \"/\"."
+ (setq width (or width 79))
+ (setq path (delq nil path))
+ (unless (> width 0)
+ (user-error "Argument `width' must be positive"))
+ (setq separator (or separator "/"))
+ (let* ((org-odd-levels-only nil)
+ (fpath (concat
+ prefix (and prefix path separator)
+ (mapconcat
+ (lambda (s) (replace-regexp-in-string "[ \t]+\\'" "" s))
+ (cl-loop for head in path
+ for n from 0
+ collect (org-add-props
+ head nil 'face
+ (nth (% n org-n-level-faces) org-level-faces)))
+ separator))))
+ (when (> (length fpath) width)
+ (if (< width 7)
+ ;; It's unlikely that `width' will be this small, but don't
+ ;; waste characters by adding ".." if it is.
+ (setq fpath (substring fpath 0 width))
+ (setf (substring fpath (- width 2)) "..")))
+ fpath))
+
+(defun org-display-outline-path (&optional file current separator just-return-string)
+ "Display the current outline path in the echo area.
+
+If FILE is non-nil, prepend the output with the file name.
+If CURRENT is non-nil, append the current heading to the output.
+SEPARATOR is passed through to `org-format-outline-path'. It separates
+the different parts of the path and defaults to \"/\".
+If JUST-RETURN-STRING is non-nil, return a string, don't display a message."
+ (interactive "P")
+ (let* (case-fold-search
+ (bfn (buffer-file-name (buffer-base-buffer)))
+ (path (and (derived-mode-p 'org-mode) (org-get-outline-path)))
+ res)
+ (when current (setq path (append path
+ (save-excursion
+ (org-back-to-heading t)
+ (when (looking-at org-complex-heading-regexp)
+ (list (match-string 4)))))))
+ (setq res
+ (org-format-outline-path
+ path
+ (1- (frame-width))
+ (and file bfn (concat (file-name-nondirectory bfn) separator))
+ separator))
+ (add-face-text-property 0 (length res)
+ `(:height ,(face-attribute 'default :height))
+ nil res)
+ (if just-return-string
+ res
+ (org-unlogged-message "%s" res))))
+
;;; Outline Sorting
(defun org-sort (&optional with-case)
@@ -7907,8 +8081,6 @@ Optional argument WITH-CASE means sort case-sensitively."
(org-link-display-format s)
t t) t t))
-(defvar org-priority-regexp) ; defined later in the file
-
(defvar org-after-sorting-entries-or-items-hook nil
"Hook that is run after a bunch of entries or items have been sorted.
When children are sorted, the cursor is in the parent line when this
@@ -8002,7 +8174,7 @@ function is being called interactively."
(setq end (point-max))
(setq what "top-level")
(goto-char start)
- (org-show-all '(headings blocks))))
+ (org-show-all '(headings drawers blocks))))
(setq beg (point))
(when (>= beg end) (goto-char start) (user-error "Nothing to sort"))
@@ -8112,7 +8284,7 @@ function is being called interactively."
((= dcst ?p)
(if (re-search-forward org-priority-regexp (point-at-eol) t)
(string-to-char (match-string 2))
- org-default-priority))
+ org-priority-default))
((= dcst ?r)
(or (org-entry-get nil property) ""))
((= dcst ?o)
@@ -8269,13 +8441,14 @@ the value of the drawer property."
(inhibit-read-only t)
(inherit? (org-property-inherit-p dprop))
(property-re (org-re-property (concat (regexp-quote dprop) "\\+?") t))
- (global (and inherit? (org--property-global-value dprop nil))))
+ (global-or-keyword (and inherit?
+ (org--property-global-or-keyword-value dprop nil))))
(with-silent-modifications
(org-with-point-at 1
- ;; Set global values (e.g., values defined through
- ;; "#+PROPERTY:" keywords) to the whole buffer.
- (when global (put-text-property (point-min) (point-max) tprop global))
- ;; Set local values.
+ ;; Set global and keyword based values to the whole buffer.
+ (when global-or-keyword
+ (put-text-property (point-min) (point-max) tprop global-or-keyword))
+ ;; Set values based on property-drawers throughout the document.
(while (re-search-forward property-re nil t)
(when (org-at-property-p)
(org-refresh-property tprop (org-entry-get (point) dprop) inherit?))
@@ -8283,21 +8456,30 @@ the value of the drawer property."
(defun org-refresh-property (tprop p &optional inherit)
"Refresh the buffer text property TPROP from the drawer property P.
-The refresh happens only for the current headline, or the whole
-sub-tree if optional argument INHERIT is non-nil."
- (unless (org-before-first-heading-p)
- (save-excursion
- (org-back-to-heading t)
- (let ((start (point))
- (end (save-excursion
- (if inherit (org-end-of-subtree t t)
- (or (outline-next-heading) (point-max))))))
- (if (symbolp tprop)
- ;; TPROP is a text property symbol.
- (put-text-property start end tprop p)
- ;; TPROP is an alist with (property . function) elements.
- (pcase-dolist (`(,prop . ,f) tprop)
- (put-text-property start end prop (funcall f p))))))))
+
+The refresh happens only for the current entry, or the whole
+sub-tree if optional argument INHERIT is non-nil.
+
+If point is before first headline, the function applies to the
+part before the first headline. In that particular case, when
+optional argument INHERIT is non-nil, it refreshes properties for
+the whole buffer."
+ (save-excursion
+ (org-back-to-heading-or-point-min t)
+ (let ((start (point))
+ (end (save-excursion
+ (cond ((and inherit (org-before-first-heading-p))
+ (point-max))
+ (inherit
+ (org-end-of-subtree t t))
+ ((outline-next-heading))
+ ((point-max))))))
+ (if (symbolp tprop)
+ ;; TPROP is a text property symbol.
+ (put-text-property start end tprop p)
+ ;; TPROP is an alist with (property . function) elements.
+ (pcase-dolist (`(,prop . ,f) tprop)
+ (put-text-property start end prop (funcall f p)))))))
(defun org-refresh-category-properties ()
"Refresh category text properties in the buffer."
@@ -8313,9 +8495,9 @@ sub-tree if optional argument INHERIT is non-nil."
(t org-category))))
(with-silent-modifications
(org-with-wide-buffer
- ;; Set buffer-wide category. Search last #+CATEGORY keyword.
- ;; This is the default category for the buffer. If none is
- ;; found, fall-back to `org-category' or buffer file name.
+ ;; Set buffer-wide property from keyword. Search last #+CATEGORY
+ ;; keyword. If none is found, fall-back to `org-category' or
+ ;; buffer file name, or set it by the document property drawer.
(put-text-property
(point-min) (point-max)
'org-category
@@ -8327,15 +8509,20 @@ sub-tree if optional argument INHERIT is non-nil."
(throw 'buffer-category
(org-element-property :value element)))))
default-category))
- ;; Set sub-tree specific categories.
+ ;; Set categories from the document property drawer or
+ ;; property drawers in the outline. If category is found in
+ ;; the property drawer for the whole buffer that value
+ ;; overrides the keyword-based value set above.
(goto-char (point-min))
(let ((regexp (org-re-property "CATEGORY")))
(while (re-search-forward regexp nil t)
(let ((value (match-string-no-properties 3)))
(when (org-at-property-p)
(put-text-property
- (save-excursion (org-back-to-heading t) (point))
- (save-excursion (org-end-of-subtree t t) (point))
+ (save-excursion (org-back-to-heading-or-point-min t))
+ (save-excursion (if (org-before-first-heading-p)
+ (point-max)
+ (org-end-of-subtree t t)))
'org-category
value)))))))))
@@ -8659,31 +8846,30 @@ a link."
;; a link, a footnote reference.
((memq type '(headline inlinetask))
(org-match-line org-complex-heading-regexp)
- (if (and (match-beginning 5)
- (>= (point) (match-beginning 5))
- (< (point) (match-end 5)))
- ;; On tags.
- (org-tags-view
- arg
- (save-excursion
- (let* ((beg (match-beginning 5))
- (end (match-end 5))
- (beg-tag (or (search-backward ":" beg 'at-limit) (point)))
- (end-tag (search-forward ":" end nil 2)))
- (buffer-substring (1+ beg-tag) (1- end-tag)))))
- ;; Not on tags.
- (pcase (org-offer-links-in-entry (current-buffer) (point) arg)
- (`(nil . ,_)
- (require 'org-attach)
- (message "Opening attachment-dir")
- (if (equal arg '(4))
- (org-attach-reveal-in-emacs)
- (org-attach-reveal)))
- (`(,links . ,links-end)
- (dolist (link (if (stringp links) (list links) links))
- (search-forward link nil links-end)
- (goto-char (match-beginning 0))
- (org-open-at-point arg))))))
+ (let ((tags-beg (match-beginning 5))
+ (tags-end (match-end 5)))
+ (if (and tags-beg (>= (point) tags-beg) (< (point) tags-end))
+ ;; On tags.
+ (org-tags-view
+ arg
+ (save-excursion
+ (let* ((beg-tag (or (search-backward ":" tags-beg 'at-limit) (point)))
+ (end-tag (search-forward ":" tags-end nil 2)))
+ (buffer-substring (1+ beg-tag) (1- end-tag)))))
+ ;; Not on tags.
+ (pcase (org-offer-links-in-entry (current-buffer) (point) arg)
+ (`(nil . ,_)
+ (require 'org-attach)
+ (when (org-attach-dir)
+ (message "Opening attachment")
+ (if (equal arg '(4))
+ (org-attach-reveal-in-emacs)
+ (org-attach-reveal))))
+ (`(,links . ,links-end)
+ (dolist (link (if (stringp links) (list links) links))
+ (search-forward link nil links-end)
+ (goto-char (match-beginning 0))
+ (org-open-at-point arg)))))))
;; On a footnote reference or at definition's label.
((or (eq type 'footnote-reference)
(and (eq type 'footnote-definition)
@@ -8903,639 +9089,10 @@ or to another Org file, automatically push the old position onto the ring."
(when (string-match (car entry) buffer-file-name)
(throw 'exit (cdr entry))))))))
-(defvar org-refile-target-table nil
- "The list of refile targets, created by `org-refile'.")
-
(defvar org-agenda-new-buffers nil
"Buffers created to visit agenda files.")
-(defvar org-refile-cache nil
- "Cache for refile targets.")
-
-(defvar org-refile-markers nil
- "All the markers used for caching refile locations.")
-
-(defun org-refile-marker (pos)
- "Get a new refile marker, but only if caching is in use."
- (if (not org-refile-use-cache)
- pos
- (let ((m (make-marker)))
- (move-marker m pos)
- (push m org-refile-markers)
- m)))
-
-(defun org-refile-cache-clear ()
- "Clear the refile cache and disable all the markers."
- (dolist (m org-refile-markers) (move-marker m nil))
- (setq org-refile-markers nil)
- (setq org-refile-cache nil)
- (message "Refile cache has been cleared"))
-
-(defun org-refile-cache-check-set (set)
- "Check if all the markers in the cache still have live buffers."
- (let (marker)
- (catch 'exit
- (while (and set (setq marker (nth 3 (pop set))))
- ;; If `org-refile-use-outline-path' is 'file, marker may be nil
- (when (and marker (null (marker-buffer marker)))
- (message "Please regenerate the refile cache with `C-0 C-c C-w'")
- (sit-for 3)
- (throw 'exit nil)))
- t)))
-
-(defun org-refile-cache-put (set &rest identifiers)
- "Push the refile targets SET into the cache, under IDENTIFIERS."
- (let* ((key (sha1 (prin1-to-string identifiers)))
- (entry (assoc key org-refile-cache)))
- (if entry
- (setcdr entry set)
- (push (cons key set) org-refile-cache))))
-
-(defun org-refile-cache-get (&rest identifiers)
- "Retrieve the cached value for refile targets given by IDENTIFIERS."
- (cond
- ((not org-refile-cache) nil)
- ((not org-refile-use-cache) (org-refile-cache-clear) nil)
- (t
- (let ((set (cdr (assoc (sha1 (prin1-to-string identifiers))
- org-refile-cache))))
- (and set (org-refile-cache-check-set set) set)))))
-
-(defvar org-outline-path-cache nil
- "Alist between buffer positions and outline paths.
-It value is an alist (POSITION . PATH) where POSITION is the
-buffer position at the beginning of an entry and PATH is a list
-of strings describing the outline path for that entry, in reverse
-order.")
-
-(defun org-refile-get-targets (&optional default-buffer)
- "Produce a table with refile targets."
- (let ((case-fold-search nil)
- ;; otherwise org confuses "TODO" as a kw and "Todo" as a word
- (entries (or org-refile-targets '((nil . (:level . 1)))))
- targets tgs files desc descre)
- (message "Getting targets...")
- (with-current-buffer (or default-buffer (current-buffer))
- (dolist (entry entries)
- (setq files (car entry) desc (cdr entry))
- (cond
- ((null files) (setq files (list (current-buffer))))
- ((eq files 'org-agenda-files)
- (setq files (org-agenda-files 'unrestricted)))
- ((and (symbolp files) (fboundp files))
- (setq files (funcall files)))
- ((and (symbolp files) (boundp files))
- (setq files (symbol-value files))))
- (when (stringp files) (setq files (list files)))
- (cond
- ((eq (car desc) :tag)
- (setq descre (concat "^\\*+[ \t]+.*?:" (regexp-quote (cdr desc)) ":")))
- ((eq (car desc) :todo)
- (setq descre (concat "^\\*+[ \t]+" (regexp-quote (cdr desc)) "[ \t]")))
- ((eq (car desc) :regexp)
- (setq descre (cdr desc)))
- ((eq (car desc) :level)
- (setq descre (concat "^\\*\\{" (number-to-string
- (if org-odd-levels-only
- (1- (* 2 (cdr desc)))
- (cdr desc)))
- "\\}[ \t]")))
- ((eq (car desc) :maxlevel)
- (setq descre (concat "^\\*\\{1," (number-to-string
- (if org-odd-levels-only
- (1- (* 2 (cdr desc)))
- (cdr desc)))
- "\\}[ \t]")))
- (t (error "Bad refiling target description %s" desc)))
- (dolist (f files)
- (with-current-buffer (if (bufferp f) f (org-get-agenda-file-buffer f))
- (or
- (setq tgs (org-refile-cache-get (buffer-file-name) descre))
- (progn
- (when (bufferp f)
- (setq f (buffer-file-name (buffer-base-buffer f))))
- (setq f (and f (expand-file-name f)))
- (when (eq org-refile-use-outline-path 'file)
- (push (list (file-name-nondirectory f) f nil nil) tgs))
- (when (eq org-refile-use-outline-path 'buffer-name)
- (push (list (buffer-name (buffer-base-buffer)) f nil nil) tgs))
- (when (eq org-refile-use-outline-path 'full-file-path)
- (push (list (file-truename (buffer-file-name (buffer-base-buffer))) f nil nil) tgs))
- (org-with-wide-buffer
- (goto-char (point-min))
- (setq org-outline-path-cache nil)
- (while (re-search-forward descre nil t)
- (beginning-of-line)
- (let ((case-fold-search nil))
- (looking-at org-complex-heading-regexp))
- (let ((begin (point))
- (heading (match-string-no-properties 4)))
- (unless (or (and
- org-refile-target-verify-function
- (not
- (funcall org-refile-target-verify-function)))
- (not heading))
- (let ((re (format org-complex-heading-regexp-format
- (regexp-quote heading)))
- (target
- (if (not org-refile-use-outline-path) heading
- (mapconcat
- #'identity
- (append
- (pcase org-refile-use-outline-path
- (`file (list (file-name-nondirectory
- (buffer-file-name
- (buffer-base-buffer)))))
- (`full-file-path
- (list (buffer-file-name
- (buffer-base-buffer))))
- (`buffer-name
- (list (buffer-name
- (buffer-base-buffer))))
- (_ nil))
- (mapcar (lambda (s) (replace-regexp-in-string
- "/" "\\/" s nil t))
- (org-get-outline-path t t)))
- "/"))))
- (push (list target f re (org-refile-marker (point)))
- tgs)))
- (when (= (point) begin)
- ;; Verification function has not moved point.
- (end-of-line)))))))
- (when org-refile-use-cache
- (org-refile-cache-put tgs (buffer-file-name) descre))
- (setq targets (append tgs targets))))))
- (message "Getting targets...done")
- (delete-dups (nreverse targets))))
-
-(defun org--get-outline-path-1 (&optional use-cache)
- "Return outline path to current headline.
-
-Outline path is a list of strings, in reverse order. When
-optional argument USE-CACHE is non-nil, make use of a cache. See
-`org-get-outline-path' for details.
-
-Assume buffer is widened and point is on a headline."
- (or (and use-cache (cdr (assq (point) org-outline-path-cache)))
- (let ((p (point))
- (heading (let ((case-fold-search nil))
- (looking-at org-complex-heading-regexp)
- (if (not (match-end 4)) ""
- ;; Remove statistics cookies.
- (org-trim
- (org-link-display-format
- (replace-regexp-in-string
- "\\[[0-9]+%\\]\\|\\[[0-9]+/[0-9]+\\]" ""
- (match-string-no-properties 4))))))))
- (if (org-up-heading-safe)
- (let ((path (cons heading (org--get-outline-path-1 use-cache))))
- (when use-cache
- (push (cons p path) org-outline-path-cache))
- path)
- ;; This is a new root node. Since we assume we are moving
- ;; forward, we can drop previous cache so as to limit number
- ;; of associations there.
- (let ((path (list heading)))
- (when use-cache (setq org-outline-path-cache (list (cons p path))))
- path)))))
-
-(defun org-get-outline-path (&optional with-self use-cache)
- "Return the outline path to the current entry.
-
-An outline path is a list of ancestors for current headline, as
-a list of strings. Statistics cookies are removed and links are
-replaced with their description, if any, or their path otherwise.
-
-When optional argument WITH-SELF is non-nil, the path also
-includes the current headline.
-
-When optional argument USE-CACHE is non-nil, cache outline paths
-between calls to this function so as to avoid backtracking. This
-argument is useful when planning to find more than one outline
-path in the same document. In that case, there are two
-conditions to satisfy:
- - `org-outline-path-cache' is set to nil before starting the
- process;
- - outline paths are computed by increasing buffer positions."
- (org-with-wide-buffer
- (and (or (and with-self (org-back-to-heading t))
- (org-up-heading-safe))
- (reverse (org--get-outline-path-1 use-cache)))))
-
-(defun org-format-outline-path (path &optional width prefix separator)
- "Format the outline path PATH for display.
-WIDTH is the maximum number of characters that is available.
-PREFIX is a prefix to be included in the returned string,
-such as the file name.
-SEPARATOR is inserted between the different parts of the path,
-the default is \"/\"."
- (setq width (or width 79))
- (setq path (delq nil path))
- (unless (> width 0)
- (user-error "Argument `width' must be positive"))
- (setq separator (or separator "/"))
- (let* ((org-odd-levels-only nil)
- (fpath (concat
- prefix (and prefix path separator)
- (mapconcat
- (lambda (s) (replace-regexp-in-string "[ \t]+\\'" "" s))
- (cl-loop for head in path
- for n from 0
- collect (org-add-props
- head nil 'face
- (nth (% n org-n-level-faces) org-level-faces)))
- separator))))
- (when (> (length fpath) width)
- (if (< width 7)
- ;; It's unlikely that `width' will be this small, but don't
- ;; waste characters by adding ".." if it is.
- (setq fpath (substring fpath 0 width))
- (setf (substring fpath (- width 2)) "..")))
- fpath))
-
-(defun org-display-outline-path (&optional file current separator just-return-string)
- "Display the current outline path in the echo area.
-
-If FILE is non-nil, prepend the output with the file name.
-If CURRENT is non-nil, append the current heading to the output.
-SEPARATOR is passed through to `org-format-outline-path'. It separates
-the different parts of the path and defaults to \"/\".
-If JUST-RETURN-STRING is non-nil, return a string, don't display a message."
- (interactive "P")
- (let* (case-fold-search
- (bfn (buffer-file-name (buffer-base-buffer)))
- (path (and (derived-mode-p 'org-mode) (org-get-outline-path)))
- res)
- (when current (setq path (append path
- (save-excursion
- (org-back-to-heading t)
- (when (looking-at org-complex-heading-regexp)
- (list (match-string 4)))))))
- (setq res
- (org-format-outline-path
- path
- (1- (frame-width))
- (and file bfn (concat (file-name-nondirectory bfn) separator))
- separator))
- (if just-return-string
- (org-no-properties res)
- (org-unlogged-message "%s" res))))
-
-(defvar org-refile-history nil
- "History for refiling operations.")
-
-(defvar org-after-refile-insert-hook nil
- "Hook run after `org-refile' has inserted its stuff at the new location.
-Note that this is still *before* the stuff will be removed from
-the *old* location.")
-
-(defvar org-capture-last-stored-marker)
-(defvar org-refile-keep nil
- "Non-nil means `org-refile' will copy instead of refile.")
-
-(defun org-copy ()
- "Like `org-refile', but copy."
- (interactive)
- (let ((org-refile-keep t))
- (org-refile nil nil nil "Copy")))
-
-(defun org-refile (&optional arg default-buffer rfloc msg)
- "Move the entry or entries at point to another heading.
-
-The list of target headings is compiled using the information in
-`org-refile-targets', which see.
-
-At the target location, the entry is filed as a subitem of the
-target heading. Depending on `org-reverse-note-order', the new
-subitem will either be the first or the last subitem.
-
-If there is an active region, all entries in that region will be
-refiled. However, the region must fulfill the requirement that
-the first heading sets the top-level of the moved text.
-
-With a `\\[universal-argument]' ARG, the command will only visit the target \
-location
-and not actually move anything.
-
-With a prefix `\\[universal-argument] \\[universal-argument]', go to the \
-location where the last
-refiling operation has put the subtree.
-
-With a numeric prefix argument of `2', refile to the running clock.
-
-With a numeric prefix argument of `3', emulate `org-refile-keep'
-being set to t and copy to the target location, don't move it.
-Beware that keeping refiled entries may result in duplicated ID
-properties.
-
-RFLOC can be a refile location obtained in a different way.
-
-MSG is a string to replace \"Refile\" in the default prompt with
-another verb. E.g. `org-copy' sets this parameter to \"Copy\".
-
-See also `org-refile-use-outline-path'.
-
-If you are using target caching (see `org-refile-use-cache'), you
-have to clear the target cache in order to find new targets.
-This can be done with a `0' prefix (`C-0 C-c C-w') or a triple
-prefix argument (`C-u C-u C-u C-c C-w')."
- (interactive "P")
- (if (member arg '(0 (64)))
- (org-refile-cache-clear)
- (let* ((actionmsg (cond (msg msg)
- ((equal arg 3) "Refile (and keep)")
- (t "Refile")))
- (regionp (org-region-active-p))
- (region-start (and regionp (region-beginning)))
- (region-end (and regionp (region-end)))
- (org-refile-keep (if (equal arg 3) t org-refile-keep))
- pos it nbuf file level reversed)
- (setq last-command nil)
- (when regionp
- (goto-char region-start)
- (beginning-of-line)
- (setq region-start (point))
- (unless (or (org-kill-is-subtree-p
- (buffer-substring region-start region-end))
- (prog1 org-refile-active-region-within-subtree
- (let ((s (point-at-eol)))
- (org-toggle-heading)
- (setq region-end (+ (- (point-at-eol) s) region-end)))))
- (user-error "The region is not a (sequence of) subtree(s)")))
- (if (equal arg '(16))
- (org-refile-goto-last-stored)
- (when (or
- (and (equal arg 2)
- org-clock-hd-marker (marker-buffer org-clock-hd-marker)
- (prog1
- (setq it (list (or org-clock-heading "running clock")
- (buffer-file-name
- (marker-buffer org-clock-hd-marker))
- ""
- (marker-position org-clock-hd-marker)))
- (setq arg nil)))
- (setq it
- (or rfloc
- (let (heading-text)
- (save-excursion
- (unless (and arg (listp arg))
- (org-back-to-heading t)
- (setq heading-text
- (replace-regexp-in-string
- org-link-bracket-re
- "\\2"
- (or (nth 4 (org-heading-components))
- ""))))
- (org-refile-get-location
- (cond ((and arg (listp arg)) "Goto")
- (regionp (concat actionmsg " region to"))
- (t (concat actionmsg " subtree \""
- heading-text "\" to")))
- default-buffer
- (and (not (equal '(4) arg))
- org-refile-allow-creating-parent-nodes)))))))
- (setq file (nth 1 it)
- pos (nth 3 it))
- (when (and (not arg)
- pos
- (equal (buffer-file-name) file)
- (if regionp
- (and (>= pos region-start)
- (<= pos region-end))
- (and (>= pos (point))
- (< pos (save-excursion
- (org-end-of-subtree t t))))))
- (error "Cannot refile to position inside the tree or region"))
- (setq nbuf (or (find-buffer-visiting file)
- (find-file-noselect file)))
- (if (and arg (not (equal arg 3)))
- (progn
- (pop-to-buffer-same-window nbuf)
- (goto-char (cond (pos)
- ((org-notes-order-reversed-p) (point-min))
- (t (point-max))))
- (org-show-context 'org-goto))
- (if regionp
- (progn
- (org-kill-new (buffer-substring region-start region-end))
- (org-save-markers-in-region region-start region-end))
- (org-copy-subtree 1 nil t))
- (with-current-buffer (setq nbuf (or (find-buffer-visiting file)
- (find-file-noselect file)))
- (setq reversed (org-notes-order-reversed-p))
- (org-with-wide-buffer
- (if pos
- (progn
- (goto-char pos)
- (setq level (org-get-valid-level (funcall outline-level) 1))
- (goto-char
- (if reversed
- (or (outline-next-heading) (point-max))
- (or (save-excursion (org-get-next-sibling))
- (org-end-of-subtree t t)
- (point-max)))))
- (setq level 1)
- (if (not reversed)
- (goto-char (point-max))
- (goto-char (point-min))
- (or (outline-next-heading) (goto-char (point-max)))))
- (unless (bolp) (newline))
- (org-paste-subtree level nil nil t)
- ;; Record information, according to `org-log-refile'.
- ;; Do not prompt for a note when refiling multiple
- ;; headlines, however. Simply add a time stamp.
- (cond
- ((not org-log-refile))
- (regionp
- (org-map-region
- (lambda () (org-add-log-setup 'refile nil nil 'time))
- (point)
- (+ (point) (- region-end region-start))))
- (t
- (org-add-log-setup 'refile nil nil org-log-refile)))
- (and org-auto-align-tags
- (let ((org-loop-over-headlines-in-active-region nil))
- (org-align-tags)))
- (let ((bookmark-name (plist-get org-bookmark-names-plist
- :last-refile)))
- (when bookmark-name
- (with-demoted-errors
- (bookmark-set bookmark-name))))
- ;; If we are refiling for capture, make sure that the
- ;; last-capture pointers point here
- (when (bound-and-true-p org-capture-is-refiling)
- (let ((bookmark-name (plist-get org-bookmark-names-plist
- :last-capture-marker)))
- (when bookmark-name
- (with-demoted-errors
- (bookmark-set bookmark-name))))
- (move-marker org-capture-last-stored-marker (point)))
- (when (fboundp 'deactivate-mark) (deactivate-mark))
- (run-hooks 'org-after-refile-insert-hook)))
- (unless org-refile-keep
- (if regionp
- (delete-region (point) (+ (point) (- region-end region-start)))
- (org-preserve-local-variables
- (delete-region
- (and (org-back-to-heading t) (point))
- (min (1+ (buffer-size)) (org-end-of-subtree t t) (point))))))
- (when (featurep 'org-inlinetask)
- (org-inlinetask-remove-END-maybe))
- (setq org-markers-to-move nil)
- (message "%s to \"%s\" in file %s: done" actionmsg
- (car it) file)))))))
-
-(defun org-refile-goto-last-stored ()
- "Go to the location where the last refile was stored."
- (interactive)
- (bookmark-jump (plist-get org-bookmark-names-plist :last-refile))
- (message "This is the location of the last refile"))
-
-(defun org-refile--get-location (refloc tbl)
- "When user refile to REFLOC, find the associated target in TBL.
-Also check `org-refile-target-table'."
- (car (delq
- nil
- (mapcar
- (lambda (r) (or (assoc r tbl)
- (assoc r org-refile-target-table)))
- (list (replace-regexp-in-string "/$" "" refloc)
- (replace-regexp-in-string "\\([^/]\\)$" "\\1/" refloc))))))
-
-(defun org-refile-get-location (&optional prompt default-buffer new-nodes)
- "Prompt the user for a refile location, using PROMPT.
-PROMPT should not be suffixed with a colon and a space, because
-this function appends the default value from
-`org-refile-history' automatically, if that is not empty."
- (let ((org-refile-targets org-refile-targets)
- (org-refile-use-outline-path org-refile-use-outline-path))
- (setq org-refile-target-table (org-refile-get-targets default-buffer)))
- (unless org-refile-target-table
- (user-error "No refile targets"))
- (let* ((cbuf (current-buffer))
- (cfn (buffer-file-name (buffer-base-buffer cbuf)))
- (cfunc (if (and org-refile-use-outline-path
- org-outline-path-complete-in-steps)
- #'org-olpath-completing-read
- #'completing-read))
- (extra (if org-refile-use-outline-path "/" ""))
- (cbnex (concat (buffer-name) extra))
- (filename (and cfn (expand-file-name cfn)))
- (tbl (mapcar
- (lambda (x)
- (if (and (not (member org-refile-use-outline-path
- '(file full-file-path)))
- (not (equal filename (nth 1 x))))
- (cons (concat (car x) extra " ("
- (file-name-nondirectory (nth 1 x)) ")")
- (cdr x))
- (cons (concat (car x) extra) (cdr x))))
- org-refile-target-table))
- (completion-ignore-case t)
- cdef
- (prompt (concat prompt
- (or (and (car org-refile-history)
- (concat " (default " (car org-refile-history) ")"))
- (and (assoc cbnex tbl) (setq cdef cbnex)
- (concat " (default " cbnex ")"))) ": "))
- pa answ parent-target child parent old-hist)
- (setq old-hist org-refile-history)
- (setq answ (funcall cfunc prompt tbl nil (not new-nodes)
- nil 'org-refile-history (or cdef (car org-refile-history))))
- (if (setq pa (org-refile--get-location answ tbl))
- (progn
- (org-refile-check-position pa)
- (when (or (not org-refile-history)
- (not (eq old-hist org-refile-history))
- (not (equal (car pa) (car org-refile-history))))
- (setq org-refile-history
- (cons (car pa) (if (assoc (car org-refile-history) tbl)
- org-refile-history
- (cdr org-refile-history))))
- (when (equal (car org-refile-history) (nth 1 org-refile-history))
- (pop org-refile-history)))
- pa)
- (if (string-match "\\`\\(.*\\)/\\([^/]+\\)\\'" answ)
- (progn
- (setq parent (match-string 1 answ)
- child (match-string 2 answ))
- (setq parent-target (org-refile--get-location parent tbl))
- (when (and parent-target
- (or (eq new-nodes t)
- (and (eq new-nodes 'confirm)
- (y-or-n-p (format "Create new node \"%s\"? "
- child)))))
- (org-refile-new-child parent-target child)))
- (user-error "Invalid target location")))))
-
(declare-function org-string-nw-p "org-macs" (s))
-(defun org-refile-check-position (refile-pointer)
- "Check if the refile pointer matches the headline to which it points."
- (let* ((file (nth 1 refile-pointer))
- (re (nth 2 refile-pointer))
- (pos (nth 3 refile-pointer))
- buffer)
- (if (and (not (markerp pos)) (not file))
- (user-error "Please indicate a target file in the refile path")
- (when (org-string-nw-p re)
- (setq buffer (if (markerp pos)
- (marker-buffer pos)
- (or (find-buffer-visiting file)
- (find-file-noselect file))))
- (with-current-buffer buffer
- (org-with-wide-buffer
- (goto-char pos)
- (beginning-of-line 1)
- (unless (looking-at-p re)
- (user-error "Invalid refile position, please clear the cache with `C-0 C-c C-w' before refiling"))))))))
-
-(defun org-refile-new-child (parent-target child)
- "Use refile target PARENT-TARGET to add new CHILD below it."
- (unless parent-target
- (error "Cannot find parent for new node"))
- (let ((file (nth 1 parent-target))
- (pos (nth 3 parent-target))
- level)
- (with-current-buffer (or (find-buffer-visiting file)
- (find-file-noselect file))
- (org-with-wide-buffer
- (if pos
- (goto-char pos)
- (goto-char (point-max))
- (unless (bolp) (newline)))
- (when (looking-at org-outline-regexp)
- (setq level (funcall outline-level))
- (org-end-of-subtree t t))
- (org-back-over-empty-lines)
- (insert "\n" (make-string
- (if pos (org-get-valid-level level 1) 1) ?*)
- " " child "\n")
- (beginning-of-line 0)
- (list (concat (car parent-target) "/" child) file "" (point))))))
-
-(defun org-olpath-completing-read (prompt collection &rest args)
- "Read an outline path like a file name."
- (let ((thetable collection))
- (apply #'completing-read
- prompt
- (lambda (string predicate &optional flag)
- (cond
- ((eq flag nil) (try-completion string thetable))
- ((eq flag t)
- (let ((l (length string)))
- (mapcar (lambda (x)
- (let ((r (substring x l))
- (f (if (string-match " ([^)]*)$" x)
- (match-string 0 x)
- "")))
- (if (string-match "/" r)
- (concat string (substring r 0 (match-end 0)) f)
- x)))
- (all-completions string thetable predicate))))
- ;; Exact match?
- ((eq flag 'lambda) (assoc string thetable))))
- args)))
-
;;;; Dynamic blocks
(defun org-find-dblock (name)
@@ -9631,15 +9188,18 @@ block of such type."
(`nil (push (cons type func) org-dynamic-block-alist))
(def (setcdr def func))))
-(defun org-dynamic-block-insert-dblock (type)
+(defun org-dynamic-block-insert-dblock (type &optional interactive-p)
"Insert a dynamic block of type TYPE.
When used interactively, select the dynamic block types among
-defined types, per `org-dynamic-block-define'."
+defined types, per `org-dynamic-block-define'. If INTERACTIVE-P
+is non-nil, call the dynamic block function interactively."
(interactive (list (completing-read "Dynamic block: "
- (org-dynamic-block-types))))
+ (org-dynamic-block-types))
+ t))
(pcase (org-dynamic-block-function type)
(`nil (error "No such dynamic block: %S" type))
- ((and f (pred functionp)) (funcall f))
+ ((and f (pred functionp))
+ (if interactive-p (call-interactively f) (funcall f)))
(_ (error "Invalid function for dynamic block %S" type))))
(defun org-dblock-update (&optional arg)
@@ -9763,8 +9323,7 @@ block can be inserted by pressing TAB after the string \"<KEY\"."
(defun org--check-org-structure-template-alist (&optional checklist)
"Check whether `org-structure-template-alist' is set up correctly.
In particular, check if the Org 9.2 format is used as opposed to
-previous format.
-"
+previous format."
(let ((elm (cl-remove-if-not (lambda (x) (listp (cdr x)))
(or (eval checklist)
org-structure-template-alist))))
@@ -10039,9 +9598,9 @@ When called through ELisp, arg is also interpreted in the following way:
'region-start-level 'region))
org-loop-over-headlines-in-active-region)
(org-map-entries
- `(org-todo ,arg)
- org-loop-over-headlines-in-active-region
- cl (when (org-invisible-p) (org-end-of-subtree nil t))))
+ (lambda () (org-todo arg))
+ nil cl
+ (when (org-invisible-p) (org-end-of-subtree nil t))))
(when (equal arg '(16)) (setq arg 'nextset))
(when (equal arg -1) (org-cancel-repeater) (setq arg nil))
(let ((org-blocker-hook org-blocker-hook)
@@ -10158,7 +9717,7 @@ When called through ELisp, arg is also interpreted in the following way:
(throw 'exit nil)))))
(store-match-data match-data)
(replace-match next t t)
- (cond ((equal this org-state)
+ (cond ((and org-state (equal this org-state))
(message "TODO state was already %s" (org-trim next)))
((not (pos-visible-in-window-p hl-pos))
(message "TODO state changed to %s" (org-trim next))))
@@ -10534,8 +10093,7 @@ when there is a statistics cookie in the headline!
(defun org-summary-todo (n-done n-not-done)
\"Switch entry to DONE when all subentries are done, to TODO otherwise.\"
(let (org-log-done org-log-states) ; turn off logging
- (org-todo (if (= n-not-done 0) \"DONE\" \"TODO\"))))
-")
+ (org-todo (if (= n-not-done 0) \"DONE\" \"TODO\"))))")
(defvar org-todo-statistics-hook nil
"Hook that is run whenever Org thinks TODO statistics should be updated.
@@ -10824,9 +10382,13 @@ This function is run automatically after each state change to a DONE state."
(repeater-type (match-string 1 ts)))
(cond
((equal "." repeater-type)
- ;; Shift starting date to today.
- (org-timestamp-change (- (org-today) (time-to-days time))
- 'day))
+ ;; Shift starting date to today, or now if
+ ;; repeater is by hours.
+ (if (equal what "h")
+ (org-timestamp-change
+ (floor (- (org-time-stamp-to-now ts t)) 60) 'minute)
+ (org-timestamp-change
+ (- (org-today) (time-to-days time)) 'day)))
((equal "+" repeater-type)
(let ((nshiftmax 10)
(nshift 0))
@@ -10965,7 +10527,11 @@ TYPE is either `deadline' or `scheduled'. See `org-deadline' or
org-last-inserted-timestamp)))))
(defun org-deadline (arg &optional time)
- "Insert the \"DEADLINE:\" string with a timestamp to make a deadline.
+ "Insert a \"DEADLINE:\" string with a timestamp to make a deadline.
+
+When called interactively, this command pops up the Emacs calendar to let
+the user select a date.
+
With one universal prefix argument, remove any deadline from the item.
With two universal prefix arguments, prompt for a warning delay.
With argument TIME, set the deadline at the corresponding date. TIME
@@ -10982,7 +10548,11 @@ can either be an Org date like \"2011-07-24\" or a delta like \"+2d\"."
(org--deadline-or-schedule arg 'deadline time)))
(defun org-schedule (arg &optional time)
- "Insert the SCHEDULED: string with a timestamp to schedule a TODO item.
+ "Insert a \"SCHEDULED:\" string with a timestamp to schedule an item.
+
+When called interactively, this command pops up the Emacs calendar to let
+the user select a date.
+
With one universal prefix argument, remove any scheduling date from the item.
With two universal prefix arguments, prompt for a delay cookie.
With argument TIME, scheduled at the corresponding date. TIME can
@@ -11057,97 +10627,100 @@ the time to use. If none is given, the user is prompted for
a date. REMOVE indicates what kind of entries to remove. An old
WHAT entry will also be removed."
(let (org-time-was-given org-end-time-was-given default-time default-input)
- (catch 'exit
- (when (and (memq what '(scheduled deadline))
- (or (not time)
- (and (stringp time)
- (string-match "^[-+]+[0-9]" time))))
- ;; Try to get a default date/time from existing timestamp
- (save-excursion
- (org-back-to-heading t)
- (let ((end (save-excursion (outline-next-heading) (point))) ts)
- (when (re-search-forward (if (eq what 'scheduled)
- org-scheduled-time-regexp
- org-deadline-time-regexp)
- end t)
- (setq ts (match-string 1)
- default-time (org-time-string-to-time ts)
- default-input (and ts (org-get-compact-tod ts)))))))
- (when what
- (setq time
- (if (stringp time)
- ;; This is a string (relative or absolute), set
- ;; proper date.
- (apply #'encode-time
- (org-read-date-analyze
- time default-time (decode-time default-time)))
- ;; If necessary, get the time from the user
- (or time (org-read-date nil 'to-time nil
- (cl-case what
- (deadline "DEADLINE")
- (scheduled "SCHEDULED")
- (otherwise nil))
- default-time default-input)))))
- (org-with-wide-buffer
- (org-back-to-heading t)
- (forward-line)
- (unless (bolp) (insert "\n"))
- (cond ((looking-at-p org-planning-line-re)
- ;; Move to current indentation.
- (skip-chars-forward " \t")
- ;; Check if we have to remove something.
- (dolist (type (if what (cons what remove) remove))
- (save-excursion
- (when (re-search-forward
- (cl-case type
- (closed org-closed-time-regexp)
- (deadline org-deadline-time-regexp)
- (scheduled org-scheduled-time-regexp)
- (otherwise
- (error "Invalid planning type: %s" type)))
- (line-end-position) t)
- ;; Delete until next keyword or end of line.
- (delete-region
- (match-beginning 0)
- (if (re-search-forward org-keyword-time-not-clock-regexp
- (line-end-position)
- t)
- (match-beginning 0)
- (line-end-position))))))
- ;; If there is nothing more to add and no more keyword
- ;; is left, remove the line completely.
- (if (and (looking-at-p "[ \t]*$") (not what))
- (delete-region (line-beginning-position)
- (line-beginning-position 2))
- ;; If we removed last keyword, do not leave trailing
- ;; white space at the end of line.
- (let ((p (point)))
- (save-excursion
- (end-of-line)
- (unless (= (skip-chars-backward " \t" p) 0)
- (delete-region (point) (line-end-position)))))))
- ((not what) (throw 'exit nil)) ; Nothing to do.
- (t (insert-before-markers "\n")
- (backward-char 1)
- (when org-adapt-indentation
- (indent-to-column (1+ (org-outline-level))))))
- (when what
- ;; Insert planning keyword.
- (insert (cl-case what
- (closed org-closed-string)
- (deadline org-deadline-string)
- (scheduled org-scheduled-string)
- (otherwise (error "Invalid planning type: %s" what)))
- " ")
- ;; Insert associated timestamp.
- (let ((ts (org-insert-time-stamp
- time
- (or org-time-was-given
- (and (eq what 'closed) org-log-done-with-time))
- (eq what 'closed)
- nil nil (list org-end-time-was-given))))
- (unless (eolp) (insert " "))
- ts))))))
+ (when (and (memq what '(scheduled deadline))
+ (or (not time)
+ (and (stringp time)
+ (string-match "^[-+]+[0-9]" time))))
+ ;; Try to get a default date/time from existing timestamp
+ (save-excursion
+ (org-back-to-heading t)
+ (let ((end (save-excursion (outline-next-heading) (point))) ts)
+ (when (re-search-forward (if (eq what 'scheduled)
+ org-scheduled-time-regexp
+ org-deadline-time-regexp)
+ end t)
+ (setq ts (match-string 1)
+ default-time (org-time-string-to-time ts)
+ default-input (and ts (org-get-compact-tod ts)))))))
+ (when what
+ (setq time
+ (if (stringp time)
+ ;; This is a string (relative or absolute), set
+ ;; proper date.
+ (apply #'encode-time
+ (org-read-date-analyze
+ time default-time (decode-time default-time)))
+ ;; If necessary, get the time from the user
+ (or time (org-read-date nil 'to-time nil
+ (cl-case what
+ (deadline "DEADLINE")
+ (scheduled "SCHEDULED")
+ (otherwise nil))
+ default-time default-input)))))
+ (org-with-wide-buffer
+ (org-back-to-heading t)
+ (let ((planning? (save-excursion
+ (forward-line)
+ (looking-at-p org-planning-line-re))))
+ (cond
+ (planning?
+ (forward-line)
+ ;; Move to current indentation.
+ (skip-chars-forward " \t")
+ ;; Check if we have to remove something.
+ (dolist (type (if what (cons what remove) remove))
+ (save-excursion
+ (when (re-search-forward
+ (cl-case type
+ (closed org-closed-time-regexp)
+ (deadline org-deadline-time-regexp)
+ (scheduled org-scheduled-time-regexp)
+ (otherwise (error "Invalid planning type: %s" type)))
+ (line-end-position)
+ t)
+ ;; Delete until next keyword or end of line.
+ (delete-region
+ (match-beginning 0)
+ (if (re-search-forward org-keyword-time-not-clock-regexp
+ (line-end-position)
+ t)
+ (match-beginning 0)
+ (line-end-position))))))
+ ;; If there is nothing more to add and no more keyword is
+ ;; left, remove the line completely.
+ (if (and (looking-at-p "[ \t]*$") (not what))
+ (delete-region (line-end-position 0)
+ (line-end-position))
+ ;; If we removed last keyword, do not leave trailing white
+ ;; space at the end of line.
+ (let ((p (point)))
+ (save-excursion
+ (end-of-line)
+ (unless (= (skip-chars-backward " \t" p) 0)
+ (delete-region (point) (line-end-position)))))))
+ (what
+ (end-of-line)
+ (insert "\n")
+ (when org-adapt-indentation
+ (indent-to-column (1+ (org-outline-level)))))
+ (t nil)))
+ (when what
+ ;; Insert planning keyword.
+ (insert (cl-case what
+ (closed org-closed-string)
+ (deadline org-deadline-string)
+ (scheduled org-scheduled-string)
+ (otherwise (error "Invalid planning type: %s" what)))
+ " ")
+ ;; Insert associated timestamp.
+ (let ((ts (org-insert-time-stamp
+ time
+ (or org-time-was-given
+ (and (eq what 'closed) org-log-done-with-time))
+ (eq what 'closed)
+ nil nil (list org-end-time-was-given))))
+ (unless (eolp) (insert " "))
+ ts)))))
(defvar org-log-note-marker (make-marker)
"Marker pointing at the entry where the note is to be inserted.")
@@ -11158,8 +10731,9 @@ WHAT entry will also be removed."
(defvar org-log-note-window-configuration nil)
(defvar org-log-note-return-to (make-marker))
(defvar org-log-note-effective-time nil
- "Remembered current time so that dynamically scoped
-`org-extend-today-until' affects timestamps in state change log")
+ "Remembered current time.
+So that dynamically scoped `org-extend-today-until' affects
+timestamps in state change log.")
(defvar org-log-post-message nil
"Message to be displayed after a log note has been stored.
@@ -11200,8 +10774,7 @@ narrowing."
(let ((beg (point)))
(insert ":" drawer ":\n:END:\n")
(org-indent-region beg (point))
- (org-flag-region
- (line-end-position -1) (1- (point)) t 'org-hide-drawer))
+ (org-flag-region (line-end-position -1) (1- (point)) t 'outline))
(end-of-line -1)))))
(t
(org-end-of-meta-data org-log-state-notes-insert-after-drawers)
@@ -11266,19 +10839,19 @@ EXTRA is additional text that will be inserted into the notes buffer."
(insert (format "# Insert note for %s.
# Finish with C-c C-c, or cancel with C-c C-k.\n\n"
(cl-case org-log-note-purpose
- (clock-out "stopped clock")
- (done "closed todo item")
- (reschedule "rescheduling")
- (delschedule "no longer scheduled")
- (redeadline "changing deadline")
- (deldeadline "removing deadline")
- (refile "refiling")
- (note "this entry")
- (state
- (format "state change from \"%s\" to \"%s\""
- (or org-log-note-previous-state "")
- (or org-log-note-state "")))
- (t (error "This should not happen")))))
+ (clock-out "stopped clock")
+ (done "closed todo item")
+ (reschedule "rescheduling")
+ (delschedule "no longer scheduled")
+ (redeadline "changing deadline")
+ (deldeadline "removing deadline")
+ (refile "refiling")
+ (note "this entry")
+ (state
+ (format "state change from \"%s\" to \"%s\""
+ (or org-log-note-previous-state "")
+ (or org-log-note-state "")))
+ (t (error "This should not happen")))))
(when org-log-note-extra (insert org-log-note-extra))
(setq-local org-finish-function 'org-store-log-note)
(run-hooks 'org-log-buffer-setup-hook)))
@@ -11410,8 +10983,8 @@ D Show deadlines and scheduled items between a date range."
(setq type (or type org-sparse-tree-default-date-type))
(setq org-ts-type type)
(message "Sparse tree: [r]egexp [t]odo [T]odo-kwd [m]atch [p]roperty
- \[d]eadlines [b]efore-date [a]fter-date [D]ates range
- \[c]ycle through date types: %s"
+ [d]eadlines [b]efore-date [a]fter-date [D]ates range
+ [c]ycle through date types: %s"
(cl-case type
(all "all timestamps")
(scheduled "only scheduled")
@@ -11459,7 +11032,7 @@ on `org-remove-highlights-with-change'), this variable is emptied
as well.")
(defun org-occur (regexp &optional keep-previous callback)
- "Make a compact tree which shows all matches of REGEXP.
+ "Make a compact tree showing all matches of REGEXP.
The tree will show the lines where the regexp matches, and any other context
defined in `org-show-context-detail', which see.
@@ -11553,10 +11126,13 @@ from the `before-change-functions' in the current buffer."
;;;; Priorities
-(defvar org-priority-regexp ".*?\\(\\[#\\([A-Z0-9]\\)\\] ?\\)"
- "Regular expression matching the priority indicator.")
-
-(defvar org-remove-priority-next-time nil)
+(defvar org-priority-regexp ".*?\\(\\[#\\([A-Z0-9]+\\)\\] ?\\)"
+ "Regular expression matching the priority indicator.
+A priority indicator can be e.g. [#A] or [#1].
+This regular expression matches these groups:
+0 : the whole match, e.g. \"TODO [#A] Hack\"
+1 : the priority cookie, e.g. \"[#A]\"
+2 : the value of the priority cookie, e.g. \"A\".")
(defun org-priority-up ()
"Increase the priority of the current item."
@@ -11582,16 +11158,18 @@ or a character."
;; passed the SHOW argument should be removed.
(warn "`org-priority' called with deprecated SHOW argument"))
(if (equal action '(4))
- (org-show-priority)
- (unless org-enable-priority-commands
+ (org-priority-show)
+ (unless org-priority-enable-commands
(user-error "Priority commands are disabled"))
(setq action (or action 'set))
- (let (current new news have remove)
+ (let ((nump (< org-priority-lowest 65))
+ current new news have remove)
(save-excursion
(org-back-to-heading t)
(when (looking-at org-priority-regexp)
- (setq current (string-to-char (match-string 2))
- have t))
+ (let ((ms (match-string 2)))
+ (setq current (org-priority-to-value ms)
+ have t)))
(cond
((eq action 'remove)
(setq remove t new ?\ ))
@@ -11599,49 +11177,61 @@ or a character."
(integerp action))
(if (not (eq action 'set))
(setq new action)
- (message "Priority %c-%c, SPC to remove: "
- org-highest-priority org-lowest-priority)
- (save-match-data
- (setq new (read-char-exclusive))))
- (when (and (= (upcase org-highest-priority) org-highest-priority)
- (= (upcase org-lowest-priority) org-lowest-priority))
+ (setq
+ new
+ (if nump
+ (string-to-number
+ (read-string (format "Priority %s-%s, SPC to remove: "
+ (number-to-string org-priority-highest)
+ (number-to-string org-priority-lowest))))
+ (progn (message "Priority %c-%c, SPC to remove: "
+ org-priority-highest org-priority-lowest)
+ (save-match-data
+ (setq new (read-char-exclusive)))))))
+ (when (and (= (upcase org-priority-highest) org-priority-highest)
+ (= (upcase org-priority-lowest) org-priority-lowest))
(setq new (upcase new)))
(cond ((equal new ?\s) (setq remove t))
- ((or (< (upcase new) org-highest-priority) (> (upcase new) org-lowest-priority))
- (user-error "Priority must be between `%c' and `%c'"
- org-highest-priority org-lowest-priority))))
+ ((or (< (upcase new) org-priority-highest) (> (upcase new) org-priority-lowest))
+ (user-error
+ (if nump
+ "Priority must be between `%s' and `%s'"
+ "Priority must be between `%c' and `%c'")
+ org-priority-highest org-priority-lowest))))
((eq action 'up)
(setq new (if have
(1- current) ; normal cycling
;; last priority was empty
(if (eq last-command this-command)
- org-lowest-priority ; wrap around empty to lowest
+ org-priority-lowest ; wrap around empty to lowest
;; default
(if org-priority-start-cycle-with-default
- org-default-priority
- (1- org-default-priority))))))
+ org-priority-default
+ (1- org-priority-default))))))
((eq action 'down)
(setq new (if have
(1+ current) ; normal cycling
;; last priority was empty
(if (eq last-command this-command)
- org-highest-priority ; wrap around empty to highest
+ org-priority-highest ; wrap around empty to highest
;; default
(if org-priority-start-cycle-with-default
- org-default-priority
- (1+ org-default-priority))))))
+ org-priority-default
+ (1+ org-priority-default))))))
(t (user-error "Invalid action")))
- (when (or (< (upcase new) org-highest-priority)
- (> (upcase new) org-lowest-priority))
+ (when (or (< (upcase new) org-priority-highest)
+ (> (upcase new) org-priority-lowest))
(if (and (memq action '(up down))
(not have) (not (eq last-command this-command)))
;; `new' is from default priority
(error
- "The default can not be set, see `org-default-priority' why")
+ "The default can not be set, see `org-priority-default' why")
;; normal cycling: `new' is beyond highest/lowest priority
;; and is wrapped around to the empty priority
(setq remove t)))
- (setq news (format "%c" new))
+ ;; Numerical priorities are limited to 64, beyond that number,
+ ;; assume the priority cookie is a character.
+ (setq news (if (> new 64) (format "%c" new) (format "%s" new)))
(if have
(if remove
(replace-match "" t t nil 1)
@@ -11660,7 +11250,8 @@ or a character."
(message "Priority removed")
(message "Priority of current item set to %s" news)))))
-(defun org-show-priority ()
+(defalias 'org-show-priority 'org-priority-show)
+(defun org-priority-show ()
"Show the priority of the current item.
This priority is composed of the main priority given with the [#A] cookies,
and by additional input from the age of a schedules or deadline entry."
@@ -11675,14 +11266,18 @@ and by additional input from the age of a schedules or deadline entry."
(message "Priority is %d" (if pri pri -1000))))
(defun org-get-priority (s)
- "Find priority cookie and return priority."
+ "Find priority cookie and return priority.
+S is a string against which you can match `org-priority-regexp'.
+If `org-priority-get-priority-function' is set to a custom
+function, use it. Otherwise process S and output the priority
+value, an integer."
(save-match-data
- (if (functionp org-get-priority-function)
- (funcall org-get-priority-function s)
+ (if (functionp org-priority-get-priority-function)
+ (funcall org-priority-get-priority-function s)
(if (not (string-match org-priority-regexp s))
- (* 1000 (- org-lowest-priority org-default-priority))
- (* 1000 (- org-lowest-priority
- (string-to-char (match-string 2 s))))))))
+ (* 1000 (- org-priority-lowest org-priority-default))
+ (* 1000 (- org-priority-lowest
+ (org-priority-to-value (match-string 2 s))))))))
;;;; Tags
@@ -11907,7 +11502,7 @@ are also TODO tasks."
(interactive "P")
(org-agenda-prepare-buffers (list (current-buffer)))
(let ((org--matcher-tags-todo-only todo-only))
- (org-scan-tags 'sparse-tree (cdr (org-make-tags-matcher match))
+ (org-scan-tags 'sparse-tree (cdr (org-make-tags-matcher match t))
org--matcher-tags-todo-only)))
(defalias 'org-tags-sparse-tree 'org-match-sparse-tree)
@@ -11948,7 +11543,7 @@ instead of the agenda files."
(if (car-safe files) files
(org-agenda-files))))))))
-(defun org-make-tags-matcher (match)
+(defun org-make-tags-matcher (match &optional only-local-tags)
"Create the TAGS/TODO matcher form for the selection string MATCH.
Returns a cons of the selection string MATCH and a function
@@ -11966,6 +11561,9 @@ This function sets the variable `org--matcher-tags-todo-only' to
a non-nil value if the matcher restricts matching to TODO
entries, otherwise it is not touched.
+When ONLY-LOCAL-TAGS is non-nil, ignore the global tag completion
+table, only get buffer tags.
+
See also `org-scan-tags'."
(unless match
;; Get a new match request, with completion against the global
@@ -11973,7 +11571,8 @@ See also `org-scan-tags'."
(let ((org-last-tags-completion-table
(org--tag-add-to-alist
(org-get-buffer-tags)
- (org-global-tags-completion-table))))
+ (unless only-local-tags
+ (org-global-tags-completion-table)))))
(setq match
(completing-read
"Match: "
@@ -12100,7 +11699,7 @@ See also `org-scan-tags'."
(cons match0 `(lambda (todo tags-list level) ,matcher)))))
(defun org--tags-expand-group (group tag-groups expanded)
- "Recursively Expand all tags in GROUP, according to TAG-GROUPS.
+ "Recursively expand all tags in GROUP, according to TAG-GROUPS.
TAG-GROUPS is the list of groups used for expansion. EXPANDED is
an accumulator used in recursive calls."
(dolist (tag group)
@@ -12148,7 +11747,9 @@ When DOWNCASED is non-nil, expand downcased TAGS."
(if (not downcased) g
(mapcar (lambda (s) (mapcar #'downcase s)) g)))))
(cond
- (single-as-list (org--tags-expand-group (list match) tag-groups nil))
+ (single-as-list (org--tags-expand-group
+ (list (if downcased (downcase match) match))
+ tag-groups nil))
(org-group-tags
(let* ((case-fold-search t)
(tag-syntax org-mode-syntax-table)
@@ -12331,7 +11932,12 @@ in Lisp code use `org-set-tags' instead."
#'org-tags-completion-function
nil nil (org-make-tag-string current-tags)
'org-tags-history)))))))
- (org-set-tags tags)))))))
+ (org-set-tags tags)))))
+ ;; `save-excursion' may not replace the point at the right
+ ;; position.
+ (when (and (save-excursion (skip-chars-backward "*") (bolp))
+ (looking-at-p " "))
+ (forward-char))))
(defun org-align-tags (&optional all)
"Align tags in current entry.
@@ -12712,7 +12318,8 @@ According to `org-use-tag-inheritance', tags may be inherited
from parent headlines, and from the whole document, through
`org-file-tags'. In this case, the returned list of tags
contains tags in this order: file tags, tags inherited from
-parent headlines, local tags.
+parent headlines, local tags. If a tag appears multiple times,
+only the most local tag is returned.
However, when optional argument LOCAL is non-nil, only return
tags specified at the headline.
@@ -12728,12 +12335,13 @@ Inherited tags have the `inherited' text property."
(let ((ltags (org--get-local-tags)) itags)
(if (or local (not org-use-tag-inheritance)) ltags
(while (org-up-heading-safe)
- (setq itags (append (mapcar #'org-add-prop-inherited
- (org--get-local-tags))
- itags)))
+ (setq itags (nconc (mapcar #'org-add-prop-inherited
+ (org--get-local-tags))
+ itags)))
(setq itags (append org-file-tags itags))
- (delete-dups
- (append (org-remove-uninherited-tags itags) ltags))))))))
+ (nreverse
+ (delete-dups
+ (nreverse (nconc (org-remove-uninherited-tags itags) ltags))))))))))
(defun org-get-buffer-tags ()
"Get a table of all tags used in the buffer, for completion."
@@ -12921,30 +12529,52 @@ Modifications are made by side-effect. Return new alist."
(defun org-get-property-block (&optional beg force)
"Return the (beg . end) range of the body of the property drawer.
-BEG is the beginning of the current subtree, or of the part
-before the first headline. If it is not given, it will be found.
-If the drawer does not exist, create it if FORCE is non-nil, or
-return nil."
+BEG is the beginning of the current subtree or the beginning of
+the document if before the first headline. If it is not given,
+it will be found. If the drawer does not exist, create it if
+FORCE is non-nil, or return nil."
(org-with-wide-buffer
- (when beg (goto-char beg))
- (unless (org-before-first-heading-p)
- (let ((beg (cond (beg)
+ (let ((beg (cond (beg (goto-char beg))
((or (not (featurep 'org-inlinetask))
(org-inlinetask-in-task-p))
- (org-back-to-heading t))
- (t (org-with-limited-levels (org-back-to-heading t))))))
- (forward-line)
- (when (looking-at-p org-planning-line-re) (forward-line))
- (cond ((looking-at org-property-drawer-re)
- (forward-line)
- (cons (point) (progn (goto-char (match-end 0))
- (line-beginning-position))))
- (force
- (goto-char beg)
- (org-insert-property-drawer)
- (let ((pos (save-excursion (search-forward ":END:")
- (line-beginning-position))))
- (cons pos pos))))))))
+ (org-back-to-heading-or-point-min t) (point))
+ (t (org-with-limited-levels
+ (org-back-to-heading-or-point-min t))
+ (point)))))
+ ;; Move point to its position according to its positional rules.
+ (cond ((org-before-first-heading-p)
+ (while (and (org-at-comment-p) (bolp)) (forward-line)))
+ (t (forward-line)
+ (when (looking-at-p org-planning-line-re) (forward-line))))
+ (cond ((looking-at org-property-drawer-re)
+ (forward-line)
+ (cons (point) (progn (goto-char (match-end 0))
+ (line-beginning-position))))
+ (force
+ (goto-char beg)
+ (org-insert-property-drawer)
+ (let ((pos (save-excursion (re-search-forward org-property-drawer-re)
+ (line-beginning-position))))
+ (cons pos pos)))))))
+
+(defun org-at-property-drawer-p ()
+ "Non-nil when point is at the first line of a property drawer."
+ (org-with-wide-buffer
+ (beginning-of-line)
+ (and (looking-at org-property-drawer-re)
+ (or (bobp)
+ (progn
+ (forward-line -1)
+ (cond ((org-at-heading-p))
+ ((looking-at org-planning-line-re)
+ (forward-line -1)
+ (org-at-heading-p))
+ ((looking-at org-comment-regexp)
+ (forward-line -1)
+ (while (and (not (bobp)) (looking-at org-comment-regexp))
+ (forward-line -1))
+ (looking-at org-comment-regexp))
+ (t nil)))))))
(defun org-at-property-p ()
"Non-nil when point is inside a property drawer.
@@ -13000,6 +12630,10 @@ variables is set."
(not (get-text-property 0 'org-unrestricted
(caar allowed))))))
(completing-read "Effort: " allowed nil must-match))))))
+ ;; Test whether the value can be interpreted as a duration before
+ ;; inserting it in the buffer:
+ (org-duration-to-minutes value)
+ ;; Maybe update the effort value:
(unless (equal current value)
(org-entry-put nil org-effort-property value))
(org-refresh-property '((effort . identity)
@@ -13029,7 +12663,7 @@ Return value is an alist. Keys are properties, as upcased
strings."
(org-with-point-at pom
(when (and (derived-mode-p 'org-mode)
- (ignore-errors (org-back-to-heading t)))
+ (org-back-to-heading-or-point-min t))
(catch 'exit
(let* ((beg (point))
(specific (and (stringp which) (upcase which)))
@@ -13072,7 +12706,7 @@ strings."
(push (cons "PRIORITY"
(if (looking-at org-priority-regexp)
(match-string-no-properties 2)
- (char-to-string org-default-priority)))
+ (char-to-string org-priority-default)))
props)
(when specific (throw 'exit props)))
(when (or (not specific) (string= specific "FILE"))
@@ -13238,13 +12872,13 @@ unless LITERAL-NIL is non-nil."
;; Return final values.
(and (not (equal value '(nil))) (nreverse value))))))
-(defun org--property-global-value (property literal-nil)
- "Return value for PROPERTY in current buffer.
+(defun org--property-global-or-keyword-value (property literal-nil)
+ "Return value for PROPERTY as defined by global properties or by keyword.
Return value is a string. Return nil if property is not set
-globally. Also return nil when PROPERTY is set to \"nil\",
-unless LITERAL-NIL is non-nil."
+globally or by keyword. Also return nil when PROPERTY is set to
+\"nil\", unless LITERAL-NIL is non-nil."
(let ((global
- (cdr (or (assoc-string property org-file-properties t)
+ (cdr (or (assoc-string property org-keyword-properties t)
(assoc-string property org-global-properties t)
(assoc-string property org-global-properties-fixed t)))))
(if literal-nil global (org-not-nil global))))
@@ -13393,12 +13027,12 @@ However, if LITERAL-NIL is set, return the string value \"nil\" instead."
value)))
(cond
((car v)
- (org-back-to-heading t)
+ (org-back-to-heading-or-point-min t)
(move-marker org-entry-property-inherited-from (point))
(throw 'exit nil))
- ((org-up-heading-safe))
+ ((org-up-heading-or-point-min))
(t
- (let ((global (org--property-global-value property literal-nil)))
+ (let ((global (org--property-global-or-keyword-value property literal-nil)))
(cond ((not global))
(value (setq value (concat global " " value)))
(t (setq value global))))
@@ -13430,8 +13064,8 @@ decreases scheduled or deadline date by one day."
(user-error "Invalid property name: \"%s\"" property)))
(org-with-point-at pom
(if (or (not (featurep 'org-inlinetask)) (org-inlinetask-in-task-p))
- (org-back-to-heading t)
- (org-with-limited-levels (org-back-to-heading t)))
+ (org-back-to-heading-or-point-min t)
+ (org-with-limited-levels (org-back-to-heading-or-point-min t)))
(let ((beg (point)))
(cond
((equal property "TODO")
@@ -13501,7 +13135,10 @@ COLUMN formats in the current buffer."
(props (append
(and specials org-special-properties)
(and defaults (cons org-effort-property org-default-properties))
- nil)))
+ ;; Get property names from #+PROPERTY keywords as well
+ (mapcar (lambda (s)
+ (nth 0 (split-string s)))
+ (cdar (org-collect-keywords '("PROPERTY")))))))
(org-with-wide-buffer
(goto-char (point-min))
(while (re-search-forward org-property-start-re nil t)
@@ -13549,7 +13186,15 @@ COLUMN formats in the current buffer."
(let ((p (match-string-no-properties 1 value)))
(unless (member-ignore-case p org-special-properties)
(push p props))))))))))
- (sort (delete-dups props) (lambda (a b) (string< (upcase a) (upcase b))))))
+ (sort (delete-dups
+ (append props
+ ;; for each xxx_ALL property, make sure the bare
+ ;; xxx property is also included
+ (delq nil (mapcar (lambda (p)
+ (and (string-match-p "._ALL\\'" p)
+ (substring p 0 -4)))
+ props))))
+ (lambda (a b) (string< (upcase a) (upcase b))))))
(defun org-property-values (key)
"List all non-nil values of property KEY in current buffer."
@@ -13567,21 +13212,26 @@ COLUMN formats in the current buffer."
Do nothing if the drawer already exists. The newly created
drawer is immediately hidden."
(org-with-wide-buffer
+ ;; Set point to the position where the drawer should be inserted.
(if (or (not (featurep 'org-inlinetask)) (org-inlinetask-in-task-p))
- (org-back-to-heading t)
- (org-with-limited-levels (org-back-to-heading t)))
- (forward-line)
- (when (looking-at-p org-planning-line-re) (forward-line))
+ (org-back-to-heading-or-point-min t)
+ (org-with-limited-levels (org-back-to-heading-or-point-min t)))
+ (if (org-before-first-heading-p)
+ (while (and (org-at-comment-p) (bolp)) (forward-line))
+ (progn
+ (forward-line)
+ (when (looking-at-p org-planning-line-re) (forward-line))))
(unless (looking-at-p org-property-drawer-re)
;; Make sure we start editing a line from current entry, not from
;; next one. It prevents extending text properties or overlays
;; belonging to the latter.
- (when (bolp) (backward-char))
- (let ((begin (1+ (point)))
+ (when (and (bolp) (> (point) (point-min))) (backward-char))
+ (let ((begin (if (bobp) (point) (1+ (point))))
(inhibit-read-only t))
- (insert "\n:PROPERTIES:\n:END:")
- (org-flag-drawer t nil (line-end-position 0) (point))
- (when (eobp) (insert "\n"))
+ (unless (bobp) (insert "\n"))
+ (insert ":PROPERTIES:\n:END:")
+ (org-flag-region (line-end-position 0) (point) t 'outline)
+ (when (or (eobp) (= begin (point-min))) (insert "\n"))
(org-indent-region begin (point))))))
(defun org-insert-drawer (&optional arg drawer)
@@ -13761,7 +13411,8 @@ part of the buffer."
(while (re-search-forward re nil t)
(when (if value (org-at-property-p)
(org-entry-get (point) property nil t))
- (throw 'exit (progn (org-back-to-heading t) (point)))))))))
+ (throw 'exit (progn (org-back-to-heading-or-point-min t)
+ (point)))))))))
(defun org-delete-property (property)
"In the current entry, delete PROPERTY."
@@ -13831,8 +13482,8 @@ completion."
(setq vals (org-with-point-at pom
(append org-todo-keywords-1 '("")))))
((equal property "PRIORITY")
- (let ((n org-lowest-priority))
- (while (>= n org-highest-priority)
+ (let ((n org-priority-lowest))
+ (while (>= n org-priority-highest)
(push (char-to-string n) vals)
(setq n (1- n)))))
((equal property "CATEGORY"))
@@ -13897,15 +13548,9 @@ completion."
(defun org-find-olp (path &optional this-buffer)
"Return a marker pointing to the entry at outline path OLP.
-If anything goes wrong, throw an error.
-You can wrap this call to catch the error like this:
-
- (condition-case msg
- (org-mobile-locate-entry (match-string 4))
- (error (nth 1 msg)))
-
-The return value will then be either a string with the error message,
-or a marker if everything is OK.
+If anything goes wrong, throw an error, and if you need to do
+something based on this error, you can catch it with
+`condition-case'.
If THIS-BUFFER is set, the outline path does not contain a file,
only headings."
@@ -14081,16 +13726,16 @@ non-nil."
(defun org-time-stamp-inactive (&optional arg)
"Insert an inactive time stamp.
-An inactive time stamp is enclosed in square brackets instead of angle
-brackets. It is inactive in the sense that it does not trigger agenda entries,
-does not link to the calendar and cannot be changed with the S-cursor keys.
-So these are more for recording a certain time/date.
+An inactive time stamp is enclosed in square brackets instead of
+angle brackets. It is inactive in the sense that it does not
+trigger agenda entries. So these are more for recording a
+certain time/date.
If the user specifies a time like HH:MM or if this command is called with
at least one prefix argument, the time stamp contains the date and the time.
Otherwise, only the date is included.
-When called with two universal prefix arguments, insert an active time stamp
+When called with two universal prefix arguments, insert an inactive time stamp
with the current time without prompting the user."
(interactive "P")
(org-time-stamp arg 'inactive))
@@ -14106,7 +13751,6 @@ with the current time without prompting the user."
(defvar org-overriding-default-time nil) ; dynamically scoped
(defvar org-read-date-overlay nil)
-(defvar org-dcst nil) ; dynamically scoped
(defvar org-read-date-history nil)
(defvar org-read-date-final-answer nil)
(defvar org-read-date-analyze-futurep nil)
@@ -14176,7 +13820,6 @@ user."
(if (equal org-with-time '(16))
'(0 0)
org-time-stamp-rounding-minutes))
- (org-dcst org-display-custom-times)
(ct (org-current-time))
(org-def (or org-overriding-default-time default-time ct))
(org-defdecode (decode-time org-def))
@@ -14295,7 +13938,7 @@ user."
" " (or org-ans1 org-ans2)))
(org-end-time-was-given nil)
(f (org-read-date-analyze ans org-def org-defdecode))
- (fmts (if org-dcst
+ (fmts (if org-display-custom-times
org-time-stamp-custom-formats
org-time-stamp-formats))
(fmt (if (or org-with-time
@@ -14961,7 +14604,7 @@ signaled."
(cdr errdata))))))))
(defun org-days-to-iso-week (days)
- "Return the iso week number."
+ "Return the ISO week number."
(require 'cal-iso)
(car (calendar-iso-from-absolute days)))
@@ -16041,7 +15684,7 @@ environment remains unintended."
;; Get indentation of next line unless at column 0.
(let ((ind (if (bolp) 0
(save-excursion
- (org-return-indent)
+ (org-return t)
(prog1 (current-indentation)
(when (progn (skip-chars-forward " \t") (eolp))
(delete-region beg (point)))))))
@@ -16086,7 +15729,10 @@ looks only before point, not after."
(catch 'exit
(let ((pos (point))
(dodollar (member "$" (plist-get org-format-latex-options :matchers)))
- (lim (save-excursion (org-backward-paragraph) (point)))
+ (lim (progn
+ (re-search-backward (concat "^\\(" paragraph-start "\\)") nil
+ 'move)
+ (point)))
dd-on str (start 0) m re)
(goto-char pos)
(when dodollar
@@ -16154,7 +15800,7 @@ BEG and END are buffer positions."
;; Emacs cannot overlay images from remote hosts. Create it in
;; `temporary-file-directory' instead.
(if (or (not file) (file-remote-p file))
- temporary-file-directory
+ temporary-file-directory
default-directory)
'overlays nil 'forbuffer org-preview-latex-default-process))))
@@ -16265,6 +15911,10 @@ Some of the options can be changed using the variable
(if (string= (match-string 0 value) "$$")
(insert "\\[" (substring value 2 -2) "\\]")
(insert "\\(" (substring value 1 -1) "\\)"))))
+ ((eq processing-type 'html)
+ (goto-char beg)
+ (delete-region beg end)
+ (insert (org-format-latex-as-html value)))
((assq processing-type org-preview-latex-process-alist)
;; Process to an image.
(cl-incf cnt)
@@ -16393,7 +16043,7 @@ inspection."
(write-region mathml nil mathml-file))
(when (called-interactively-p 'any)
(message mathml)))
- ((message "LaTeX to MathML conversion failed")
+ ((warn "LaTeX to MathML conversion failed")
(message shell-command-output)))
(delete-file tmp-in-file)
(when (file-exists-p tmp-out-file)
@@ -16430,6 +16080,14 @@ inspection."
;; Failed conversion. Return the LaTeX fragment verbatim
latex-frag)))
+(defun org-format-latex-as-html (latex-fragment)
+ "Convert LATEX-FRAGMENT to HTML.
+This uses `org-latex-to-html-convert-command', which see."
+ (let ((cmd (format-spec org-latex-to-html-convert-command
+ `((?i . ,latex-fragment)))))
+ (message "Running %s" cmd)
+ (shell-command-to-string cmd)))
+
(defun org--get-display-dpi ()
"Get the DPI of the display.
The function assumes that the display has the same pixel width in
@@ -16499,12 +16157,16 @@ a HTML file."
(setq bg (org-latex-color :background))
(setq bg (org-latex-color-format
(if (string= bg "Transparent") "white" bg))))
+ ;; Remove TeX \par at end of snippet to avoid trailing space.
+ (if (string-suffix-p string "\n")
+ (aset string (1- (length string)) ?%)
+ (setq string (concat string "%")))
(with-temp-file texfile
(insert latex-header)
(insert "\n\\begin{document}\n"
- "\\definecolor{fg}{rgb}{" fg "}\n"
- "\\definecolor{bg}{rgb}{" bg "}\n"
- "\n\\pagecolor{bg}\n"
+ "\\definecolor{fg}{rgb}{" fg "}%\n"
+ "\\definecolor{bg}{rgb}{" bg "}%\n"
+ "\n\\pagecolor{bg}%\n"
"\n{\\color{fg}\n"
string
"\n}\n"
@@ -16631,16 +16293,60 @@ INCLUDE-LINKED is passed to `org-display-inline-images'."
"No images to display inline")))))
(defun org-redisplay-inline-images ()
- "Refresh the display of inline images."
+ "Assure display of inline images and refresh them."
(interactive)
- (if (not org-inline-image-overlays)
- (org-toggle-inline-images)
- (org-toggle-inline-images)
+ (org-toggle-inline-images)
+ (unless org-inline-image-overlays
(org-toggle-inline-images)))
;; For without-x builds.
(declare-function image-refresh "image" (spec &optional frame))
+(defcustom org-display-remote-inline-images 'skip
+ "How to display remote inline images.
+Possible values of this option are:
+
+skip Don't display remote images.
+download Always download and display remote images.
+cache Display remote images, and open them in separate buffers
+ for caching. Silently update the image buffer when a file
+ change is detected."
+ :group 'org-appearance
+ :package-version '(Org . "9.4")
+ :type '(choice
+ (const :tag "Ignore remote images" skip)
+ (const :tag "Always display remote images" download)
+ (const :tag "Display and silently update remote images" cache))
+ :safe #'symbolp)
+
+(defun org--create-inline-image (file width)
+ "Create image located at FILE, or return nil.
+WIDTH is the width of the image. The image may not be created
+according to the value of `org-display-remote-inline-images'."
+ (let* ((remote? (file-remote-p file))
+ (file-or-data
+ (pcase org-display-remote-inline-images
+ ((guard (not remote?)) file)
+ (`download (with-temp-buffer
+ (set-buffer-multibyte nil)
+ (insert-file-contents-literally file)
+ (buffer-string)))
+ (`cache (let ((revert-without-query '(".")))
+ (with-current-buffer (find-file-noselect file)
+ (buffer-string))))
+ (`skip nil)
+ (other
+ (message "Invalid value of `org-display-remote-inline-images': %S"
+ other)
+ nil))))
+ (when file-or-data
+ (create-image file-or-data
+ (and (image-type-available-p 'imagemagick)
+ width
+ 'imagemagick)
+ remote?
+ :width width))))
+
(defun org-display-inline-images (&optional include-linked refresh beg end)
"Display inline images.
@@ -16759,11 +16465,7 @@ buffer boundaries with possible narrowing."
'org-image-overlay)))
(if (and (car-safe old) refresh)
(image-refresh (overlay-get (cdr old) 'display))
- (let ((image (create-image file
- (and (image-type-available-p 'imagemagick)
- width 'imagemagick)
- nil
- :width width)))
+ (let ((image (org--create-inline-image file width)))
(when image
(let ((ov (make-overlay
(org-element-property :begin link)
@@ -16778,7 +16480,9 @@ buffer boundaries with possible narrowing."
(overlay-put
ov 'modification-hooks
(list 'org-display-inline-remove-overlay))
- (overlay-put ov 'keymap image-map)
+ (when (<= 26 emacs-major-version)
+ (cl-assert (boundp 'image-map))
+ (overlay-put ov 'keymap image-map))
(push ov org-inline-image-overlays))))))))))))))))
(defun org-display-inline-remove-overlay (ov after _beg _end &optional _len)
@@ -16865,7 +16569,7 @@ overwritten, and the table is not marked as requiring realignment."
(1+ org-self-insert-command-undo-counter))))))))
(defun org-check-before-invisible-edit (kind)
- "Check is editing if kind KIND would be dangerous with invisible text around.
+ "Check if editing kind KIND would be dangerous with invisible text around.
The detailed reaction depends on the user option `org-catch-invisible-edits'."
;; First, try to get out of here as quickly as possible, to reduce overhead
(when (and org-catch-invisible-edits
@@ -17025,7 +16729,7 @@ word constituents."
(defvar org-ctrl-c-ctrl-c-hook nil
"Hook for functions attaching themselves to `C-c C-c'.
-This can be used to add additional functionality to the C-c C-c
+This can be used to add additional functionality to the `C-c C-c'
key which executes context-dependent commands. This hook is run
before any other test, while `org-ctrl-c-ctrl-c-final-hook' is
run after the last test.
@@ -17038,7 +16742,7 @@ context is wrong, just do nothing and return nil.")
(defvar org-ctrl-c-ctrl-c-final-hook nil
"Hook for functions attaching themselves to `C-c C-c'.
-This can be used to add additional functionality to the C-c C-c
+This can be used to add additional functionality to the `C-c C-c'
key which executes context-dependent commands. This hook is run
after any other test, while `org-ctrl-c-ctrl-c-hook' is run
before the first test.
@@ -17403,13 +17107,15 @@ individual commands for more information."
(call-interactively (if org-edit-timestamp-down-means-later
'org-timestamp-down 'org-timestamp-up)))
((and (not (eq org-support-shift-select 'always))
- org-enable-priority-commands
+ org-priority-enable-commands
(org-at-heading-p))
(call-interactively 'org-priority-up))
((and (not org-support-shift-select) (org-at-item-p))
(call-interactively 'org-previous-item))
((org-clocktable-try-shift 'up arg))
- ((org-at-table-p) (org-table-move-cell-up))
+ ((and (not (eq org-support-shift-select 'always))
+ (org-at-table-p))
+ (org-table-move-cell-up))
((run-hook-with-args-until-success 'org-shiftup-final-hook))
(org-support-shift-select
(org-call-for-shift-select 'previous-line))
@@ -17429,13 +17135,15 @@ individual commands for more information."
(call-interactively (if org-edit-timestamp-down-means-later
'org-timestamp-up 'org-timestamp-down)))
((and (not (eq org-support-shift-select 'always))
- org-enable-priority-commands
+ org-priority-enable-commands
(org-at-heading-p))
(call-interactively 'org-priority-down))
((and (not org-support-shift-select) (org-at-item-p))
(call-interactively 'org-next-item))
((org-clocktable-try-shift 'down arg))
- ((org-at-table-p) (org-table-move-cell-down))
+ ((and (not (eq org-support-shift-select 'always))
+ (org-at-table-p))
+ (org-table-move-cell-down))
((run-hook-with-args-until-success 'org-shiftdown-final-hook))
(org-support-shift-select
(org-call-for-shift-select 'next-line))
@@ -17473,7 +17181,9 @@ This does one of the following:
(org-at-property-p))
(call-interactively 'org-property-next-allowed-value))
((org-clocktable-try-shift 'right arg))
- ((org-at-table-p) (org-table-move-cell-right))
+ ((and (not (eq org-support-shift-select 'always))
+ (org-at-table-p))
+ (org-table-move-cell-right))
((run-hook-with-args-until-success 'org-shiftright-final-hook))
(org-support-shift-select
(org-call-for-shift-select 'forward-char))
@@ -17511,7 +17221,9 @@ This does one of the following:
(org-at-property-p))
(call-interactively 'org-property-previous-allowed-value))
((org-clocktable-try-shift 'left arg))
- ((org-at-table-p) (org-table-move-cell-left))
+ ((and (not (eq org-support-shift-select 'always))
+ (org-at-table-p))
+ (org-table-move-cell-left))
((run-hook-with-args-until-success 'org-shiftleft-final-hook))
(org-support-shift-select
(org-call-for-shift-select 'backward-char))
@@ -17588,23 +17300,12 @@ this numeric value."
(org-increase-number-at-point (- (or inc 1))))
(defun org-ctrl-c-ret ()
- "Call `org-table-hline-and-move' or `org-insert-heading' dep. on context."
+ "Call `org-table-hline-and-move' or `org-insert-heading'."
(interactive)
(cond
((org-at-table-p) (call-interactively 'org-table-hline-and-move))
(t (call-interactively 'org-insert-heading))))
-(defun org-find-visible ()
- (let ((s (point)))
- (while (and (not (= (point-max) (setq s (next-overlay-change s))))
- (get-char-property s 'invisible)))
- s))
-(defun org-find-invisible ()
- (let ((s (point)))
- (while (and (not (= (point-max) (setq s (next-overlay-change s))))
- (not (get-char-property s 'invisible))))
- s))
-
(defun org-copy-visible (beg end)
"Copy the visible parts of the region."
(interactive "r")
@@ -17712,6 +17413,7 @@ Otherwise, return a user error."
(pcase (org-element-type context)
(`footnote-reference (org-edit-footnote-reference))
(`inline-src-block (org-edit-inline-src-code))
+ (`latex-fragment (org-edit-latex-fragment))
(`timestamp (if (eq 'inactive (org-element-property :type context))
(call-interactively #'org-time-stamp-inactive)
(call-interactively #'org-time-stamp)))
@@ -17723,14 +17425,19 @@ Otherwise, return a user error."
This command does many different things, depending on context:
+- If column view is active, in agenda or org buffers, quit it.
+
+- If there are highlights, remove them.
+
- If a function in `org-ctrl-c-ctrl-c-hook' recognizes this location,
this is what we do.
- If the cursor is on a statistics cookie, update it.
-- If the cursor is in a headline, prompt for tags and insert them
- into the current line, aligned to `org-tags-column'. When called
- with prefix arg, realign all tags in the current buffer.
+- If the cursor is in a headline, in an agenda or an org buffer,
+ prompt for tags and insert them into the current line, aligned
+ to `org-tags-column'. When called with prefix arg, realign all
+ tags in the current buffer.
- If the cursor is in one of the special #+KEYWORD lines, this
triggers scanning the buffer for these lines and updating the
@@ -17764,6 +17471,7 @@ This command does many different things, depending on context:
inhibited by setting `org-babel-no-eval-on-ctrl-c-ctrl-c'."
(interactive "P")
(cond
+ ((bound-and-true-p org-columns-overlays) (org-columns-quit))
((or (bound-and-true-p org-clock-overlays) org-occur-highlights)
(when (boundp 'org-clock-overlays) (org-clock-remove-overlays))
(org-remove-occur-highlights)
@@ -17785,6 +17493,7 @@ This command does many different things, depending on context:
src-block statistics-cookie table table-cell table-row
timestamp)
t))
+ (radio-list-p (org-at-radio-list-p))
(type (org-element-type context)))
;; For convenience: at the first line of a paragraph on the same
;; line as an item, apply function on that item instead.
@@ -17831,39 +17540,81 @@ This command does many different things, depending on context:
;; unconditionally, whereas `C-u' will toggle its presence.
;; Without a universal argument, if the item has a checkbox,
;; toggle it. Otherwise repair the list.
- (let* ((box (org-element-property :checkbox context))
- (struct (org-element-property :structure context))
- (old-struct (copy-tree struct))
- (parents (org-list-parents-alist struct))
- (prevs (org-list-prevs-alist struct))
- (orderedp (org-not-nil (org-entry-get nil "ORDERED"))))
- (org-list-set-checkbox
- (org-element-property :begin context) struct
- (cond ((equal arg '(16)) "[-]")
- ((and (not box) (equal arg '(4))) "[ ]")
- ((or (not box) (equal arg '(4))) nil)
- ((eq box 'on) "[ ]")
- (t "[X]")))
- ;; Mimic `org-list-write-struct' but with grabbing a return
- ;; value from `org-list-struct-fix-box'.
- (org-list-struct-fix-ind struct parents 2)
- (org-list-struct-fix-item-end struct)
- (org-list-struct-fix-bul struct prevs)
- (org-list-struct-fix-ind struct parents)
- (let ((block-item
- (org-list-struct-fix-box struct parents prevs orderedp)))
- (if (and box (equal struct old-struct))
- (if (equal arg '(16))
- (message "Checkboxes already reset")
- (user-error "Cannot toggle this checkbox: %s"
- (if (eq box 'on)
- "all subitems checked"
- "unchecked subitems")))
- (org-list-struct-apply-struct struct old-struct)
- (org-update-checkbox-count-maybe))
- (when block-item
- (message "Checkboxes were removed due to empty box at line %d"
- (org-current-line block-item))))))
+ (if (or radio-list-p
+ (and (boundp org-list-checkbox-radio-mode)
+ org-list-checkbox-radio-mode))
+ (org-toggle-radio-button arg)
+ (let* ((box (org-element-property :checkbox context))
+ (struct (org-element-property :structure context))
+ (old-struct (copy-tree struct))
+ (parents (org-list-parents-alist struct))
+ (prevs (org-list-prevs-alist struct))
+ (orderedp (org-not-nil (org-entry-get nil "ORDERED"))))
+ (org-list-set-checkbox
+ (org-element-property :begin context) struct
+ (cond ((equal arg '(16)) "[-]")
+ ((and (not box) (equal arg '(4))) "[ ]")
+ ((or (not box) (equal arg '(4))) nil)
+ ((eq box 'on) "[ ]")
+ (t "[X]")))
+ ;; Mimic `org-list-write-struct' but with grabbing a return
+ ;; value from `org-list-struct-fix-box'.
+ (org-list-struct-fix-ind struct parents 2)
+ (org-list-struct-fix-item-end struct)
+ (org-list-struct-fix-bul struct prevs)
+ (org-list-struct-fix-ind struct parents)
+ (let ((block-item
+ (org-list-struct-fix-box struct parents prevs orderedp)))
+ (if (and box (equal struct old-struct))
+ (if (equal arg '(16))
+ (message "Checkboxes already reset")
+ (user-error "Cannot toggle this checkbox: %s"
+ (if (eq box 'on)
+ "all subitems checked"
+ "unchecked subitems")))
+ (org-list-struct-apply-struct struct old-struct)
+ (org-update-checkbox-count-maybe))
+ (when block-item
+ (message "Checkboxes were removed due to empty box at line %d"
+ (org-current-line block-item)))))))
+ (`plain-list
+ ;; At a plain list, with a double C-u argument, set
+ ;; checkboxes of each item to "[-]", whereas a single one
+ ;; will toggle their presence according to the state of the
+ ;; first item in the list. Without an argument, repair the
+ ;; list.
+ (if (or radio-list-p
+ (and (boundp org-list-checkbox-radio-mode)
+ org-list-checkbox-radio-mode))
+ (org-toggle-radio-button arg)
+ (let* ((begin (org-element-property :contents-begin context))
+ (struct (org-element-property :structure context))
+ (old-struct (copy-tree struct))
+ (first-box (save-excursion
+ (goto-char begin)
+ (looking-at org-list-full-item-re)
+ (match-string-no-properties 3)))
+ (new-box (cond ((equal arg '(16)) "[-]")
+ ((equal arg '(4)) (unless first-box "[ ]"))
+ ((equal first-box "[X]") "[ ]")
+ (t "[X]"))))
+ (cond
+ (arg
+ (dolist (pos
+ (org-list-get-all-items
+ begin struct (org-list-prevs-alist struct)))
+ (org-list-set-checkbox pos struct new-box)))
+ ((and first-box (eq (point) begin))
+ ;; For convenience, when point is at bol on the first
+ ;; item of the list and no argument is provided, simply
+ ;; toggle checkbox of that item, if any.
+ (org-list-set-checkbox begin struct new-box)))
+ (when (equal
+ (org-list-write-struct
+ struct (org-list-parents-alist struct) old-struct)
+ old-struct)
+ (message "Cannot update this checkbox"))
+ (org-update-checkbox-count-maybe))))
(`keyword
(let ((org-inhibit-startup-visibility-stuff t)
(org-startup-align-all-tables nil))
@@ -17872,40 +17623,6 @@ This command does many different things, depending on context:
(setq org-table-coordinate-overlays nil))
(org-save-outline-visibility 'use-markers (org-mode-restart)))
(message "Local setup has been refreshed"))
- (`plain-list
- ;; At a plain list, with a double C-u argument, set
- ;; checkboxes of each item to "[-]", whereas a single one
- ;; will toggle their presence according to the state of the
- ;; first item in the list. Without an argument, repair the
- ;; list.
- (let* ((begin (org-element-property :contents-begin context))
- (struct (org-element-property :structure context))
- (old-struct (copy-tree struct))
- (first-box (save-excursion
- (goto-char begin)
- (looking-at org-list-full-item-re)
- (match-string-no-properties 3)))
- (new-box (cond ((equal arg '(16)) "[-]")
- ((equal arg '(4)) (unless first-box "[ ]"))
- ((equal first-box "[X]") "[ ]")
- (t "[X]"))))
- (cond
- (arg
- (dolist (pos
- (org-list-get-all-items
- begin struct (org-list-prevs-alist struct)))
- (org-list-set-checkbox pos struct new-box)))
- ((and first-box (eq (point) begin))
- ;; For convenience, when point is at bol on the first
- ;; item of the list and no argument is provided, simply
- ;; toggle checkbox of that item, if any.
- (org-list-set-checkbox begin struct new-box)))
- (when (equal
- (org-list-write-struct
- struct (org-list-parents-alist struct) old-struct)
- old-struct)
- (message "Cannot update this checkbox"))
- (org-update-checkbox-count-maybe)))
((or `property-drawer `node-property)
(call-interactively #'org-property-action))
(`radio-target
@@ -17949,6 +17666,7 @@ Use `\\[org-edit-special]' to edit table.el tables"))
"`\\[org-ctrl-c-ctrl-c]' can do nothing useful here"))))))))
(defun org-mode-restart ()
+"Restart `org-mode'."
(interactive)
(let ((indent-status (bound-and-true-p org-indent-mode)))
(funcall major-mode)
@@ -17980,13 +17698,17 @@ Move point to the beginning of first heading or end of buffer."
(defun org-kill-note-or-show-branches ()
"Abort storing current note, or show just branches."
(interactive)
- (if org-finish-function
- (let ((org-note-abort t))
- (funcall org-finish-function))
- (if (org-before-first-heading-p)
- (org-show-branches-buffer)
- (outline-hide-subtree)
- (outline-show-branches))))
+ (cond (org-finish-function
+ (let ((org-note-abort t)) (funcall org-finish-function)))
+ ((org-before-first-heading-p)
+ (org-show-branches-buffer)
+ (org-hide-archived-subtrees (point-min) (point-max)))
+ (t
+ (let ((beg (progn (org-back-to-heading) (point)))
+ (end (save-excursion (org-end-of-subtree t t) (point))))
+ (outline-hide-subtree)
+ (outline-show-branches)
+ (org-hide-archived-subtrees beg end)))))
(defun org-delete-indentation (&optional arg)
"Join current line to previous and fix whitespace at join.
@@ -17994,7 +17716,9 @@ Move point to the beginning of first heading or end of buffer."
If previous line is a headline add to headline title. Otherwise
the function calls `delete-indentation'.
-With a non-nil optional argument, join it to the following one."
+I.e. with a non-nil optional argument, join the line with the
+following one. If there is a region then join the lines in that
+region."
(interactive "*P")
(if (save-excursion
(beginning-of-line (if arg 1 0))
@@ -18019,7 +17743,8 @@ With a non-nil optional argument, join it to the following one."
((not tags-column)) ;no tags
(org-auto-align-tags (org-align-tags))
(t (org--align-tags-here tags-column)))) ;preserve tags column
- (delete-indentation arg)))
+ (let ((current-prefix-arg arg))
+ (call-interactively #'delete-indentation))))
(defun org-open-line (n)
"Insert a new row in tables, call `open-line' elsewhere.
@@ -18031,20 +17756,31 @@ call `open-line' on the very first character."
(org-table-insert-row)
(open-line n)))
-(defun org-return (&optional indent)
+(defun org--newline (indent arg interactive)
+ "Call `newline-and-indent' or just `newline'.
+If INDENT is non-nil, call `newline-and-indent' with ARG to
+indent unconditionally; otherwise, call `newline' with ARG and
+INTERACTIVE, which can trigger indentation if
+`electric-indent-mode' is enabled."
+ (if indent
+ (org-newline-and-indent arg)
+ (newline arg interactive)))
+
+(defun org-return (&optional indent arg interactive)
"Goto next table row or insert a newline.
Calls `org-table-next-row' or `newline', depending on context.
When optional INDENT argument is non-nil, call
-`newline-and-indent' instead of `newline'.
+`newline-and-indent' with ARG, otherwise call `newline' with ARG
+and INTERACTIVE.
When `org-return-follows-link' is non-nil and point is on
a timestamp or a link, call `org-open-at-point'. However, it
will not happen if point is in a table or on a \"dead\"
object (e.g., within a comment). In these case, you need to use
`org-open-at-point' directly."
- (interactive)
+ (interactive "i\nP\np")
(let ((context (if org-return-follows-link (org-element-context)
(org-element-at-point))))
(cond
@@ -18095,45 +17831,47 @@ object (e.g., within a comment). In these case, you need to use
(t (org--align-tags-here tags-column))) ;preserve tags column
(end-of-line)
(org-show-entry)
- (if indent (newline-and-indent) (newline))
+ (org--newline indent arg interactive)
(when string (save-excursion (insert (org-trim string))))))
;; In a list, make sure indenting keeps trailing text within.
- ((and indent
- (not (eolp))
+ ((and (not (eolp))
(org-element-lineage context '(item)))
(let ((trailing-data
(delete-and-extract-region (point) (line-end-position))))
- (newline-and-indent)
+ (org--newline indent arg interactive)
(save-excursion (insert trailing-data))))
(t
;; Do not auto-fill when point is in an Org property drawer.
(let ((auto-fill-function (and (not (org-at-property-p))
auto-fill-function)))
- (if indent
- (newline-and-indent)
- (newline)))))))
+ (org--newline indent arg interactive))))))
-(defun org-return-indent ()
- "Goto next table row or insert a newline and indent.
-Calls `org-table-next-row' or `newline-and-indent', depending on
-context. See the individual commands for more information."
+(defun org-return-and-maybe-indent ()
+ "Goto next table row, or insert a newline.
+Call `org-table-next-row' or `org-return', depending on context.
+See the individual commands for more information.
+
+When inserting a newline, indent the new line if
+`electric-indent-mode' is disabled."
(interactive)
- (org-return t))
+ (org-return (not electric-indent-mode)))
(defun org-ctrl-c-tab (&optional arg)
"Toggle columns width in a table, or show children.
Call `org-table-toggle-column-width' if point is in a table.
-Otherwise, call `org-show-children'. ARG is the level to hide."
+Otherwise provide a compact view of the children. ARG is the
+level to hide."
(interactive "p")
- (if (org-at-table-p)
- (call-interactively #'org-table-toggle-column-width)
- (if (org-before-first-heading-p)
- (progn
- (org-flag-above-first-heading)
- (outline-hide-sublevels (or arg 1))
- (goto-char (point-min)))
- (outline-hide-subtree)
- (org-show-children arg))))
+ (cond
+ ((org-at-table-p)
+ (call-interactively #'org-table-toggle-column-width))
+ ((org-before-first-heading-p)
+ (save-excursion
+ (org-flag-above-first-heading)
+ (outline-hide-sublevels (or arg 1))))
+ (t
+ (outline-hide-subtree)
+ (org-show-children arg))))
(defun org-ctrl-c-star ()
"Compute table, or change heading status of lines.
@@ -18277,79 +18015,14 @@ an argument, unconditionally call `org-insert-heading'."
(t #'org-insert-heading)))))
;;; Menu entries
-
(defsubst org-in-subtree-not-table-p ()
"Are we in a subtree and not in a table?"
(and (not (org-before-first-heading-p))
(not (org-at-table-p))))
;; Define the Org mode menus
-(easy-menu-define org-tbl-menu org-mode-map "Tbl menu"
- '("Tbl"
- ["Align" org-ctrl-c-ctrl-c :active (org-at-table-p)]
- ["Next Field" org-cycle (org-at-table-p)]
- ["Previous Field" org-shifttab (org-at-table-p)]
- ["Next Row" org-return (org-at-table-p)]
- "--"
- ["Blank Field" org-table-blank-field (org-at-table-p)]
- ["Edit Field" org-table-edit-field (org-at-table-p)]
- ["Copy Field from Above" org-table-copy-down (org-at-table-p)]
- "--"
- ("Column"
- ["Move Column Left" org-metaleft (org-at-table-p)]
- ["Move Column Right" org-metaright (org-at-table-p)]
- ["Delete Column" org-shiftmetaleft (org-at-table-p)]
- ["Insert Column" org-shiftmetaright (org-at-table-p)]
- ["Shrink Column" org-table-toggle-column-width (org-at-table-p)])
- ("Row"
- ["Move Row Up" org-metaup (org-at-table-p)]
- ["Move Row Down" org-metadown (org-at-table-p)]
- ["Delete Row" org-shiftmetaup (org-at-table-p)]
- ["Insert Row" org-shiftmetadown (org-at-table-p)]
- ["Sort lines in region" org-table-sort-lines (org-at-table-p)]
- "--"
- ["Insert Hline" org-ctrl-c-minus (org-at-table-p)])
- ("Rectangle"
- ["Copy Rectangle" org-copy-special (org-at-table-p)]
- ["Cut Rectangle" org-cut-special (org-at-table-p)]
- ["Paste Rectangle" org-paste-special (org-at-table-p)]
- ["Fill Rectangle" org-table-wrap-region (org-at-table-p)])
- "--"
- ("Calculate"
- ["Set Column Formula" org-table-eval-formula (org-at-table-p)]
- ["Set Field Formula" (org-table-eval-formula '(4)) :active (org-at-table-p) :keys "C-u C-c ="]
- ["Edit Formulas" org-edit-special (org-at-table-p)]
- "--"
- ["Recalculate line" org-table-recalculate (org-at-table-p)]
- ["Recalculate all" (lambda () (interactive) (org-table-recalculate '(4))) :active (org-at-table-p) :keys "C-u C-c *"]
- ["Iterate all" (lambda () (interactive) (org-table-recalculate '(16))) :active (org-at-table-p) :keys "C-u C-u C-c *"]
- "--"
- ["Toggle Recalculate Mark" org-table-rotate-recalc-marks (org-at-table-p)]
- "--"
- ["Sum Column/Rectangle" org-table-sum
- (or (org-at-table-p) (org-region-active-p))]
- ["Which Column?" org-table-current-column (org-at-table-p)])
- ["Debug Formulas"
- org-table-toggle-formula-debugger
- :style toggle :selected (bound-and-true-p org-table-formula-debug)]
- ["Show Col/Row Numbers"
- org-table-toggle-coordinate-overlays
- :style toggle
- :selected (bound-and-true-p org-table-overlay-coordinates)]
- "--"
- ["Create" org-table-create (not (org-at-table-p))]
- ["Convert Region" org-table-convert-region (not (org-at-table-p 'any))]
- ["Import from File" org-table-import (not (org-at-table-p))]
- ["Export to File" org-table-export (org-at-table-p)]
- "--"
- ["Create/Convert from/to table.el" org-table-create-with-table.el t]
- "--"
- ("Plot"
- ["Ascii plot" orgtbl-ascii-plot :active (org-at-table-p) :keys "C-c \" a"]
- ["Gnuplot" org-plot/gnuplot :active (org-at-table-p) :keys "C-c \" g"])))
-
(easy-menu-define org-org-menu org-mode-map "Org menu"
- '("Org"
+ `("Org"
("Show/Hide"
["Cycle Visibility" org-cycle :active (or (bobp) (outline-on-heading-p))]
["Cycle Global Visibility" org-shifttab :active (not (org-at-table-p))]
@@ -18369,8 +18042,6 @@ an argument, unconditionally call `org-insert-heading'."
"--"
["Jump" org-goto t])
("Edit Structure"
- ["Refile Subtree" org-refile (org-in-subtree-not-table-p)]
- "--"
["Move Subtree Up" org-metaup (org-at-heading-p)]
["Move Subtree Down" org-metadown (org-at-heading-p)]
"--"
@@ -18393,6 +18064,7 @@ an argument, unconditionally call `org-insert-heading'."
["Convert to odd/even levels" org-convert-to-oddeven-levels t])
("Editing"
["Emphasis..." org-emphasize t]
+ ["Add block structure" org-insert-structure-template t]
["Edit Source Example" org-edit-special t]
"--"
["Footnote new/jump" org-footnote-action t]
@@ -18402,8 +18074,7 @@ an argument, unconditionally call `org-insert-heading'."
"--"
["Move Subtree to Archive file" org-archive-subtree (org-in-subtree-not-table-p)]
["Toggle ARCHIVE tag" org-toggle-archive-tag (org-in-subtree-not-table-p)]
- ["Move subtree to Archive sibling" org-archive-to-archive-sibling (org-in-subtree-not-table-p)]
- )
+ ["Move subtree to Archive sibling" org-archive-to-archive-sibling (org-in-subtree-not-table-p)])
"--"
("Hyperlinks"
["Store Link (Global)" org-store-link t]
@@ -18520,13 +18191,6 @@ an argument, unconditionally call `org-insert-heading'."
(org-inside-LaTeX-fragment-p)]
["Insert citation" org-reftex-citation t])
"--"
- ("MobileOrg"
- ["Push Files and Views" org-mobile-push t]
- ["Get Captured and Flagged" org-mobile-pull t]
- ["Find FLAGGED Tasks" (org-agenda nil "?") :active t :keys "\\[org-agenda] ?"]
- "--"
- ["Setup" (progn (require 'org-mobile) (customize-group 'org-mobile)) t])
- "--"
("Documentation"
["Show Version" org-version t]
["Info Documentation" org-info t]
@@ -18534,8 +18198,7 @@ an argument, unconditionally call `org-insert-heading'."
("Customize"
["Browse Org Group" org-customize t]
"--"
- ["Expand This Menu" org-create-customize-menu
- (fboundp 'customize-menu-create)])
+ ["Expand This Menu" org-create-customize-menu t])
["Send bug report" org-submit-bug-report t]
"--"
("Refresh/Reload"
@@ -18543,6 +18206,70 @@ an argument, unconditionally call `org-insert-heading'."
["Reload Org (after update)" org-reload t]
["Reload Org uncompiled" (org-reload t) :active t :keys "C-u C-c C-x !"])))
+(easy-menu-define org-tbl-menu org-mode-map "Org Table menu"
+ '("Table"
+ ["Align" org-ctrl-c-ctrl-c :active (org-at-table-p)]
+ ["Next Field" org-cycle (org-at-table-p)]
+ ["Previous Field" org-shifttab (org-at-table-p)]
+ ["Next Row" org-return (org-at-table-p)]
+ "--"
+ ["Blank Field" org-table-blank-field (org-at-table-p)]
+ ["Edit Field" org-table-edit-field (org-at-table-p)]
+ ["Copy Field from Above" org-table-copy-down (org-at-table-p)]
+ "--"
+ ("Column"
+ ["Move Column Left" org-metaleft (org-at-table-p)]
+ ["Move Column Right" org-metaright (org-at-table-p)]
+ ["Delete Column" org-shiftmetaleft (org-at-table-p)]
+ ["Insert Column" org-shiftmetaright (org-at-table-p)]
+ ["Shrink Column" org-table-toggle-column-width (org-at-table-p)])
+ ("Row"
+ ["Move Row Up" org-metaup (org-at-table-p)]
+ ["Move Row Down" org-metadown (org-at-table-p)]
+ ["Delete Row" org-shiftmetaup (org-at-table-p)]
+ ["Insert Row" org-shiftmetadown (org-at-table-p)]
+ ["Sort lines in region" org-table-sort-lines (org-at-table-p)]
+ "--"
+ ["Insert Hline" org-ctrl-c-minus (org-at-table-p)])
+ ("Rectangle"
+ ["Copy Rectangle" org-copy-special (org-at-table-p)]
+ ["Cut Rectangle" org-cut-special (org-at-table-p)]
+ ["Paste Rectangle" org-paste-special (org-at-table-p)]
+ ["Fill Rectangle" org-table-wrap-region (org-at-table-p)])
+ "--"
+ ("Calculate"
+ ["Set Column Formula" org-table-eval-formula (org-at-table-p)]
+ ["Set Field Formula" (org-table-eval-formula '(4)) :active (org-at-table-p) :keys "C-u C-c ="]
+ ["Edit Formulas" org-edit-special (org-at-table-p)]
+ "--"
+ ["Recalculate line" org-table-recalculate (org-at-table-p)]
+ ["Recalculate all" (lambda () (interactive) (org-table-recalculate '(4))) :active (org-at-table-p) :keys "C-u C-c *"]
+ ["Iterate all" (lambda () (interactive) (org-table-recalculate '(16))) :active (org-at-table-p) :keys "C-u C-u C-c *"]
+ "--"
+ ["Toggle Recalculate Mark" org-table-rotate-recalc-marks (org-at-table-p)]
+ "--"
+ ["Sum Column/Rectangle" org-table-sum
+ (or (org-at-table-p) (org-region-active-p))]
+ ["Which Column?" org-table-current-column (org-at-table-p)])
+ ["Debug Formulas"
+ org-table-toggle-formula-debugger
+ :style toggle :selected (bound-and-true-p org-table-formula-debug)]
+ ["Show Col/Row Numbers"
+ org-table-toggle-coordinate-overlays
+ :style toggle
+ :selected (bound-and-true-p org-table-overlay-coordinates)]
+ "--"
+ ["Create" org-table-create (not (org-at-table-p))]
+ ["Convert Region" org-table-convert-region (not (org-at-table-p 'any))]
+ ["Import from File" org-table-import (not (org-at-table-p))]
+ ["Export to File" org-table-export (org-at-table-p)]
+ "--"
+ ["Create/Convert from/to table.el" org-table-create-with-table.el t]
+ "--"
+ ("Plot"
+ ["Ascii plot" orgtbl-ascii-plot :active (org-at-table-p) :keys "C-c \" a"]
+ ["Gnuplot" org-plot/gnuplot :active (org-at-table-p) :keys "C-c \" g"])))
+
(defun org-info (&optional node)
"Read documentation for Org in the info system.
With optional NODE, go directly to that node."
@@ -18579,14 +18306,22 @@ information about your Org version and configuration."
(erase-buffer)
(insert "You are about to submit a bug report to the Org mailing list.
-We would like to add your full Org and Outline configuration to the
-bug report. This greatly simplifies the work of the maintainer and
-other experts on the mailing list.
+If your report is about Org installation, please read this section:
+https://orgmode.org/org.html#Installation
+
+Please read https://orgmode.org/org.html#Feedback on how to make
+a good report, it will help Org contributors fixing your problem.
+
+Search https://lists.gnu.org/archive/html/emacs-orgmode/ to see
+if the issue you are about to raise has already been dealt with.
+
+We also would like to add your full Org and Outline configuration
+to the bug report. It will help us debugging the issue.
-HOWEVER, some variables you have customized may contain private
+*HOWEVER*, some variables you have customized may contain private
information. The names of customers, colleagues, or friends, might
-appear in the form of file names, tags, todo states, or search strings.
-If you answer yes to the prompt, you might want to check and remove
+appear in the form of file names, tags, todo states or search strings.
+If you answer \"yes\" to the prompt, you might want to check and remove
such private information before sending the email.")
(add-text-properties (point-min) (point-max) '(face org-warning))
(when (yes-or-no-p "Include your Org configuration ")
@@ -18616,6 +18351,7 @@ Your bug report will be posted to the Org mailing list.
(defun org-install-agenda-files-menu ()
+ "Install agenda file menu."
(let ((bl (buffer-list)))
(save-excursion
(while bl
@@ -18708,20 +18444,17 @@ With prefix arg UNCOMPILED, load the uncompiled versions."
(interactive)
(org-load-modules-maybe)
(org-require-autoloaded-modules)
- (if (fboundp 'customize-menu-create)
- (progn
- (easy-menu-change
- '("Org") "Customize"
- `(["Browse Org group" org-customize t]
- "--"
- ,(customize-menu-create 'org)
- ["Set" Custom-set t]
- ["Save" Custom-save t]
- ["Reset to Current" Custom-reset-current t]
- ["Reset to Saved" Custom-reset-saved t]
- ["Reset to Standard Settings" Custom-reset-standard t]))
- (message "\"Org\"-menu now contains full customization menu"))
- (error "Cannot expand menu (outdated version of cus-edit.el)")))
+ (easy-menu-change
+ '("Org") "Customize"
+ `(["Browse Org group" org-customize t]
+ "--"
+ ,(customize-menu-create 'org)
+ ["Set" Custom-set t]
+ ["Save" Custom-save t]
+ ["Reset to Current" Custom-reset-current t]
+ ["Reset to Saved" Custom-reset-saved t]
+ ["Reset to Standard Settings" Custom-reset-standard t]))
+ (message "\"Org\"-menu now contains full customization menu"))
;;;; Miscellaneous stuff
@@ -18851,7 +18584,8 @@ and :keyword."
(when (memq 'org-formula faces)
(push (list :table-special
(previous-single-property-change p 'face)
- (next-single-property-change p 'face)) clist)))
+ (next-single-property-change p 'face))
+ clist)))
((org-at-table-p 'any)
(push (list :table-table) clist)))
(goto-char p)
@@ -18864,14 +18598,16 @@ and :keyword."
(re-search-backward "[ \t]*\\(#+BEGIN: clocktable\\)" nil t))
(match-beginning 1))
(and (re-search-forward "[ \t]*#\\+END:?" nil t)
- (match-end 0))) clist))
+ (match-end 0)))
+ clist))
((org-in-src-block-p)
(push (list :src-block
(and (or (looking-at "[ \t]*\\(#\\+BEGIN_SRC\\)")
(re-search-backward "[ \t]*\\(#+BEGIN_SRC\\)" nil t))
(match-beginning 1))
(and (search-forward "#+END_SRC" nil t)
- (match-beginning 0))) clist))))
+ (match-beginning 0)))
+ clist))))
(goto-char p)
;; Now the small context
@@ -18881,20 +18617,24 @@ and :keyword."
((memq 'org-link faces)
(push (list :link
(previous-single-property-change p 'face)
- (next-single-property-change p 'face)) clist))
+ (next-single-property-change p 'face))
+ clist))
((memq 'org-special-keyword faces)
(push (list :keyword
(previous-single-property-change p 'face)
- (next-single-property-change p 'face)) clist))
+ (next-single-property-change p 'face))
+ clist))
((setq o (cl-some
(lambda (o)
(and (eq (overlay-get o 'org-overlay-type) 'org-latex-overlay)
o))
(overlays-at (point))))
(push (list :latex-fragment
- (overlay-start o) (overlay-end o)) clist)
+ (overlay-start o) (overlay-end o))
+ clist)
(push (list :latex-preview
- (overlay-start o) (overlay-end o)) clist))
+ (overlay-start o) (overlay-end o))
+ clist))
((org-inside-LaTeX-fragment-p)
;; FIXME: positions wrong.
(push (list :latex-fragment (point) (point)) clist)))
@@ -19023,7 +18763,7 @@ earliest time on the cursor date that Org treats as that date
(let (date day defd tp hod mod)
(when with-time
(setq tp (get-text-property (point) 'time))
- (when (and tp (string-match "\\([0-9][0-9]\\):\\([0-9][0-9]\\)" tp))
+ (when (and tp (string-match "\\([0-2]?[0-9]\\):\\([0-5][0-9]\\)" tp))
(setq hod (string-to-number (match-string 1 tp))
mod (string-to-number (match-string 2 tp))))
(or tp (let ((now (decode-time)))
@@ -19081,6 +18821,11 @@ ELEMENT."
(t
(goto-char start)
(current-indentation))))
+ ((and
+ (eq org-adapt-indentation 'headline-data)
+ (memq type '(planning clock node-property property-drawer drawer)))
+ (org--get-expected-indentation
+ (org-element-property :parent element) t))
((memq type '(headline inlinetask nil))
(if (org-match-line "[ \t]*$")
(org--get-expected-indentation element t)
@@ -19094,7 +18839,8 @@ ELEMENT."
;; At first line: indent according to previous sibling, if any,
;; ignoring footnote definitions and inline tasks, or parent's
;; contents.
- ((= (line-beginning-position) start)
+ ((and ( = (line-beginning-position) start)
+ (eq org-adapt-indentation t))
(catch 'exit
(while t
(if (= (point-min) start) (throw 'exit 0)
@@ -19119,7 +18865,7 @@ ELEMENT."
(org--get-expected-indentation
(org-element-property :parent previous) t))))))))))
;; Otherwise, move to the first non-blank line above.
- (t
+ ((not (eq org-adapt-indentation 'headline-data))
(beginning-of-line)
(let ((pos (point)))
(skip-chars-backward " \r\t\n")
@@ -19161,7 +18907,9 @@ ELEMENT."
(goto-char start)
(current-indentation)))
;; In any other case, indent like the current line.
- (t (current-indentation)))))))))
+ (t (current-indentation)))))
+ ;; Finally, no indentation is needed, fall back to 0.
+ (t (current-indentation))))))
(defun org--align-node-property ()
"Align node property at point.
@@ -19219,31 +18967,28 @@ list structure. Instead, use \\<org-mode-map>`\\[org-shiftmetaleft]' or \
Also align node properties according to `org-property-format'."
(interactive)
- (cond
- ((org-at-heading-p) 'noindent)
- (t
+ (unless (org-at-heading-p)
(let* ((element (save-excursion (beginning-of-line) (org-element-at-point)))
(type (org-element-type element)))
(cond ((and (memq type '(plain-list item))
(= (line-beginning-position)
(org-element-property :post-affiliated element)))
- 'noindent)
+ nil)
((and (eq type 'latex-environment)
(>= (point) (org-element-property :post-affiliated element))
- (< (point) (org-with-wide-buffer
- (goto-char (org-element-property :end element))
- (skip-chars-backward " \r\t\n")
- (line-beginning-position 2))))
- 'noindent)
+ (< (point)
+ (org-with-point-at (org-element-property :end element)
+ (skip-chars-backward " \t\n")
+ (line-beginning-position 2))))
+ nil)
((and (eq type 'src-block)
org-src-tab-acts-natively
(> (line-beginning-position)
(org-element-property :post-affiliated element))
(< (line-beginning-position)
- (org-with-wide-buffer
- (goto-char (org-element-property :end element))
- (skip-chars-backward " \r\t\n")
- (line-beginning-position))))
+ (org-with-point-at (org-element-property :end element)
+ (skip-chars-backward " \t\n")
+ (line-beginning-position))))
(org-babel-do-key-sequence-in-edit-buffer (kbd "TAB")))
(t
(let ((column (org--get-expected-indentation element nil)))
@@ -19255,7 +19000,7 @@ Also align node properties according to `org-property-format'."
(when (eq type 'node-property)
(let ((column (current-column)))
(org--align-node-property)
- (org-move-to-column column)))))))))
+ (org-move-to-column column))))))))
(defun org-indent-region (start end)
"Indent each non-blank line in the region.
@@ -19670,12 +19415,17 @@ filling the current element."
(unwind-protect
(progn
(goto-char (region-end))
+ (skip-chars-backward " \t\n")
(while (> (point) start)
- (org-backward-paragraph)
- (org-fill-element justify)))
+ (org-fill-element justify)
+ (org-backward-paragraph)))
(goto-char origin)
(set-marker origin nil))))
- (t (org-fill-element justify)))
+ (t
+ (save-excursion
+ (when (org-match-line "[ \t]*$")
+ (skip-chars-forward " \t\n"))
+ (org-fill-element justify))))
;; If we didn't change anything in the buffer (and the buffer was
;; previously unmodified), then flip the modification status back
;; to "unchanged".
@@ -20377,7 +20127,8 @@ depending on context."
(if (<= end (point)) ;on tags part
(kill-region (point) (line-end-position))
(kill-region (point) end)))
- (org-align-tags))
+ ;; Only align tags when we are still on a heading:
+ (if (org-at-heading-p) (org-align-tags)))
(t (kill-region (point) (line-end-position)))))
(defun org-yank (&optional arg)
@@ -20486,8 +20237,18 @@ interactive command with similar behavior."
"Call `outline-back-to-heading', but provide a better error message."
(condition-case nil
(outline-back-to-heading invisible-ok)
- (error (error "Before first headline at position %d in buffer %s"
- (point) (current-buffer)))))
+ (error
+ (user-error "Before first headline at position %d in buffer %s"
+ (point) (current-buffer)))))
+
+(defun org-back-to-heading-or-point-min (&optional invisible-ok)
+ "Go back to heading or first point in buffer.
+If point is before first heading go to first point in buffer
+instead of back to heading."
+ (condition-case nil
+ (outline-back-to-heading invisible-ok)
+ (error
+ (goto-char (point-min)))))
(defun org-before-first-heading-p ()
"Before first heading?"
@@ -20515,12 +20276,31 @@ unless optional argument NO-INHERITANCE is non-nil."
(t
(save-excursion (and (org-up-heading-safe) (org-in-commented-heading-p))))))
+(defun org-in-archived-heading-p (&optional no-inheritance)
+ "Non-nil if point is under an archived heading.
+This function also checks ancestors of the current headline,
+unless optional argument NO-INHERITANCE is non-nil."
+ (cond
+ ((org-before-first-heading-p) nil)
+ ((let ((tags (org-get-tags nil 'local)))
+ (and tags
+ (cl-some (apply-partially #'string= org-archive-tag) tags))))
+ (no-inheritance nil)
+ (t
+ (save-excursion (and (org-up-heading-safe) (org-in-archived-heading-p))))))
+
(defun org-at-comment-p nil
"Return t if cursor is in a commented line."
(save-excursion
(save-match-data
(beginning-of-line)
- (looking-at "^[ \t]*# "))))
+ (looking-at org-comment-regexp))))
+
+(defun org-at-keyword-p nil
+ "Return t if cursor is at a keyword-line."
+ (save-excursion
+ (move-beginning-of-line 1)
+ (looking-at org-keyword-regexp)))
(defun org-at-drawer-p nil
"Return t if cursor is at a drawer keyword."
@@ -20569,6 +20349,17 @@ make a significant difference in outlines with very many siblings."
(re-search-backward (format "^\\*\\{1,%d\\} " level-up) nil t)
(funcall outline-level)))))
+(defun org-up-heading-or-point-min ()
+ "Move to the heading line of which the present is a subheading, or point-min.
+This version is needed to make point-min behave like a virtual
+heading of level 0 for property-inheritance. It will return the
+level of the headline found (down to 0) or nil if already at a
+point before the first headline or at point-min."
+ (when (ignore-errors (org-back-to-heading t))
+ (if (< 1 (funcall outline-level))
+ (org-up-heading-safe)
+ (unless (= (point) (point-min)) (goto-char (point-min))))))
+
(defun org-first-sibling-p ()
"Is this heading the first child of its parents?"
(interactive)
@@ -20669,28 +20460,31 @@ If there is no such heading, return nil."
(defun org-end-of-subtree (&optional invisible-ok to-heading)
"Goto to the end of a subtree."
;; This contains an exact copy of the original function, but it uses
- ;; `org-back-to-heading', to make it work also in invisible
- ;; trees. And is uses an invisible-ok argument.
+ ;; `org-back-to-heading-or-point-min', to make it work also in invisible
+ ;; trees and before first headline. And is uses an invisible-ok argument.
;; Under Emacs this is not needed, but the old outline.el needs this fix.
;; Furthermore, when used inside Org, finding the end of a large subtree
;; with many children and grandchildren etc, this can be much faster
;; than the outline version.
- (org-back-to-heading invisible-ok)
+ (org-back-to-heading-or-point-min invisible-ok)
(let ((first t)
(level (funcall outline-level)))
- (if (and (derived-mode-p 'org-mode) (< level 1000))
- ;; A true heading (not a plain list item), in Org
- ;; This means we can easily find the end by looking
- ;; only for the right number of stars. Using a regexp to do
- ;; this is so much faster than using a Lisp loop.
- (let ((re (concat "^\\*\\{1," (int-to-string level) "\\} ")))
- (forward-char 1)
- (and (re-search-forward re nil 'move) (beginning-of-line 1)))
- ;; something else, do it the slow way
- (while (and (not (eobp))
- (or first (> (funcall outline-level) level)))
- (setq first nil)
- (outline-next-heading)))
+ (cond ((= level 0)
+ (goto-char (point-max)))
+ ((and (derived-mode-p 'org-mode) (< level 1000))
+ ;; A true heading (not a plain list item), in Org
+ ;; This means we can easily find the end by looking
+ ;; only for the right number of stars. Using a regexp to do
+ ;; this is so much faster than using a Lisp loop.
+ (let ((re (concat "^\\*\\{1," (number-to-string level) "\\} ")))
+ (forward-char 1)
+ (and (re-search-forward re nil 'move) (beginning-of-line 1))))
+ (t
+ ;; something else, do it the slow way
+ (while (and (not (eobp))
+ (or first (> (funcall outline-level) level)))
+ (setq first nil)
+ (outline-next-heading))))
(unless to-heading
(when (memq (preceding-char) '(?\n ?\^M))
;; Go to end of line before heading
@@ -20702,26 +20496,50 @@ If there is no such heading, return nil."
(defun org-end-of-meta-data (&optional full)
"Skip planning line and properties drawer in current entry.
-When optional argument FULL is non-nil, also skip empty lines,
-clocking lines and regular drawers at the beginning of the
-entry."
+
+When optional argument FULL is t, also skip planning information,
+clocking lines and any kind of drawer.
+
+When FULL is non-nil but not t, skip planning information,
+clocking lines and only non-regular drawers, i.e. properties and
+logbook drawers."
(org-back-to-heading t)
(forward-line)
+ ;; Skip planning information.
(when (looking-at-p org-planning-line-re) (forward-line))
+ ;; Skip property drawer.
(when (looking-at org-property-drawer-re)
(goto-char (match-end 0))
(forward-line))
+ ;; When FULL is not nil, skip more.
(when (and full (not (org-at-heading-p)))
(catch 'exit
(let ((end (save-excursion (outline-next-heading) (point)))
(re (concat "[ \t]*$" "\\|" org-clock-line-re)))
(while (not (eobp))
- (cond ((looking-at-p org-drawer-regexp)
- (if (re-search-forward "^[ \t]*:END:[ \t]*$" end t)
- (forward-line)
- (throw 'exit t)))
- ((looking-at-p re) (forward-line))
- (t (throw 'exit t))))))))
+ (cond ;; Skip clock lines.
+ ((looking-at-p re) (forward-line))
+ ;; Skip logbook drawer.
+ ((looking-at-p org-logbook-drawer-re)
+ (if (re-search-forward "^[ \t]*:END:[ \t]*$" end t)
+ (forward-line)
+ (throw 'exit t)))
+ ;; When FULL is t, skip regular drawer too.
+ ((and (eq full t) (looking-at-p org-drawer-regexp))
+ (if (re-search-forward "^[ \t]*:END:[ \t]*$" end t)
+ (forward-line)
+ (throw 'exit t)))
+ (t (throw 'exit t))))))))
+
+(defun org--line-fully-invisible-p ()
+ "Return non-nil if the current line is fully invisible."
+ (let ((line-beg (line-beginning-position))
+ (line-pos (1- (line-end-position)))
+ (is-invisible t))
+ (while (and (< line-beg line-pos) is-invisible)
+ (setq is-invisible (org-invisible-p line-pos))
+ (setq line-pos (1- line-pos)))
+ is-invisible))
(defun org-forward-heading-same-level (arg &optional invisible-ok)
"Move forward to the ARG'th subheading at same level as this one.
@@ -20744,8 +20562,14 @@ non-nil it will also look at invisible ones."
(cond ((< l level) (setq count 0))
((and (= l level)
(or invisible-ok
- (not (org-invisible-p
- (line-beginning-position)))))
+ ;; FIXME: See commit a700fadd72 and the
+ ;; related discussion on why using
+ ;; `org--line-fully-invisible-p' is needed
+ ;; here, which is to serve the needs of an
+ ;; external package. If the change is
+ ;; wrong regarding Org itself, it should
+ ;; be removed.
+ (not (org--line-fully-invisible-p))))
(cl-decf count)
(when (= l level) (setq result (point)))))))
(goto-char result))
@@ -20758,175 +20582,332 @@ Stop at the first and last subheadings of a superior heading."
(org-forward-heading-same-level (if arg (- arg) -1) invisible-ok))
(defun org-next-visible-heading (arg)
- "Move to the next visible heading.
-
-This function wraps `outline-next-visible-heading' with
-`org-with-limited-levels' in order to skip over inline tasks and
-respect customization of `org-odd-levels-only'."
+ "Move to the next visible heading line.
+With ARG, repeats or can move backward if negative."
(interactive "p")
- (org-with-limited-levels
- (outline-next-visible-heading arg)))
+ (let ((regexp (concat "^" (org-get-limited-outline-regexp))))
+ (if (< arg 0)
+ (beginning-of-line)
+ (end-of-line))
+ (while (and (< arg 0) (re-search-backward regexp nil :move))
+ (unless (bobp)
+ (while (pcase (get-char-property-and-overlay (point) 'invisible)
+ (`(outline . ,o)
+ (goto-char (overlay-start o))
+ (re-search-backward regexp nil :move))
+ (_ nil))))
+ (cl-incf arg))
+ (while (and (> arg 0) (re-search-forward regexp nil t))
+ (while (pcase (get-char-property-and-overlay (point) 'invisible)
+ (`(outline . ,o)
+ (goto-char (overlay-end o))
+ (re-search-forward regexp nil :move))
+ (_
+ (end-of-line)
+ nil))) ;leave the loop
+ (cl-decf arg))
+ (if (> arg 0) (goto-char (point-max)) (beginning-of-line))))
(defun org-previous-visible-heading (arg)
"Move to the previous visible heading.
-
-This function wraps `outline-previous-visible-heading' with
-`org-with-limited-levels' in order to skip over inline tasks and
-respect customization of `org-odd-levels-only'."
+With ARG, repeats or can move forward if negative."
(interactive "p")
- (org-with-limited-levels
- (outline-previous-visible-heading arg)))
+ (org-next-visible-heading (- arg)))
+
+(defun org-forward-paragraph (&optional arg)
+ "Move forward by a paragraph, or equivalent, unit.
+
+With argument ARG, do it ARG times;
+a negative argument ARG = -N means move backward N paragraphs.
-(defun org-forward-paragraph ()
- "Move forward to beginning of next paragraph or equivalent.
+The function moves point between two structural
+elements (paragraphs, tables, lists, etc.).
-The function moves point to the beginning of the next visible
-structural element, which can be a paragraph, a table, a list
-item, etc. It also provides some special moves for convenience:
+It also provides the following special moves for convenience:
- - On an affiliated keyword, jump to the beginning of the
- relative element.
- - On an item or a footnote definition, move to the second
- element inside, if any.
- - On a table or a property drawer, jump after it.
- - On a verse or source block, stop after blank lines."
+ - on a table or a property drawer, move to its beginning;
+ - on comment, example, export, source and verse blocks, stop
+ at blank lines;
+ - skip consecutive clocks, diary S-exps, and keywords."
+ (interactive "^p")
+ (unless arg (setq arg 1))
+ (if (< arg 0) (org-backward-paragraph (- arg))
+ (while (and (> arg 0) (not (eobp)))
+ (org--forward-paragraph-once)
+ (cl-decf arg))
+ ;; Return moves left.
+ arg))
+
+(defun org-backward-paragraph (&optional arg)
+ "Move backward by a paragraph, or equivalent, unit.
+
+With argument ARG, do it ARG times;
+a negative argument ARG = -N means move forward N paragraphs.
+
+The function moves point between two structural
+elements (paragraphs, tables, lists, etc.).
+
+It also provides the following special moves for convenience:
+
+ - on a table or a property drawer, move to its beginning;
+ - on comment, example, export, source and verse blocks, stop
+ at blank lines;
+ - skip consecutive clocks, diary S-exps, and keywords."
+ (interactive "^p")
+ (unless arg (setq arg 1))
+ (if (< arg 0) (org-forward-paragraph (- arg))
+ (while (and (> arg 0) (not (bobp)))
+ (org--backward-paragraph-once)
+ (cl-decf arg))
+ ;; Return moves left.
+ arg))
+
+(defun org--paragraph-at-point ()
+ "Return paragraph, or equivalent, element at point.
+
+Paragraph element at point is the element at point, with the
+following special cases:
+
+- treat table rows (resp. node properties) as the table
+ \(resp. property drawer) containing them.
+
+- treat plain lists with an item every line as a whole.
+
+- treat consecutive keywords, clocks, and diary-sexps as a single
+ block.
+
+Function may return a real element, or a pseudo-element with type
+`pseudo-paragraph'."
+ (let* ((e (org-element-at-point))
+ (type (org-element-type e))
+ ;; If we need to fake a new pseudo-element, triplet is
+ ;;
+ ;; (BEG END PARENT)
+ ;;
+ ;; where BEG and END are element boundaries, and PARENT the
+ ;; element containing it, or nil.
+ (triplet
+ (cond
+ ((memq type '(table property-drawer))
+ (list (org-element-property :begin e)
+ (org-element-property :end e)
+ (org-element-property :parent e)))
+ ((memq type '(node-property table-row))
+ (let ((e (org-element-property :parent e)))
+ (list (org-element-property :begin e)
+ (org-element-property :end e)
+ (org-element-property :parent e))))
+ ((memq type '(clock diary-sexp keyword))
+ (let* ((regexp (pcase type
+ (`clock org-clock-line-re)
+ (`diary-sexp "%%(")
+ (_ org-keyword-regexp)))
+ (end (if (< 0 (org-element-property :post-blank e))
+ (org-element-property :end e)
+ (org-with-wide-buffer
+ (forward-line)
+ (while (looking-at regexp) (forward-line))
+ (skip-chars-forward " \t\n")
+ (line-beginning-position))))
+ (begin (org-with-point-at (org-element-property :begin e)
+ (while (and (not (bobp)) (looking-at regexp))
+ (forward-line -1))
+ ;; We may have gotten one line too far.
+ (if (looking-at regexp)
+ (point)
+ (line-beginning-position 2)))))
+ (list begin end (org-element-property :parent e))))
+ ;; Find the full plain list containing point, the check it
+ ;; contains exactly one line per item.
+ ((let ((l (org-element-lineage e '(plain-list) t)))
+ (while (memq (org-element-type (org-element-property :parent l))
+ '(item plain-list))
+ (setq l (org-element-property :parent l)))
+ (and l
+ (org-with-point-at (org-element-property :post-affiliated l)
+ (forward-line (length (org-element-property :structure l)))
+ (= (point) (org-element-property :contents-end l)))
+ ;; Return value.
+ (list (org-element-property :begin l)
+ (org-element-property :end l)
+ (org-element-property :parent l)))))
+ (t nil)))) ;no triplet: return element
+ (pcase triplet
+ (`(,b ,e ,p)
+ (org-element-create
+ 'pseudo-paragraph
+ (list :begin b :end e :parent p :post-blank 0 :post-affiliated b)))
+ (_ e))))
+
+(defun org--forward-paragraph-once ()
+ "Move forward to end of paragraph or equivalent, once.
+See `org-forward-paragraph'."
(interactive)
- (unless (eobp)
- (let* ((deactivate-mark nil)
- (element (org-element-at-point))
- (type (org-element-type element))
- (post-affiliated (org-element-property :post-affiliated element))
- (contents-begin (org-element-property :contents-begin element))
- (contents-end (org-element-property :contents-end element))
- (end (let ((end (org-element-property :end element)) (parent element))
- (while (and (setq parent (org-element-property :parent parent))
- (= (org-element-property :contents-end parent) end))
- (setq end (org-element-property :end parent)))
- end)))
- (cond ((not element)
- (skip-chars-forward " \r\t\n")
- (or (eobp) (beginning-of-line)))
- ;; On affiliated keywords, move to element's beginning.
- ((< (point) post-affiliated)
- (goto-char post-affiliated))
- ;; At a table row, move to the end of the table. Similarly,
- ;; at a node property, move to the end of the property
- ;; drawer.
- ((memq type '(node-property table-row))
- (goto-char (org-element-property
- :end (org-element-property :parent element))))
- ((memq type '(property-drawer table)) (goto-char end))
- ;; Consider blank lines as separators in verse and source
- ;; blocks to ease editing.
- ((memq type '(src-block verse-block))
- (when (eq type 'src-block)
- (setq contents-end
- (save-excursion (goto-char end)
- (skip-chars-backward " \r\t\n")
- (line-beginning-position))))
- (beginning-of-line)
- (when (looking-at "[ \t]*$") (skip-chars-forward " \r\t\n"))
- (if (not (re-search-forward "^[ \t]*$" contents-end t))
- (goto-char end)
- (skip-chars-forward " \r\t\n")
- (if (= (point) contents-end) (goto-char end)
- (beginning-of-line))))
- ;; With no contents, just skip element.
- ((not contents-begin) (goto-char end))
- ;; If contents are invisible, skip the element altogether.
- ((org-invisible-p (line-end-position))
- (cl-case type
- (headline
- (org-with-limited-levels (outline-next-visible-heading 1)))
- ;; At a plain list, make sure we move to the next item
- ;; instead of skipping the whole list.
- (plain-list (forward-char)
- (org-forward-paragraph))
- (otherwise (goto-char end))))
- ((>= (point) contents-end) (goto-char end))
- ((>= (point) contents-begin)
- ;; This can only happen on paragraphs and plain lists.
- (cl-case type
- (paragraph (goto-char end))
- ;; At a plain list, try to move to second element in
- ;; first item, if possible.
- (plain-list (end-of-line)
- (org-forward-paragraph))))
- ;; When contents start on the middle of a line (e.g. in
- ;; items and footnote definitions), try to reach first
- ;; element starting after current line.
- ((> (line-end-position) contents-begin)
- (end-of-line)
- (org-forward-paragraph))
- (t (goto-char contents-begin))))))
-
-(defun org-backward-paragraph ()
- "Move backward to start of previous paragraph or equivalent.
-
-The function moves point to the beginning of the current
-structural element, which can be a paragraph, a table, a list
-item, etc., or to the beginning of the previous visible one if
-point is already there. It also provides some special moves for
-convenience:
-
- - On an affiliated keyword, jump to the first one.
- - On a table or a property drawer, move to its beginning.
- - On comment, example, export, src and verse blocks, stop
- before blank lines."
+ (save-restriction
+ (widen)
+ (skip-chars-forward " \t\n")
+ (cond
+ ((eobp) nil)
+ ;; When inside a folded part, move out of it.
+ ((pcase (get-char-property-and-overlay (point) 'invisible)
+ (`(,(or `outline `org-hide-block) . ,o)
+ (goto-char (overlay-end o))
+ (forward-line)
+ t)
+ (_ nil)))
+ (t
+ (let* ((element (org--paragraph-at-point))
+ (type (org-element-type element))
+ (contents-begin (org-element-property :contents-begin element))
+ (end (org-element-property :end element))
+ (post-affiliated (org-element-property :post-affiliated element)))
+ (cond
+ ((eq type 'plain-list)
+ (forward-char)
+ (org--forward-paragraph-once))
+ ;; If the element is folded, skip it altogether.
+ ((pcase (org-with-point-at post-affiliated
+ (get-char-property-and-overlay (line-end-position)
+ 'invisible))
+ (`(,(or `outline `org-hide-block) . ,o)
+ (goto-char (overlay-end o))
+ (forward-line)
+ t)
+ (_ nil)))
+ ;; At a greater element, move inside.
+ ((and contents-begin
+ (> contents-begin (point))
+ (not (eq type 'paragraph)))
+ (goto-char contents-begin)
+ ;; Items and footnote definitions contents may not start at
+ ;; the beginning of the line. In this case, skip until the
+ ;; next paragraph.
+ (cond
+ ((not (bolp)) (org--forward-paragraph-once))
+ ((org-previous-line-empty-p) (forward-line -1))
+ (t nil)))
+ ;; Move between empty lines in some blocks.
+ ((memq type '(comment-block example-block export-block src-block
+ verse-block))
+ (let ((contents-start
+ (org-with-point-at post-affiliated
+ (line-beginning-position 2))))
+ (if (< (point) contents-start)
+ (goto-char contents-start)
+ (let ((contents-end
+ (org-with-point-at end
+ (skip-chars-backward " \t\n")
+ (line-beginning-position))))
+ (cond
+ ((>= (point) contents-end)
+ (goto-char end)
+ (skip-chars-backward " \t\n")
+ (forward-line))
+ ((re-search-forward "^[ \t]*\n" contents-end :move)
+ (forward-line -1))
+ (t nil))))))
+ (t
+ ;; Move to element's end.
+ (goto-char end)
+ (skip-chars-backward " \t\n")
+ (forward-line))))))))
+
+(defun org--backward-paragraph-once ()
+ "Move backward to start of paragraph or equivalent, once.
+See `org-backward-paragraph'."
(interactive)
- (unless (bobp)
- (let* ((deactivate-mark nil)
- (element (org-element-at-point))
- (type (org-element-type element))
- (contents-end (org-element-property :contents-end element))
- (post-affiliated (org-element-property :post-affiliated element))
- (begin (org-element-property :begin element))
- (special? ;blocks handled specially
- (memq type '(comment-block example-block export-block src-block
- verse-block)))
- (contents-begin
- (if special?
- ;; These types have no proper contents. Fake line
- ;; below the block opening line as contents beginning.
- (save-excursion (goto-char begin) (line-beginning-position 2))
- (org-element-property :contents-begin element))))
- (cond
- ((not element) (goto-char (point-min)))
- ((= (point) begin)
- (backward-char)
- (org-backward-paragraph))
- ((<= (point) post-affiliated) (goto-char begin))
- ;; Special behavior: on a table or a property drawer, move to
- ;; its beginning.
- ((memq type '(node-property table-row))
- (goto-char (org-element-property
- :post-affiliated (org-element-property :parent element))))
- (special?
- (if (<= (point) contents-begin) (goto-char post-affiliated)
- ;; Inside a verse block, see blank lines as paragraph
- ;; separators.
- (let ((origin (point)))
- (skip-chars-backward " \r\t\n" contents-begin)
- (when (re-search-backward "^[ \t]*$" contents-begin 'move)
- (skip-chars-forward " \r\t\n" origin)
- (if (= (point) origin) (goto-char contents-begin)
- (beginning-of-line))))))
- ((eq type 'paragraph) (goto-char contents-begin)
- ;; When at first paragraph in an item or a footnote definition,
- ;; move directly to beginning of line.
- (let ((parent-contents
- (org-element-property
- :contents-begin (org-element-property :parent element))))
- (when (and parent-contents (= parent-contents contents-begin))
- (beginning-of-line))))
- ;; At the end of a greater element, move to the beginning of
- ;; the last element within.
- ((and contents-end (>= (point) contents-end))
- (goto-char (1- contents-end))
- (org-backward-paragraph))
- (t (goto-char (or post-affiliated begin))))
- ;; Ensure we never leave point invisible.
- (when (org-invisible-p (point)) (beginning-of-visual-line)))))
+ (save-restriction
+ (widen)
+ (cond
+ ((bobp) nil)
+ ;; Blank lines at the beginning of the buffer.
+ ((and (org-match-line "^[ \t]*$")
+ (save-excursion (skip-chars-backward " \t\n") (bobp)))
+ (goto-char (point-min)))
+ ;; When inside a folded part, move out of it.
+ ((pcase (get-char-property-and-overlay (1- (point)) 'invisible)
+ (`(,(or `outline `org-hide-block) . ,o)
+ (goto-char (1- (overlay-start o)))
+ (org--backward-paragraph-once)
+ t)
+ (_ nil)))
+ (t
+ (let* ((element (org--paragraph-at-point))
+ (type (org-element-type element))
+ (begin (org-element-property :begin element))
+ (post-affiliated (org-element-property :post-affiliated element))
+ (contents-end (org-element-property :contents-end element))
+ (end (org-element-property :end element))
+ (parent (org-element-property :parent element))
+ (reach
+ ;; Move to the visible empty line above position P, or
+ ;; to position P. Return t.
+ (lambda (p)
+ (goto-char p)
+ (when (and (org-previous-line-empty-p)
+ (let ((end (line-end-position 0)))
+ (or (= end (point-min))
+ (not (org-invisible-p (1- end))))))
+ (forward-line -1))
+ t)))
+ (cond
+ ;; Already at the beginning of an element.
+ ((= begin (point))
+ (cond
+ ;; There is a blank line above. Move there.
+ ((and (org-previous-line-empty-p)
+ (not (org-invisible-p (1- (line-end-position 0)))))
+ (forward-line -1))
+ ;; At the beginning of the first element within a greater
+ ;; element. Move to the beginning of the greater element.
+ ((and parent (= begin (org-element-property :contents-begin parent)))
+ (funcall reach (org-element-property :begin parent)))
+ ;; Since we have to move anyway, find the beginning
+ ;; position of the element above.
+ (t
+ (forward-char -1)
+ (org--backward-paragraph-once))))
+ ;; Skip paragraphs at the very beginning of footnote
+ ;; definitions or items.
+ ((and (eq type 'paragraph)
+ (org-with-point-at begin (not (bolp))))
+ (funcall reach (progn (goto-char begin) (line-beginning-position))))
+ ;; If the element is folded, skip it altogether.
+ ((org-with-point-at post-affiliated
+ (org-invisible-p (line-end-position) t))
+ (funcall reach begin))
+ ;; At the end of a greater element, move inside.
+ ((and contents-end
+ (<= contents-end (point))
+ (not (eq type 'paragraph)))
+ (cond
+ ((memq type '(footnote-definition plain-list))
+ (skip-chars-backward " \t\n")
+ (org--backward-paragraph-once))
+ ((= contents-end (point))
+ (forward-char -1)
+ (org--backward-paragraph-once))
+ (t
+ (goto-char contents-end))))
+ ;; Move between empty lines in some blocks.
+ ((and (memq type '(comment-block example-block export-block src-block
+ verse-block))
+ (let ((contents-start
+ (org-with-point-at post-affiliated
+ (line-beginning-position 2))))
+ (when (> (point) contents-start)
+ (let ((contents-end
+ (org-with-point-at end
+ (skip-chars-backward " \t\n")
+ (line-beginning-position))))
+ (if (> (point) contents-end)
+ (progn (goto-char contents-end) t)
+ (skip-chars-backward " \t\n" begin)
+ (re-search-backward "^[ \t]*\n" contents-start :move)
+ t))))))
+ ;; Move to element's start.
+ (t
+ (funcall reach begin))))))))
(defun org-forward-element ()
"Move forward by one element.
@@ -21108,10 +21089,11 @@ ones already marked."
(set-mark
(save-excursion
(goto-char (mark))
- (goto-char (org-element-property :end (org-element-at-point)))))
+ (goto-char (org-element-property :end (org-element-at-point)))
+ (point)))
(let ((element (org-element-at-point)))
(end-of-line)
- (push-mark (org-element-property :end element) t t)
+ (push-mark (min (point-max) (org-element-property :end element)) t t)
(goto-char (org-element-property :begin element))))))
(defun org-narrow-to-element ()
@@ -21231,4 +21213,8 @@ Started from `gnus-info-find-node'."
(run-hooks 'org-load-hook)
+;; Local variables:
+;; generated-autoload-file: "org-loaddefs.el"
+;; End:
+
;;; org.el ends here