summaryrefslogtreecommitdiff
path: root/lisp/org/org-element.el
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/org/org-element.el')
-rw-r--r--lisp/org/org-element.el430
1 files changed, 266 insertions, 164 deletions
diff --git a/lisp/org/org-element.el b/lisp/org/org-element.el
index 04e2fda55e3..56b3cc4131f 100644
--- a/lisp/org/org-element.el
+++ b/lisp/org/org-element.el
@@ -58,10 +58,55 @@
;;; Code:
-(require 'org)
(require 'avl-tree)
(require 'cl-lib)
-
+(require 'ol)
+(require 'org)
+(require 'org-compat)
+(require 'org-entities)
+(require 'org-footnote)
+(require 'org-list)
+(require 'org-macs)
+(require 'org-table)
+
+(declare-function org-at-heading-p "org" (&optional _))
+(declare-function org-end-of-subtree "org" (&optional invisible-ok to-heading))
+(declare-function org-escape-code-in-string "org-src" (s))
+(declare-function org-find-visible "org" ())
+(declare-function org-macro-escape-arguments "org-macro" (&rest args))
+(declare-function org-macro-extract-arguments "org-macro" (s))
+(declare-function org-reduced-level "org" (l))
+(declare-function org-unescape-code-in-string "org-src" (s))
+(declare-function outline-next-heading "outline" ())
+(declare-function outline-previous-heading "outline" ())
+
+(defvar org-archive-tag)
+(defvar org-clock-line-re)
+(defvar org-closed-string)
+(defvar org-comment-string)
+(defvar org-complex-heading-regexp)
+(defvar org-dblock-start-re)
+(defvar org-deadline-string)
+(defvar org-done-keywords)
+(defvar org-drawer-regexp)
+(defvar org-edit-src-content-indentation)
+(defvar org-emph-re)
+(defvar org-emphasis-regexp-components)
+(defvar org-keyword-time-not-clock-regexp)
+(defvar org-match-substring-regexp)
+(defvar org-odd-levels-only)
+(defvar org-outline-regexp-bol)
+(defvar org-planning-line-re)
+(defvar org-property-drawer-re)
+(defvar org-property-format)
+(defvar org-property-re)
+(defvar org-scheduled-string)
+(defvar org-src-preserve-indentation)
+(defvar org-tags-column)
+(defvar org-time-stamp-formats)
+(defvar org-todo-regexp)
+(defvar org-ts-regexp-both)
+(defvar org-verbatim-re)
;;; Definitions And Rules
@@ -91,7 +136,7 @@ specially in `org-element--object-lex'.")
(setq org-element-paragraph-separate
(concat "^\\(?:"
;; Headlines, inlinetasks.
- org-outline-regexp "\\|"
+ "\\*+ " "\\|"
;; Footnote definitions.
"\\[fn:[-_[:word:]]+\\]" "\\|"
;; Diary sexps.
@@ -117,7 +162,7 @@ specially in `org-element--object-lex'.")
;; LaTeX environments.
"\\\\begin{\\([A-Za-z0-9*]+\\)}" "\\|"
;; Clock lines.
- (regexp-quote org-clock-string) "\\|"
+ "CLOCK:" "\\|"
;; Lists.
(let ((term (pcase org-plain-list-ordered-item-terminator
(?\) ")") (?. "\\.") (_ "[.)]")))
@@ -307,8 +352,9 @@ Don't modify it, set `org-element-affiliated-keywords' instead.")
(strike-through ,@standard-set)
(subscript ,@standard-set)
(superscript ,@standard-set)
- ;; Ignore inline babel call and inline src block as formulas are
- ;; possible. Also ignore line breaks and statistics cookies.
+ ;; Ignore inline babel call and inline source block as formulas
+ ;; are possible. Also ignore line breaks and statistics
+ ;; cookies.
(table-cell bold code entity export-snippet footnote-reference italic
latex-fragment link macro radio-target strike-through
subscript superscript target timestamp underline verbatim)
@@ -491,6 +537,7 @@ objects, or a strings.
The function takes care of setting `:parent' property for CHILD.
Return parent element."
+ (declare (indent 1))
(if (not children) parent
;; Link every child to PARENT. If PARENT is nil, it is a secondary
;; string: parent is the list itself.
@@ -677,7 +724,7 @@ Assume point is at the beginning of the block."
(defun org-element-center-block-interpreter (_ contents)
"Interpret a center-block element as Org syntax.
CONTENTS is the contents of the element."
- (format "#+BEGIN_CENTER\n%s#+END_CENTER" contents))
+ (format "#+begin_center\n%s#+end_center" contents))
;;;; Drawer
@@ -787,7 +834,7 @@ Assume point is at beginning of dynamic block."
(defun org-element-dynamic-block-interpreter (dynamic-block contents)
"Interpret DYNAMIC-BLOCK element as Org syntax.
CONTENTS is the contents of the element."
- (format "#+BEGIN: %s%s\n%s#+END:"
+ (format "#+begin: %s%s\n%s#+end:"
(org-element-property :block-name dynamic-block)
(let ((args (org-element-property :arguments dynamic-block)))
(if args (concat " " args) ""))
@@ -812,7 +859,8 @@ their value.
Return a list whose CAR is `footnote-definition' and CDR is
a plist containing `:label', `:begin' `:end', `:contents-begin',
-`:contents-end', `:post-blank' and `:post-affiliated' keywords.
+`:contents-end', `:pre-blank',`:post-blank' and
+`:post-affiliated' keywords.
Assume point is at the beginning of the footnote definition."
(save-excursion
@@ -838,12 +886,16 @@ Assume point is at the beginning of the footnote definition."
((eq ?* (char-after (match-beginning 0))) (match-beginning 0))
(t (skip-chars-forward " \r\t\n" limit)
(if (= limit (point)) limit (line-beginning-position))))))
+ (pre-blank 0)
(contents-begin
(progn (search-forward "]")
(skip-chars-forward " \r\t\n" end)
(cond ((= (point) end) nil)
((= (line-beginning-position) post-affiliated) (point))
- (t (line-beginning-position)))))
+ (t
+ (setq pre-blank
+ (count-lines (line-beginning-position) begin))
+ (line-beginning-position)))))
(contents-end
(progn (goto-char end)
(skip-chars-backward " \r\t\n")
@@ -855,6 +907,7 @@ Assume point is at the beginning of the footnote definition."
:end end
:contents-begin contents-begin
:contents-end (and contents-begin contents-end)
+ :pre-blank pre-blank
:post-blank (count-lines contents-end end)
:post-affiliated post-affiliated)
(cdr affiliated))))))
@@ -862,9 +915,18 @@ Assume point is at the beginning of the footnote definition."
(defun org-element-footnote-definition-interpreter (footnote-definition contents)
"Interpret FOOTNOTE-DEFINITION element as Org syntax.
CONTENTS is the contents of the footnote-definition."
- (concat (format "[fn:%s]" (org-element-property :label footnote-definition))
- " "
- contents))
+ (let ((pre-blank
+ (min (or (org-element-property :pre-blank footnote-definition)
+ ;; 0 is specific to paragraphs at the beginning of
+ ;; the footnote definition, so we use 1 as
+ ;; a fall-back value, which is more universal.
+ 1)
+ ;; Footnote ends after more than two consecutive empty
+ ;; lines: limit ourselves to 2 newline characters.
+ 2)))
+ (concat (format "[fn:%s]" (org-element-property :label footnote-definition))
+ (if (= pre-blank 0) (concat " " (org-trim contents))
+ (concat (make-string pre-blank ?\n) contents)))))
;;;; Headline
@@ -911,7 +973,7 @@ Return value is a plist."
Return a list whose CAR is `headline' and CDR is a plist
containing `:raw-value', `:title', `:begin', `:end',
`:pre-blank', `:contents-begin' and `:contents-end', `:level',
-`:priority', `:tags', `:todo-keyword',`:todo-type', `:scheduled',
+`:priority', `:tags', `:todo-keyword', `:todo-type', `:scheduled',
`:deadline', `:closed', `:archivedp', `:commentedp'
`:footnote-section-p', `:post-blank' and `:post-affiliated'
keywords.
@@ -931,10 +993,10 @@ Assume point is at beginning of the headline."
(level (prog1 (org-reduced-level (skip-chars-forward "*"))
(skip-chars-forward " \t")))
(todo (and org-todo-regexp
- (let (case-fold-search) (looking-at org-todo-regexp))
+ (let (case-fold-search) (looking-at (concat org-todo-regexp " ")))
(progn (goto-char (match-end 0))
(skip-chars-forward " \t")
- (match-string 0))))
+ (match-string 1))))
(todo-type
(and todo (if (member todo org-done-keywords) 'done 'todo)))
(priority (and (looking-at "\\[#.\\][ \t]*")
@@ -1172,18 +1234,18 @@ CONTENTS is the contents of inlinetask."
(concat
(make-string
(max (- (+ org-tags-column (length task) (length tags))) 1)
- ? )
+ ?\s)
tags))
(t
(concat
- (make-string (max (- org-tags-column (length task)) 1) ? )
+ (make-string (max (- org-tags-column (length task)) 1) ?\s)
tags))))
;; Prefer degenerate inlinetasks when there are no
;; contents.
(when contents
(concat "\n"
contents
- (make-string level ?*) " END")))))
+ (make-string level ?*) " end")))))
;;;; Item
@@ -1195,8 +1257,8 @@ STRUCT is the structure of the plain list.
Return a list whose CAR is `item' and CDR is a plist containing
`:bullet', `:begin', `:end', `:contents-begin', `:contents-end',
-`:checkbox', `:counter', `:tag', `:structure', `:post-blank' and
-`:post-affiliated' keywords.
+`:checkbox', `:counter', `:tag', `:structure', `:pre-blank',
+`:post-blank' and `:post-affiliated' keywords.
When optional argument RAW-SECONDARY-P is non-nil, item's tag, if
any, will not be parsed as a secondary string, but as a plain
@@ -1223,20 +1285,25 @@ Assume point is at the beginning of the item."
(string-to-number (match-string 0 c)))))))
(end (progn (goto-char (nth 6 (assq (point) struct)))
(if (bolp) (point) (line-beginning-position 2))))
+ (pre-blank 0)
(contents-begin
- (progn (goto-char
- ;; Ignore tags in un-ordered lists: they are just
- ;; a part of item's body.
- (if (and (match-beginning 4)
- (save-match-data (string-match "[.)]" bullet)))
- (match-beginning 4)
- (match-end 0)))
- (skip-chars-forward " \r\t\n" end)
- (cond ((= (point) end) nil)
- ;; If first line isn't empty, contents really
- ;; start at the text after item's meta-data.
- ((= (line-beginning-position) begin) (point))
- (t (line-beginning-position)))))
+ (progn
+ (goto-char
+ ;; Ignore tags in un-ordered lists: they are just
+ ;; a part of item's body.
+ (if (and (match-beginning 4)
+ (save-match-data (string-match "[.)]" bullet)))
+ (match-beginning 4)
+ (match-end 0)))
+ (skip-chars-forward " \r\t\n" end)
+ (cond ((= (point) end) nil)
+ ;; If first line isn't empty, contents really
+ ;; start at the text after item's meta-data.
+ ((= (line-beginning-position) begin) (point))
+ (t
+ (setq pre-blank
+ (count-lines (line-beginning-position) begin))
+ (line-beginning-position)))))
(contents-end (and contents-begin
(progn (goto-char end)
(skip-chars-backward " \r\t\n")
@@ -1251,6 +1318,7 @@ Assume point is at the beginning of the item."
:checkbox checkbox
:counter counter
:structure struct
+ :pre-blank pre-blank
:post-blank (count-lines (or contents-end begin) end)
:post-affiliated begin))))
(org-element-put-property
@@ -1266,35 +1334,43 @@ Assume point is at the beginning of the item."
(defun org-element-item-interpreter (item contents)
"Interpret ITEM element as Org syntax.
CONTENTS is the contents of the element."
- (let* ((bullet (let ((bullet (org-element-property :bullet item)))
- (org-list-bullet-string
- (cond ((not (string-match "[0-9a-zA-Z]" bullet)) "- ")
- ((eq org-plain-list-ordered-item-terminator ?\)) "1)")
- (t "1.")))))
- (checkbox (org-element-property :checkbox item))
- (counter (org-element-property :counter item))
- (tag (let ((tag (org-element-property :tag item)))
- (and tag (org-element-interpret-data tag))))
- ;; Compute indentation.
- (ind (make-string (length bullet) 32))
- (item-starts-with-par-p
- (eq (org-element-type (car (org-element-contents item)))
- 'paragraph)))
- ;; Indent contents.
+ (let ((tag (pcase (org-element-property :tag item)
+ (`nil nil)
+ (tag (format "%s :: " (org-element-interpret-data tag)))))
+ (bullet
+ (org-list-bullet-string
+ (cond
+ ((not (string-match-p "[0-9a-zA-Z]"
+ (org-element-property :bullet item))) "- ")
+ ((eq org-plain-list-ordered-item-terminator ?\)) "1)")
+ (t "1.")))))
(concat
bullet
- (and counter (format "[@%d] " counter))
- (pcase checkbox
+ (pcase (org-element-property :counter item)
+ (`nil nil)
+ (counter (format "[@%d] " counter)))
+ (pcase (org-element-property :checkbox item)
(`on "[X] ")
(`off "[ ] ")
(`trans "[-] ")
(_ nil))
- (and tag (format "%s :: " tag))
+ tag
(when contents
- (let ((contents (replace-regexp-in-string
- "\\(^\\)[ \t]*\\S-" ind contents nil nil 1)))
- (if item-starts-with-par-p (org-trim contents)
- (concat "\n" contents)))))))
+ (let* ((ind (make-string (if tag 5 (length bullet)) ?\s))
+ (pre-blank
+ (min (or (org-element-property :pre-blank item)
+ ;; 0 is specific to paragraphs at the
+ ;; beginning of the item, so we use 1 as
+ ;; a fall-back value, which is more universal.
+ 1)
+ ;; Lists ends after more than two consecutive
+ ;; empty lines: limit ourselves to 2 newline
+ ;; characters.
+ 2))
+ (contents (replace-regexp-in-string
+ "\\(^\\)[ \t]*\\S-" ind contents nil nil 1)))
+ (if (= pre-blank 0) (org-trim contents)
+ (concat (make-string pre-blank ?\n) contents)))))))
;;;; Plain List
@@ -1516,7 +1592,7 @@ Assume point is at the beginning of the block."
(defun org-element-quote-block-interpreter (_ contents)
"Interpret quote-block element as Org syntax.
CONTENTS is the contents of the element."
- (format "#+BEGIN_QUOTE\n%s#+END_QUOTE" contents))
+ (format "#+begin_quote\n%s#+end_quote" contents))
;;;; Section
@@ -1602,7 +1678,7 @@ Assume point is at the beginning of the block."
"Interpret SPECIAL-BLOCK element as Org syntax.
CONTENTS is the contents of the element."
(let ((block-type (org-element-property :type special-block)))
- (format "#+BEGIN_%s\n%s#+END_%s" block-type contents block-type)))
+ (format "#+begin_%s\n%s#+end_%s" block-type contents block-type)))
@@ -1670,7 +1746,7 @@ containing `:call', `:inside-header', `:arguments',
(defun org-element-babel-call-interpreter (babel-call _)
"Interpret BABEL-CALL element as Org syntax."
- (concat "#+CALL: "
+ (concat "#+call: "
(org-element-property :call babel-call)
(let ((h (org-element-property :inside-header babel-call)))
(and h (format "[%s]" h)))
@@ -1692,7 +1768,7 @@ Return a list whose CAR is `clock' and CDR is a plist containing
(save-excursion
(let* ((case-fold-search nil)
(begin (point))
- (value (progn (search-forward org-clock-string (line-end-position) t)
+ (value (progn (search-forward "CLOCK:" (line-end-position) t)
(skip-chars-forward " \t")
(org-element-timestamp-parser)))
(duration (and (search-forward " => " (line-end-position) t)
@@ -1717,7 +1793,7 @@ Return a list whose CAR is `clock' and CDR is a plist containing
(defun org-element-clock-interpreter (clock _)
"Interpret CLOCK element as Org syntax."
- (concat org-clock-string " "
+ (concat "CLOCK: "
(org-element-timestamp-interpreter
(org-element-property :value clock) nil)
(let ((duration (org-element-property :duration clock)))
@@ -1824,7 +1900,7 @@ Assume point is at comment block beginning."
(defun org-element-comment-block-interpreter (comment-block _)
"Interpret COMMENT-BLOCK element as Org syntax."
- (format "#+BEGIN_COMMENT\n%s#+END_COMMENT"
+ (format "#+begin_comment\n%s#+end_comment"
(org-element-normalize-string
(org-remove-indentation
(org-element-property :value comment-block)))))
@@ -1951,15 +2027,22 @@ containing `:begin', `:end', `:number-lines', `:preserve-indent',
(defun org-element-example-block-interpreter (example-block _)
"Interpret EXAMPLE-BLOCK element as Org syntax."
(let ((switches (org-element-property :switches example-block))
- (value (org-element-property :value example-block)))
- (concat "#+BEGIN_EXAMPLE" (and switches (concat " " switches)) "\n"
- (org-element-normalize-string
- (org-escape-code-in-string
- (if (or org-src-preserve-indentation
- (org-element-property :preserve-indent example-block))
- value
- (org-remove-indentation value))))
- "#+END_EXAMPLE")))
+ (value
+ (let ((val (org-element-property :value example-block)))
+ (cond
+ ((or org-src-preserve-indentation
+ (org-element-property :preserve-indent example-block))
+ val)
+ ((= 0 org-edit-src-content-indentation)
+ (org-remove-indentation val))
+ (t
+ (let ((ind (make-string org-edit-src-content-indentation ?\s)))
+ (replace-regexp-in-string "^[ \t]*\\S-"
+ (concat ind "\\&")
+ (org-remove-indentation val))))))))
+ (concat "#+begin_example" (and switches (concat " " switches)) "\n"
+ (org-element-normalize-string (org-escape-code-in-string value))
+ "#+end_example")))
;;;; Export Block
@@ -2012,7 +2095,7 @@ Assume point is at export-block beginning."
(defun org-element-export-block-interpreter (export-block _)
"Interpret EXPORT-BLOCK element as Org syntax."
- (format "#+BEGIN_EXPORT %s\n%s#+END_EXPORT"
+ (format "#+begin_export %s\n%s#+end_export"
(org-element-property :type export-block)
(org-element-property :value export-block)))
@@ -2035,26 +2118,22 @@ Assume point is at the beginning of the fixed-width area."
(save-excursion
(let* ((begin (car affiliated))
(post-affiliated (point))
- value
(end-area
(progn
(while (and (< (point) limit)
(looking-at "[ \t]*:\\( \\|$\\)"))
- ;; Accumulate text without starting colons.
- (setq value
- (concat value
- (buffer-substring-no-properties
- (match-end 0) (point-at-eol))
- "\n"))
(forward-line))
- (point)))
+ (if (bolp) (line-end-position 0) (point))))
(end (progn (skip-chars-forward " \r\t\n" limit)
(if (eobp) (point) (line-beginning-position)))))
(list 'fixed-width
(nconc
(list :begin begin
:end end
- :value value
+ :value (replace-regexp-in-string
+ "^[ \t]*: ?" ""
+ (buffer-substring-no-properties post-affiliated
+ end-area))
:post-blank (count-lines end-area end)
:post-affiliated post-affiliated)
(cdr affiliated))))))
@@ -2062,10 +2141,7 @@ Assume point is at the beginning of the fixed-width area."
(defun org-element-fixed-width-interpreter (fixed-width _)
"Interpret FIXED-WIDTH element as Org syntax."
(let ((value (org-element-property :value fixed-width)))
- (and value
- (replace-regexp-in-string
- "^" ": "
- (if (string-match "\n\\'" value) (substring value 0 -1) value)))))
+ (and value (replace-regexp-in-string "^" ": " value))))
;;;; Horizontal Rule
@@ -2139,7 +2215,7 @@ containing `:key', `:value', `:begin', `:end', `:post-blank' and
(defun org-element-keyword-interpreter (keyword _)
"Interpret KEYWORD element as Org syntax."
(format "#+%s: %s"
- (org-element-property :key keyword)
+ (downcase (org-element-property :key keyword))
(org-element-property :value keyword)))
@@ -2369,7 +2445,7 @@ containing `:closed', `:deadline', `:scheduled', `:begin',
;;;; Src Block
(defun org-element-src-block-parser (limit affiliated)
- "Parse a src block.
+ "Parse a source block.
LIMIT bounds the search. AFFILIATED is a list of which CAR is
the buffer position at the beginning of the first affiliated
@@ -2425,7 +2501,7 @@ Assume point is at the beginning of the block."
(string-match "-l +\"\\([^\"\n]+\\)\"" switches)
(match-string 1 switches)))
;; Should labels be retained in (or stripped from)
- ;; src blocks?
+ ;; source blocks?
(retain-labels
(or (not switches)
(not (string-match "-r\\>" switches))
@@ -2480,14 +2556,14 @@ Assume point is at the beginning of the block."
(org-remove-indentation val))
(t
(let ((ind (make-string org-edit-src-content-indentation ?\s)))
- (replace-regexp-in-string
- "^" ind (org-remove-indentation val))))))))
- (concat (format "#+BEGIN_SRC%s\n"
- (concat (and lang (concat " " lang))
- (and switches (concat " " switches))
- (and params (concat " " params))))
- (org-element-normalize-string (org-escape-code-in-string value))
- "#+END_SRC")))
+ (replace-regexp-in-string "^[ \t]*\\S-"
+ (concat ind "\\&")
+ (org-remove-indentation val))))))))
+ (format "#+begin_src%s\n%s#+end_src"
+ (concat (and lang (concat " " lang))
+ (and switches (concat " " switches))
+ (and params (concat " " params)))
+ (org-element-normalize-string (org-escape-code-in-string value)))))
;;;; Table
@@ -2635,7 +2711,7 @@ Assume point is at beginning of the block."
(defun org-element-verse-block-interpreter (_ contents)
"Interpret verse-block element as Org syntax.
CONTENTS is verse block contents."
- (format "#+BEGIN_VERSE\n%s#+END_VERSE" contents))
+ (format "#+begin_verse\n%s#+end_verse" contents))
@@ -2803,7 +2879,7 @@ Assume point is at the beginning of the snippet."
When at a footnote reference, return a list whose car is
`footnote-reference' and cdr a plist with `:label', `:type',
-`:begin', `:end', `:content-begin', `:contents-end' and
+`:begin', `:end', `:contents-begin', `:contents-end' and
`:post-blank' as keywords. Otherwise, return nil."
(when (looking-at org-footnote-re)
(let ((closing (with-syntax-table org-element--pair-square-table
@@ -2899,7 +2975,7 @@ When at an inline source block, return a list whose car is
`:language', `:value', `:parameters' and `:post-blank' as
keywords. Otherwise, return nil.
-Assume point is at the beginning of the inline src block."
+Assume point is at the beginning of the inline source block."
(save-excursion
(catch :no-object
(when (let ((case-fold-search nil))
@@ -3066,13 +3142,13 @@ Assume point is at the beginning of the link."
(setq contents-begin (match-beginning 1))
(setq contents-end (match-end 1)))
;; Type 2: Standard link, i.e. [[https://orgmode.org][homepage]]
- ((looking-at org-bracket-link-regexp)
+ ((looking-at org-link-bracket-re)
(setq format 'bracket)
- (setq contents-begin (match-beginning 3))
- (setq contents-end (match-end 3))
+ (setq contents-begin (match-beginning 2))
+ (setq contents-end (match-end 2))
(setq link-end (match-end 0))
- ;; RAW-LINK is the original link. Expand any
- ;; abbreviation in it.
+ ;; RAW-LINK is the original link. Decode any encoding.
+ ;; Expand any abbreviation in it.
;;
;; Also treat any newline character and associated
;; indentation as a single space character. This is not
@@ -3083,9 +3159,10 @@ Assume point is at the beginning of the link."
;; [[shell:ls *.org]], which defeats Org's focus on
;; simplicity.
(setq raw-link (org-link-expand-abbrev
- (replace-regexp-in-string
- "[ \t]*\n[ \t]*" " "
- (match-string-no-properties 1))))
+ (org-link-unescape
+ (replace-regexp-in-string
+ "[ \t]*\n[ \t]*" " "
+ (match-string-no-properties 1)))))
;; Determine TYPE of link and set PATH accordingly. According
;; to RFC 3986, remove whitespaces from URI in external links.
;; In internal ones, treat indentation as a single space.
@@ -3115,7 +3192,7 @@ Assume point is at the beginning of the link."
(setq type "fuzzy")
(setq path raw-link))))
;; Type 3: Plain link, e.g., https://orgmode.org
- ((looking-at org-plain-link-re)
+ ((looking-at org-link-plain-re)
(setq format 'plain)
(setq raw-link (match-string-no-properties 0))
(setq type (match-string-no-properties 1))
@@ -3124,7 +3201,7 @@ Assume point is at the beginning of the link."
;; Type 4: Angular link, e.g., <https://orgmode.org>. Unlike to
;; bracket links, follow RFC 3986 and remove any extra
;; whitespace in URI.
- ((looking-at org-angle-link-re)
+ ((looking-at org-link-angle-re)
(setq format 'angle)
(setq type (match-string-no-properties 1))
(setq link-end (match-end 0))
@@ -3218,15 +3295,18 @@ a plist with `:key', `:args', `:begin', `:end', `:value' and
Assume point is at the macro."
(save-excursion
- (when (looking-at "{{{\\([a-zA-Z][-a-zA-Z0-9_]*\\)\\(([ \t\n]*\\([^\000]*?\\))\\)?}}}")
+ (when (looking-at "{{{\\([a-zA-Z][-a-zA-Z0-9_]*\\)\\((\\([^\000]*?\\))\\)?}}}")
(let ((begin (point))
(key (downcase (match-string-no-properties 1)))
(value (match-string-no-properties 0))
(post-blank (progn (goto-char (match-end 0))
(skip-chars-forward " \t")))
(end (point))
- (args (let ((args (match-string-no-properties 3)))
- (and args (org-macro-extract-arguments args)))))
+ (args (pcase (match-string-no-properties 3)
+ (`nil nil)
+ (a (org-macro-extract-arguments
+ (replace-regexp-in-string
+ "[ \t\r\n]+" " " (org-trim a)))))))
(list 'macro
(list :key key
:value value
@@ -3237,7 +3317,11 @@ Assume point is at the macro."
(defun org-element-macro-interpreter (macro _)
"Interpret MACRO object as Org syntax."
- (org-element-property :value macro))
+ (format "{{{%s%s}}}"
+ (org-element-property :key macro)
+ (pcase (org-element-property :args macro)
+ (`nil "")
+ (args (format "(%s)" (apply #'org-macro-escape-arguments args))))))
;;;; Radio-target
@@ -3815,7 +3899,8 @@ element it has to parse."
((org-at-heading-p)
(org-element-inlinetask-parser limit raw-secondary-p))
;; From there, elements can have affiliated keywords.
- (t (let ((affiliated (org-element--collect-affiliated-keywords limit)))
+ (t (let ((affiliated (org-element--collect-affiliated-keywords
+ limit (memq granularity '(nil object)))))
(cond
;; Jumping over affiliated keywords put point off-limits.
;; Parse them as regular keywords.
@@ -3874,7 +3959,18 @@ element it has to parse."
((looking-at "%%(")
(org-element-diary-sexp-parser limit affiliated))
;; Table.
- ((looking-at "[ \t]*\\(|\\|\\+\\(-+\\+\\)+[ \t]*$\\)")
+ ((or (looking-at "[ \t]*|")
+ ;; There is no strict definition of a table.el
+ ;; table. Try to prevent false positive while being
+ ;; quick.
+ (let ((rule-regexp "[ \t]*\\+\\(-+\\+\\)+[ \t]*$")
+ (next (line-beginning-position 2)))
+ (and (looking-at rule-regexp)
+ (save-excursion
+ (forward-line)
+ (re-search-forward "^[ \t]*\\($\\|[^|]\\)" limit t)
+ (and (> (line-beginning-position) next)
+ (org-match-line rule-regexp))))))
(org-element-table-parser limit affiliated))
;; List.
((looking-at (org-item-re))
@@ -3890,7 +3986,7 @@ element it has to parse."
;; that element, and, in the meantime, collect information they give
;; into appropriate properties. Hence the following function.
-(defun org-element--collect-affiliated-keywords (limit)
+(defun org-element--collect-affiliated-keywords (limit parse)
"Collect affiliated keywords from point down to LIMIT.
Return a list whose CAR is the position at the first of them and
@@ -3899,13 +3995,16 @@ beginning of the first line after them.
As a special case, if element doesn't start at the beginning of
the line (e.g., a paragraph starting an item), CAR is current
-position of point and CDR is nil."
+position of point and CDR is nil.
+
+When PARSE is non-nil, values from keywords belonging to
+`org-element-parsed-keywords' are parsed as secondary strings."
(if (not (bolp)) (list (point))
(let ((case-fold-search t)
(origin (point))
;; RESTRICT is the list of objects allowed in parsed
- ;; keywords value.
- (restrict (org-element-restriction 'keyword))
+ ;; keywords value. If PARSE is nil, no object is allowed.
+ (restrict (and parse (org-element-restriction 'keyword)))
output)
(while (and (< (point) limit) (looking-at org-element--affiliated-re))
(let* ((raw-kwd (upcase (match-string 1)))
@@ -3914,35 +4013,35 @@ position of point and CDR is nil."
(kwd (or (cdr (assoc raw-kwd
org-element-keyword-translation-alist))
raw-kwd))
+ ;; PARSED? is non-nil when keyword should have its
+ ;; value parsed.
+ (parsed? (member kwd org-element-parsed-keywords))
;; Find main value for any keyword.
(value
- (save-match-data
- (org-trim
- (buffer-substring-no-properties
- (match-end 0) (line-end-position)))))
- ;; PARSEDP is non-nil when keyword should have its
- ;; value parsed.
- (parsedp (member kwd org-element-parsed-keywords))
- ;; If KWD is a dual keyword, find its secondary
- ;; value. Maybe parse it.
- (dualp (member kwd org-element-dual-keywords))
+ (let ((beg (match-end 0))
+ (end (save-excursion
+ (end-of-line)
+ (skip-chars-backward " \t")
+ (point))))
+ (if parsed?
+ (org-element--parse-objects beg end nil restrict)
+ (org-trim (buffer-substring-no-properties beg end)))))
+ ;; If KWD is a dual keyword, find its secondary value.
+ ;; Maybe parse it.
+ (dual? (member kwd org-element-dual-keywords))
(dual-value
- (and dualp
+ (and dual?
(let ((sec (match-string-no-properties 2)))
- (if (or (not sec) (not parsedp)) sec
+ (cond
+ ((and sec parsed?)
(save-match-data
(org-element--parse-objects
- (match-beginning 2) (match-end 2) nil restrict))))))
+ (match-beginning 2) (match-end 2) nil restrict)))
+ (sec sec)))))
;; Attribute a property name to KWD.
(kwd-sym (and kwd (intern (concat ":" (downcase kwd))))))
;; Now set final shape for VALUE.
- (when parsedp
- (setq value
- (org-element--parse-objects
- (match-end 0)
- (progn (end-of-line) (skip-chars-backward " \t") (point))
- nil restrict)))
- (when dualp
+ (when dual?
(setq value (and (or value dual-value) (cons value dual-value))))
(when (or (member kwd org-element-multiple-keywords)
;; Attributes can always appear on multiple lines.
@@ -4046,7 +4145,10 @@ If STRING is the empty string or nil, return nil."
(ignore-errors
(if (symbolp v) (makunbound v)
(set (make-local-variable (car v)) (cdr v)))))
- (insert string)
+ ;; Transferring local variables may put the temporary buffer
+ ;; into a read-only state. Make sure we can insert STRING.
+ (let ((inhibit-read-only t)) (insert string))
+ ;; Prevent "Buffer *temp* modified; kill anyway?".
(restore-buffer-modified-p nil)
(org-element--parse-objects
(point-min) (point-max) nil restriction parent))))))
@@ -4532,8 +4634,9 @@ to interpret. Return Org syntax as a string."
(and (eq type 'paragraph)
(memq (org-element-type parent)
'(footnote-definition item))
- (eq data
- (car (org-element-contents parent)))))))
+ (eq data (car (org-element-contents parent)))
+ (eq (org-element-property :pre-blank parent)
+ 0)))))
""))))))
(if (memq type '(org-data plain-text nil)) results
;; Build white spaces. If no `:post-blank' property
@@ -4555,7 +4658,7 @@ If there is no affiliated keyword, return the empty string."
(let (dual)
(when (member key org-element-dual-keywords)
(setq dual (cdr value) value (car value)))
- (concat "#+" key
+ (concat "#+" (downcase key)
(and dual
(format "[%s]" (org-element-interpret-data dual)))
": "
@@ -4950,7 +5053,6 @@ A and B are either integers or lists of integers, as returned by
(defsubst org-element--cache-root ()
"Return root value in cache.
This function assumes `org-element--cache' is a valid AVL tree."
- ;; FIXME: Why use internal functions of avl-tree?
(avl-tree--node-left (avl-tree--dummyroot org-element--cache)))
@@ -4979,7 +5081,6 @@ the cache."
(aref (car org-element--cache-sync-requests) 0)))
(node (org-element--cache-root))
lower upper)
- ;; FIXME: Why use internal functions of avl-tree?
(while node
(let* ((element (avl-tree--node-data node))
(begin (org-element-property :begin element)))
@@ -5055,7 +5156,7 @@ Assume ELEMENT belongs to cache and that a cache is active."
(setq org-element--cache-sync-timer
(run-with-idle-timer
(let ((idle (current-idle-time)))
- (if idle (time-add idle org-element-cache-sync-break)
+ (if idle (org-time-add idle org-element-cache-sync-break)
org-element-cache-sync-idle-time))
nil
#'org-element--cache-sync
@@ -5066,7 +5167,7 @@ Assume ELEMENT belongs to cache and that a cache is active."
TIME-LIMIT is a time value or nil."
(and time-limit
(or (input-pending-p)
- (time-less-p time-limit nil))))
+ (org-time-less-p time-limit nil))))
(defsubst org-element--cache-shift-positions (element offset &optional props)
"Shift ELEMENT properties relative to buffer positions by OFFSET.
@@ -5120,7 +5221,8 @@ updated before current modification are actually submitted."
(and next (aref next 0))
threshold
(and (not threshold)
- (time-add nil org-element-cache-sync-duration))
+ (org-time-add nil
+ org-element-cache-sync-duration))
future-change)
;; Request processed. Merge current and next offsets and
;; transfer ending position.
@@ -5460,7 +5562,7 @@ the process stopped before finding the expected result."
(defconst org-element--cache-sensitive-re
(concat
- org-outline-regexp-bol "\\|"
+ "^\\*+ " "\\|"
"\\\\end{[A-Za-z0-9*]+}[ \t]*$" "\\|"
"^[ \t]*\\(?:"
"#\\+\\(?:BEGIN[:_]\\|END\\(?:_\\|:?[ \t]*$\\)\\)" "\\|"
@@ -5869,24 +5971,24 @@ Providing it allows for quicker computation."
;; Otherwise, return NEXT.
(t (throw 'exit next)))))))))))))
-(defun org-element-lineage (blob &optional types with-self)
+(defun org-element-lineage (datum &optional types with-self)
"List all ancestors of a given element or object.
-BLOB is an object or element.
+DATUM is an object or element.
-When optional argument TYPES is a list of symbols, return the
-first element or object in the lineage whose type belongs to that
-list.
+Return ancestors from the closest to the farthest. When optional
+argument TYPES is a list of symbols, return the first element or
+object in the lineage whose type belongs to that list instead.
When optional argument WITH-SELF is non-nil, lineage includes
-BLOB itself as the first element, and TYPES, if provided, also
+DATUM itself as the first element, and TYPES, if provided, also
apply to it.
-When BLOB is obtained through `org-element-context' or
+When DATUM is obtained through `org-element-context' or
`org-element-at-point', only ancestors from its section can be
-found. There is no such limitation when BLOB belongs to a full
+found. There is no such limitation when DATUM belongs to a full
parse tree."
- (let ((up (if with-self blob (org-element-property :parent blob)))
+ (let ((up (if with-self datum (org-element-property :parent datum)))
ancestors)
(while (and up (not (memq (org-element-type up) types)))
(unless types (push up ancestors))
@@ -5914,16 +6016,16 @@ end of ELEM-A."
;; ELEM-A position in such a situation. Note that the case of
;; a footnote definition is impossible: it cannot contain two
;; paragraphs in a row because it cannot contain a blank line.
- (if (and specialp
- (or (not (eq (org-element-type elem-B) 'paragraph))
- (/= (org-element-property :begin elem-B)
- (org-element-property :contents-begin elem-B))))
- (error "Cannot swap elements"))
+ (when (and specialp
+ (or (not (eq (org-element-type elem-B) 'paragraph))
+ (/= (org-element-property :begin elem-B)
+ (org-element-property :contents-begin elem-B))))
+ (error "Cannot swap elements"))
;; In a special situation, ELEM-A will have no indentation. We'll
;; give it ELEM-B's (which will in, in turn, have no indentation).
(let* ((ind-B (when specialp
(goto-char (org-element-property :begin elem-B))
- (org-get-indentation)))
+ (current-indentation)))
(beg-A (org-element-property :begin elem-A))
(end-A (save-excursion
(goto-char (org-element-property :end elem-A))