org-element: Split tables into table-row elements and table-cell objects
* contrib/lisp/org-element.el (org-element-table-parser): Split tables into table-row elements and table-cell objects. (org-element-table-interpreter): Adapt interpreter to new code. (org-element-table-row-parser, org-element-table-row-interpreter, org-element-table-cell-parser, org-element-table-cell-interpreter, org-element-table-cell-successor, org-element-table-row-successor, org-element-restriction): New functions. (org-element-headline-parser, org-element-inlinetask-parser, org-element-item-parser, org-element-verse-block-parser, org-element-footnote-reference-parser, org-element-collect-affiliated-keywords, org-element-parse-objects): Use new function (org-element-all-objects): Add new objects. (org-element-target-parser): Small change to docstring. (org-element-object-restrictions): Merge `org-element-string-restrictions' into it. (org-element-string-restrictions): Remove variable. (org-element-parse-elements): Parse objects in non-recursive elements with contents. (org-element-normalize-string): Small refactoring. (org-element-at-point): Handle table navigation. * testing/lisp/test-org-element.el: Add tests.
This commit is contained in:
parent
aa2e5308ee
commit
eeeee5f1da
|
@ -30,24 +30,25 @@
|
||||||
;; following types: `emphasis', `entity', `export-snippet',
|
;; following types: `emphasis', `entity', `export-snippet',
|
||||||
;; `footnote-reference', `inline-babel-call', `inline-src-block',
|
;; `footnote-reference', `inline-babel-call', `inline-src-block',
|
||||||
;; `latex-fragment', `line-break', `link', `macro', `radio-target',
|
;; `latex-fragment', `line-break', `link', `macro', `radio-target',
|
||||||
;; `statistics-cookie', `subscript', `superscript', `target',
|
;; `statistics-cookie', `subscript', `superscript', `table-cell',
|
||||||
;; `time-stamp' and `verbatim'.
|
;; `target', `time-stamp' and `verbatim'.
|
||||||
|
|
||||||
;; An element always starts and ends at the beginning of a line. The
|
;; An element always starts and ends at the beginning of a line
|
||||||
;; only element's type containing objects is called a `paragraph'.
|
;; (excepted for `table-cell'). The only element's type containing
|
||||||
;; Other types are: `comment', `comment-block', `example-block',
|
;; objects is called a `paragraph'. Other types are: `comment',
|
||||||
;; `export-block', `fixed-width', `horizontal-rule', `keyword',
|
;; `comment-block', `example-block', `export-block', `fixed-width',
|
||||||
;; `latex-environment', `babel-call', `property-drawer',
|
;; `horizontal-rule', `keyword', `latex-environment', `babel-call',
|
||||||
;; `quote-section', `src-block', `table' and `verse-block'.
|
;; `property-drawer', `quote-section', `src-block', `table',
|
||||||
|
;; `table-row' and `verse-block'.
|
||||||
|
|
||||||
;; Elements containing paragraphs are called greater elements.
|
;; Elements containing paragraphs are called greater elements.
|
||||||
;; Concerned types are: `center-block', `drawer', `dynamic-block',
|
;; Concerned types are: `center-block', `drawer', `dynamic-block',
|
||||||
;; `footnote-definition', `headline', `inlinetask', `item',
|
;; `footnote-definition', `headline', `inlinetask', `item',
|
||||||
;; `plain-list', `quote-block', `section' and `special-block'.
|
;; `plain-list', `quote-block', `section' and `special-block'
|
||||||
|
|
||||||
;; Greater elements (excepted `headline', `item' and `section' types)
|
;; Greater elements (excepted `headline', `item' and `section' types)
|
||||||
;; and elements (excepted `keyword', `babel-call', and
|
;; and elements (excepted `keyword', `babel-call', `property-drawer'
|
||||||
;; `property-drawer' types) can have a fixed set of keywords as
|
;; and `table-row' types) can have a fixed set of keywords as
|
||||||
;; attributes. Those are called "affiliated keywords", to distinguish
|
;; attributes. Those are called "affiliated keywords", to distinguish
|
||||||
;; them from others keywords, which are full-fledged elements. In
|
;; them from others keywords, which are full-fledged elements. In
|
||||||
;; particular, the "name" affiliated keyword allows to label almost
|
;; particular, the "name" affiliated keyword allows to label almost
|
||||||
|
@ -79,10 +80,10 @@
|
||||||
;; The first part of this file implements a parser and an interpreter
|
;; The first part of this file implements a parser and an interpreter
|
||||||
;; for each type of Org syntax.
|
;; for each type of Org syntax.
|
||||||
|
|
||||||
;; The next two parts introduce three accessors and a function
|
;; The next two parts introduce four accessors and a function
|
||||||
;; retrieving the smallest element starting at point (respectively
|
;; retrieving the smallest element starting at point (respectively
|
||||||
;; `org-element-type', `org-element-property', `org-element-contents'
|
;; `org-element-type', `org-element-property', `org-element-contents',
|
||||||
;; and `org-element-current-element').
|
;; `org-element-restriction' and `org-element-current-element').
|
||||||
|
|
||||||
;; The following part creates a fully recursive buffer parser. It
|
;; The following part creates a fully recursive buffer parser. It
|
||||||
;; also provides a tool to map a function to elements or objects
|
;; also provides a tool to map a function to elements or objects
|
||||||
|
@ -400,8 +401,7 @@ Assume point is at beginning of the headline."
|
||||||
(setq title
|
(setq title
|
||||||
(if raw-secondary-p raw-value
|
(if raw-secondary-p raw-value
|
||||||
(org-element-parse-secondary-string
|
(org-element-parse-secondary-string
|
||||||
raw-value
|
raw-value (org-element-restriction 'headline))))
|
||||||
(cdr (assq 'headline org-element-string-restrictions)))))
|
|
||||||
`(headline
|
`(headline
|
||||||
(:raw-value ,raw-value
|
(:raw-value ,raw-value
|
||||||
:title ,title
|
:title ,title
|
||||||
|
@ -502,7 +502,7 @@ Assume point is at beginning of the inline task."
|
||||||
(title (if raw-secondary-p (nth 4 components)
|
(title (if raw-secondary-p (nth 4 components)
|
||||||
(org-element-parse-secondary-string
|
(org-element-parse-secondary-string
|
||||||
(nth 4 components)
|
(nth 4 components)
|
||||||
(cdr (assq 'inlinetask org-element-string-restrictions)))))
|
(org-element-restriction 'inlinetask))))
|
||||||
(standard-props (let (plist)
|
(standard-props (let (plist)
|
||||||
(mapc
|
(mapc
|
||||||
(lambda (p)
|
(lambda (p)
|
||||||
|
@ -615,8 +615,7 @@ Assume point is at the beginning of the item."
|
||||||
(and raw-tag
|
(and raw-tag
|
||||||
(if raw-secondary-p raw-tag
|
(if raw-secondary-p raw-tag
|
||||||
(org-element-parse-secondary-string
|
(org-element-parse-secondary-string
|
||||||
raw-tag
|
raw-tag (org-element-restriction 'item))))))
|
||||||
(cdr (assq 'item org-element-string-restrictions)))))))
|
|
||||||
(end (org-list-get-item-end begin struct))
|
(end (org-list-get-item-end begin struct))
|
||||||
(contents-begin (progn (looking-at org-list-full-item-re)
|
(contents-begin (progn (looking-at org-list-full-item-re)
|
||||||
(goto-char (match-end 0))
|
(goto-char (match-end 0))
|
||||||
|
@ -1479,6 +1478,7 @@ CONTENTS is nil."
|
||||||
(params (org-element-property :parameters src-block))
|
(params (org-element-property :parameters src-block))
|
||||||
(value (let ((val (org-element-property :value src-block)))
|
(value (let ((val (org-element-property :value src-block)))
|
||||||
(cond
|
(cond
|
||||||
|
|
||||||
(org-src-preserve-indentation val)
|
(org-src-preserve-indentation val)
|
||||||
((zerop org-edit-src-content-indentation)
|
((zerop org-edit-src-content-indentation)
|
||||||
(org-remove-indentation val))
|
(org-remove-indentation val))
|
||||||
|
@ -1501,36 +1501,85 @@ CONTENTS is nil."
|
||||||
(defun org-element-table-parser ()
|
(defun org-element-table-parser ()
|
||||||
"Parse a table at point.
|
"Parse a table at point.
|
||||||
|
|
||||||
Return a list whose car is `table' and cdr is a plist containing
|
Return a list whose CAR is `table' and CDR is a plist containing
|
||||||
`:begin', `:end', `:contents-begin', `:contents-end', `:tblfm',
|
`:begin', `:end', `:tblfm', `:type', `:contents-begin',
|
||||||
`:type', `:raw-table' and `:post-blank' keywords."
|
`:contents-end', `:value' and `:post-blank' keywords."
|
||||||
(save-excursion
|
(save-excursion
|
||||||
(let* ((table-begin (goto-char (org-table-begin t)))
|
(let* ((case-fold-search t)
|
||||||
|
(table-begin (goto-char (org-table-begin t)))
|
||||||
(type (if (org-at-table.el-p) 'table.el 'org))
|
(type (if (org-at-table.el-p) 'table.el 'org))
|
||||||
(keywords (org-element-collect-affiliated-keywords))
|
(keywords (org-element-collect-affiliated-keywords))
|
||||||
(begin (car keywords))
|
(begin (car keywords))
|
||||||
(table-end (goto-char (marker-position (org-table-end t))))
|
(table-end (goto-char (marker-position (org-table-end t))))
|
||||||
(tblfm (when (looking-at "[ \t]*#\\+tblfm: +\\(.*\\)[ \t]*")
|
(tblfm (when (looking-at "[ \t]*#\\+TBLFM: +\\(.*\\)[ \t]*$")
|
||||||
(prog1 (org-match-string-no-properties 1)
|
(prog1 (org-match-string-no-properties 1)
|
||||||
(forward-line))))
|
(forward-line))))
|
||||||
(pos-before-blank (point))
|
(pos-before-blank (point))
|
||||||
(end (progn (org-skip-whitespace)
|
(end (progn (org-skip-whitespace)
|
||||||
(if (eobp) (point) (point-at-bol))))
|
(if (eobp) (point) (point-at-bol)))))
|
||||||
(raw-table (org-remove-indentation
|
|
||||||
(buffer-substring-no-properties table-begin table-end))))
|
|
||||||
`(table
|
`(table
|
||||||
(:begin ,begin
|
(:begin ,begin
|
||||||
:end ,end
|
:end ,end
|
||||||
:type ,type
|
:type ,type
|
||||||
:raw-table ,raw-table
|
|
||||||
:tblfm ,tblfm
|
:tblfm ,tblfm
|
||||||
|
;; Only `org' tables have contents. `table.el'
|
||||||
|
;; tables use a `:value' property to store raw
|
||||||
|
;; table as a string.
|
||||||
|
:contents-begin ,(and (eq type 'org) table-begin)
|
||||||
|
:contents-end ,(and (eq type 'org) table-end)
|
||||||
|
:value ,(and (eq type 'table.el)
|
||||||
|
(buffer-substring-no-properties
|
||||||
|
table-begin table-end))
|
||||||
:post-blank ,(count-lines pos-before-blank end)
|
:post-blank ,(count-lines pos-before-blank end)
|
||||||
,@(cadr keywords))))))
|
,@(cadr keywords))))))
|
||||||
|
|
||||||
(defun org-element-table-interpreter (table contents)
|
(defun org-element-table-interpreter (table contents)
|
||||||
"Interpret TABLE element as Org syntax.
|
"Interpret TABLE element as Org syntax.
|
||||||
CONTENTS is nil."
|
CONTENTS is nil."
|
||||||
(org-element-property :raw-table table))
|
(if (eq (org-element-property :type table) 'table.el)
|
||||||
|
(org-remove-indentation (org-element-property :value table))
|
||||||
|
(concat (with-temp-buffer (insert contents)
|
||||||
|
(org-table-align)
|
||||||
|
(buffer-string))
|
||||||
|
(when (org-element-property :tblfm table)
|
||||||
|
(format "#+TBLFM: " (org-element-property :tblfm table))))))
|
||||||
|
|
||||||
|
|
||||||
|
;;;; Table Row
|
||||||
|
|
||||||
|
(defun org-element-table-row-parser ()
|
||||||
|
"Parse table row at point.
|
||||||
|
|
||||||
|
Return a list whose CAR is `table-row' and CDR is a plist
|
||||||
|
containing `:begin', `:end', `:contents-begin', `:contents-end',
|
||||||
|
`:type' and `:post-blank' keywords."
|
||||||
|
(save-excursion
|
||||||
|
(let* ((type (if (looking-at "^[ \t]*|-") 'rule 'standard))
|
||||||
|
(begin (point))
|
||||||
|
;; A table rule has no contents. In that case, ensure
|
||||||
|
;; CONTENTS-BEGIN matches CONTENTS-END.
|
||||||
|
(contents-begin (if (eq type 'standard)
|
||||||
|
(progn (search-forward "|") (point))
|
||||||
|
(end-of-line)
|
||||||
|
(skip-chars-backward " \r\t\n")
|
||||||
|
(point)))
|
||||||
|
(contents-end (progn (end-of-line)
|
||||||
|
(skip-chars-backward " \r\t\n")
|
||||||
|
(point)))
|
||||||
|
(end (progn (forward-line) (point))))
|
||||||
|
`(table-row
|
||||||
|
(:type ,type
|
||||||
|
:begin ,begin
|
||||||
|
:end ,end
|
||||||
|
:contents-begin ,contents-begin
|
||||||
|
:contents-end ,contents-end
|
||||||
|
:post-blank 0)))))
|
||||||
|
|
||||||
|
(defun org-element-table-row-interpreter (table-row contents)
|
||||||
|
"Interpret TABLE-ROW element as Org syntax.
|
||||||
|
CONTENTS is the contents of the table row."
|
||||||
|
(if (eq (org-element-property :type table-row) 'rule) "|-"
|
||||||
|
(concat "| " contents)))
|
||||||
|
|
||||||
|
|
||||||
;;;; Verse Block
|
;;;; Verse Block
|
||||||
|
@ -1569,7 +1618,7 @@ Assume point is at beginning or end of the block."
|
||||||
(buffer-substring-no-properties value-begin value-end)
|
(buffer-substring-no-properties value-begin value-end)
|
||||||
(org-element-parse-secondary-string
|
(org-element-parse-secondary-string
|
||||||
(buffer-substring-no-properties value-begin value-end)
|
(buffer-substring-no-properties value-begin value-end)
|
||||||
(cdr (assq 'verse-block org-element-string-restrictions))))))
|
(org-element-restriction 'verse-block)))))
|
||||||
`(verse-block
|
`(verse-block
|
||||||
(:begin ,begin
|
(:begin ,begin
|
||||||
:end ,end
|
:end ,end
|
||||||
|
@ -1815,8 +1864,7 @@ and `:post-blank' as keywords."
|
||||||
(and (eq type 'inline)
|
(and (eq type 'inline)
|
||||||
(org-element-parse-secondary-string
|
(org-element-parse-secondary-string
|
||||||
(buffer-substring inner-begin inner-end)
|
(buffer-substring inner-begin inner-end)
|
||||||
(cdr (assq 'footnote-reference
|
(org-element-restriction 'footnote-reference)))))
|
||||||
org-element-string-restrictions))))))
|
|
||||||
`(footnote-reference
|
`(footnote-reference
|
||||||
(:label ,label
|
(:label ,label
|
||||||
:type ,type
|
:type ,type
|
||||||
|
@ -2113,13 +2161,13 @@ Assume point is at the beginning of the link."
|
||||||
|
|
||||||
(defun org-element-link-interpreter (link contents)
|
(defun org-element-link-interpreter (link contents)
|
||||||
"Interpret LINK object as Org syntax.
|
"Interpret LINK object as Org syntax.
|
||||||
CONTENTS is the contents of the object."
|
CONTENTS is the contents of the object, or nil."
|
||||||
(let ((type (org-element-property :type link))
|
(let ((type (org-element-property :type link))
|
||||||
(raw-link (org-element-property :raw-link link)))
|
(raw-link (org-element-property :raw-link link)))
|
||||||
(if (string= type "radio") raw-link
|
(if (string= type "radio") raw-link
|
||||||
(format "[[%s]%s]"
|
(format "[[%s]%s]"
|
||||||
raw-link
|
raw-link
|
||||||
(if (string= contents "") "" (format "[%s]" contents))))))
|
(if contents (format "[%s]" contents) "")))))
|
||||||
|
|
||||||
(defun org-element-link-successor (limit)
|
(defun org-element-link-successor (limit)
|
||||||
"Search for the next link object.
|
"Search for the next link object.
|
||||||
|
@ -2338,8 +2386,7 @@ Return a list whose car is `superscript' and cdr a plist with
|
||||||
Assume point is at the caret."
|
Assume point is at the caret."
|
||||||
(save-excursion
|
(save-excursion
|
||||||
(unless (bolp) (backward-char))
|
(unless (bolp) (backward-char))
|
||||||
(let ((bracketsp (if (looking-at org-match-substring-with-braces-regexp)
|
(let ((bracketsp (if (looking-at org-match-substring-with-braces-regexp) t
|
||||||
t
|
|
||||||
(not (looking-at org-match-substring-regexp))))
|
(not (looking-at org-match-substring-regexp))))
|
||||||
(begin (match-beginning 2))
|
(begin (match-beginning 2))
|
||||||
(contents-begin (or (match-beginning 5)
|
(contents-begin (or (match-beginning 5)
|
||||||
|
@ -2364,13 +2411,48 @@ CONTENTS is the contents of the object."
|
||||||
contents))
|
contents))
|
||||||
|
|
||||||
|
|
||||||
|
;;;; Table Cell
|
||||||
|
|
||||||
|
(defun org-element-table-cell-parser ()
|
||||||
|
"Parse table cell at point.
|
||||||
|
|
||||||
|
Return a list whose CAR is `table-cell' and CDR is a plist
|
||||||
|
containing `:begin', `:end', `:contents-begin', `:contents-end'
|
||||||
|
and `:post-blank' keywords."
|
||||||
|
(looking-at "[ \t]*\\(.*?\\)[ \t]*|")
|
||||||
|
(let* ((begin (match-beginning 0))
|
||||||
|
(end (match-end 0))
|
||||||
|
(contents-begin (match-beginning 1))
|
||||||
|
(contents-end (match-end 1)))
|
||||||
|
`(table-cell
|
||||||
|
(:begin ,begin
|
||||||
|
:end ,end
|
||||||
|
:contents-begin ,contents-begin
|
||||||
|
:contents-end ,contents-end
|
||||||
|
:post-blank 0))))
|
||||||
|
|
||||||
|
(defun org-element-table-cell-interpreter (table-cell contents)
|
||||||
|
"Interpret TABLE-CELL element as Org syntax.
|
||||||
|
CONTENTS is the contents of the cell, or nil."
|
||||||
|
(concat " " contents " |"))
|
||||||
|
|
||||||
|
(defun org-element-table-cell-successor (limit)
|
||||||
|
"Search for the next table-cell object.
|
||||||
|
|
||||||
|
LIMIT bounds the search.
|
||||||
|
|
||||||
|
Return value is a cons cell whose CAR is `table-cell' and CDR is
|
||||||
|
beginning position."
|
||||||
|
(when (looking-at "[ \t]*.*?[ \t]+|") (cons 'table-cell (point))))
|
||||||
|
|
||||||
|
|
||||||
;;;; Target
|
;;;; Target
|
||||||
|
|
||||||
(defun org-element-target-parser ()
|
(defun org-element-target-parser ()
|
||||||
"Parse target at point.
|
"Parse target at point.
|
||||||
|
|
||||||
Return a list whose CAR is `target' and CDR a plist with
|
Return a list whose CAR is `target' and CDR a plist with
|
||||||
`:begin', `:end', `value' and `:post-blank' as keywords.
|
`:begin', `:end', `:value' and `:post-blank' as keywords.
|
||||||
|
|
||||||
Assume point is at the target."
|
Assume point is at the target."
|
||||||
(save-excursion
|
(save-excursion
|
||||||
|
@ -2544,20 +2626,20 @@ CONTENTS is nil."
|
||||||
export-block fixed-width footnote-definition headline
|
export-block fixed-width footnote-definition headline
|
||||||
horizontal-rule inlinetask item keyword latex-environment
|
horizontal-rule inlinetask item keyword latex-environment
|
||||||
babel-call paragraph plain-list property-drawer quote-block
|
babel-call paragraph plain-list property-drawer quote-block
|
||||||
quote-section section special-block src-block table
|
quote-section section special-block src-block table table-row
|
||||||
verse-block)
|
verse-block)
|
||||||
"Complete list of element types.")
|
"Complete list of element types.")
|
||||||
|
|
||||||
(defconst org-element-greater-elements
|
(defconst org-element-greater-elements
|
||||||
'(center-block drawer dynamic-block footnote-definition headline inlinetask
|
'(center-block drawer dynamic-block footnote-definition headline inlinetask
|
||||||
item plain-list quote-block section special-block)
|
item plain-list quote-block section special-block table)
|
||||||
"List of recursive element types aka Greater Elements.")
|
"List of recursive element types aka Greater Elements.")
|
||||||
|
|
||||||
(defconst org-element-all-successors
|
(defconst org-element-all-successors
|
||||||
'(export-snippet footnote-reference inline-babel-call inline-src-block
|
'(export-snippet footnote-reference inline-babel-call inline-src-block
|
||||||
latex-or-entity line-break link macro radio-target
|
latex-or-entity line-break link macro radio-target
|
||||||
statistics-cookie sub/superscript target text-markup
|
statistics-cookie sub/superscript table-cell target
|
||||||
time-stamp)
|
text-markup time-stamp)
|
||||||
"Complete list of successors.")
|
"Complete list of successors.")
|
||||||
|
|
||||||
(defconst org-element-object-successor-alist
|
(defconst org-element-object-successor-alist
|
||||||
|
@ -2572,12 +2654,12 @@ regexp matching one object can also match the other object.")
|
||||||
(defconst org-element-all-objects
|
(defconst org-element-all-objects
|
||||||
'(emphasis entity export-snippet footnote-reference inline-babel-call
|
'(emphasis entity export-snippet footnote-reference inline-babel-call
|
||||||
inline-src-block line-break latex-fragment link macro radio-target
|
inline-src-block line-break latex-fragment link macro radio-target
|
||||||
statistics-cookie subscript superscript target time-stamp
|
statistics-cookie subscript superscript table-cell target
|
||||||
verbatim)
|
time-stamp verbatim)
|
||||||
"Complete list of object types.")
|
"Complete list of object types.")
|
||||||
|
|
||||||
(defconst org-element-recursive-objects
|
(defconst org-element-recursive-objects
|
||||||
'(emphasis link macro subscript superscript radio-target)
|
'(emphasis link macro subscript radio-target superscript table-cell)
|
||||||
"List of recursive object types.")
|
"List of recursive object types.")
|
||||||
|
|
||||||
(defconst org-element-non-recursive-block-alist
|
(defconst org-element-non-recursive-block-alist
|
||||||
|
@ -2638,27 +2720,9 @@ This list is checked after translations have been applied. See
|
||||||
`org-element-keyword-translation-alist'.")
|
`org-element-keyword-translation-alist'.")
|
||||||
|
|
||||||
(defconst org-element-object-restrictions
|
(defconst org-element-object-restrictions
|
||||||
'((emphasis entity export-snippet inline-babel-call inline-src-block link
|
`((emphasis entity export-snippet inline-babel-call inline-src-block link
|
||||||
radio-target sub/superscript target text-markup time-stamp)
|
radio-target sub/superscript target text-markup time-stamp)
|
||||||
(link entity export-snippet inline-babel-call inline-src-block
|
(footnote-reference entity export-snippet footnote-reference
|
||||||
latex-fragment link sub/superscript text-markup)
|
|
||||||
(macro macro)
|
|
||||||
(radio-target entity export-snippet latex-fragment sub/superscript)
|
|
||||||
(subscript entity export-snippet inline-babel-call inline-src-block
|
|
||||||
latex-fragment sub/superscript text-markup)
|
|
||||||
(superscript entity export-snippet inline-babel-call inline-src-block
|
|
||||||
latex-fragment sub/superscript text-markup))
|
|
||||||
"Alist of recursive objects restrictions.
|
|
||||||
|
|
||||||
CAR is a recursive object type and CDR is a list of successors
|
|
||||||
that will be called within an object of such type.
|
|
||||||
|
|
||||||
For example, in a `radio-target' object, one can only find
|
|
||||||
entities, export snippets, latex-fragments, subscript and
|
|
||||||
superscript.")
|
|
||||||
|
|
||||||
(defconst org-element-string-restrictions
|
|
||||||
'((footnote-reference entity export-snippet footnote-reference
|
|
||||||
inline-babel-call inline-src-block latex-fragment
|
inline-babel-call inline-src-block latex-fragment
|
||||||
line-break link macro radio-target sub/superscript
|
line-break link macro radio-target sub/superscript
|
||||||
target text-markup time-stamp)
|
target text-markup time-stamp)
|
||||||
|
@ -2670,19 +2734,34 @@ superscript.")
|
||||||
(item entity inline-babel-call latex-fragment macro radio-target
|
(item entity inline-babel-call latex-fragment macro radio-target
|
||||||
sub/superscript target text-markup)
|
sub/superscript target text-markup)
|
||||||
(keyword entity latex-fragment macro sub/superscript text-markup)
|
(keyword entity latex-fragment macro sub/superscript text-markup)
|
||||||
(table entity latex-fragment macro target text-markup)
|
(link entity export-snippet inline-babel-call inline-src-block
|
||||||
|
latex-fragment link sub/superscript text-markup)
|
||||||
|
(macro macro)
|
||||||
|
(paragraph ,@org-element-all-successors)
|
||||||
|
(radio-target entity export-snippet latex-fragment sub/superscript)
|
||||||
|
(subscript entity export-snippet inline-babel-call inline-src-block
|
||||||
|
latex-fragment sub/superscript text-markup)
|
||||||
|
(superscript entity export-snippet inline-babel-call inline-src-block
|
||||||
|
latex-fragment sub/superscript text-markup)
|
||||||
|
(table-cell entity export-snippet latex-fragment link macro radio-target
|
||||||
|
sub/superscript target text-markup time-stamp)
|
||||||
|
(table-row table-cell)
|
||||||
(verse-block entity footnote-reference inline-babel-call inline-src-block
|
(verse-block entity footnote-reference inline-babel-call inline-src-block
|
||||||
latex-fragment line-break link macro radio-target
|
latex-fragment line-break link macro radio-target
|
||||||
sub/superscript target text-markup time-stamp))
|
sub/superscript target text-markup time-stamp))
|
||||||
"Alist of secondary strings restrictions.
|
"Alist of objects restrictions.
|
||||||
|
|
||||||
When parsed, some elements have a secondary string which could
|
CAR is an element or object type containing objects and CDR is
|
||||||
contain various objects (i.e. headline's name, or table's cells).
|
a list of successors that will be called within an element or
|
||||||
For association, CAR is the element type, and CDR a list of
|
object of such type.
|
||||||
successors that will be called in that secondary string.
|
|
||||||
|
|
||||||
Note: `keyword' secondary string type only applies to keywords
|
For example, in a `radio-target' object, one can only find
|
||||||
matching `org-element-parsed-keywords'.")
|
entities, export snippets, latex-fragments, subscript and
|
||||||
|
superscript.
|
||||||
|
|
||||||
|
This alist also applies to secondary string. For example, an
|
||||||
|
`headline' type element doesn't directly contain objects, but
|
||||||
|
still has an entry since one of its properties (`:title') does.")
|
||||||
|
|
||||||
(defconst org-element-secondary-value-alist
|
(defconst org-element-secondary-value-alist
|
||||||
'((headline . :title)
|
'((headline . :title)
|
||||||
|
@ -2696,8 +2775,8 @@ matching `org-element-parsed-keywords'.")
|
||||||
|
|
||||||
;;; Accessors
|
;;; Accessors
|
||||||
;;
|
;;
|
||||||
;; Provide three accessors: `org-element-type', `org-element-property'
|
;; Provide four accessors: `org-element-type', `org-element-property'
|
||||||
;; and `org-element-contents'.
|
;; `org-element-contents' and `org-element-restriction'.
|
||||||
|
|
||||||
(defun org-element-type (element)
|
(defun org-element-type (element)
|
||||||
"Return type of element ELEMENT.
|
"Return type of element ELEMENT.
|
||||||
|
@ -2717,7 +2796,14 @@ It can also return the following special value:
|
||||||
|
|
||||||
(defun org-element-contents (element)
|
(defun org-element-contents (element)
|
||||||
"Extract contents from an ELEMENT."
|
"Extract contents from an ELEMENT."
|
||||||
(nthcdr 2 element))
|
(and (consp element) (nthcdr 2 element)))
|
||||||
|
|
||||||
|
(defun org-element-restriction (element)
|
||||||
|
"Return restriction associated to ELEMENT.
|
||||||
|
ELEMENT can be an element, an object or a symbol representing an
|
||||||
|
element or object type."
|
||||||
|
(cdr (assq (if (symbolp element) element (org-element-type element))
|
||||||
|
org-element-object-restrictions)))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -2748,15 +2834,16 @@ Possible types are defined in `org-element-all-elements'.
|
||||||
|
|
||||||
Optional argument GRANULARITY determines the depth of the
|
Optional argument GRANULARITY determines the depth of the
|
||||||
recursion. Allowed values are `headline', `greater-element',
|
recursion. Allowed values are `headline', `greater-element',
|
||||||
`element', `object' or nil. When it is bigger than `object' (or
|
`element', `object' or nil. When it is broader than `object' (or
|
||||||
nil), secondary values will not be parsed, since they only
|
nil), secondary values will not be parsed, since they only
|
||||||
contain objects.
|
contain objects.
|
||||||
|
|
||||||
Optional argument SPECIAL, when non-nil, can be either `item',
|
Optional argument SPECIAL, when non-nil, can be either `item',
|
||||||
`section' or `quote-section'. `item' allows to parse item wise
|
`section', `quote-section' or `table-row'. `item' allows to
|
||||||
instead of plain-list wise, using STRUCTURE as the current list
|
parse item wise instead of plain-list wise, using STRUCTURE as
|
||||||
structure. `section' (resp. `quote-section') will try to parse
|
the current list structure. `section' (resp. `quote-section')
|
||||||
a section (resp. a quote section) before anything else.
|
will try to parse a section (resp. a quote section) before
|
||||||
|
anything else.
|
||||||
|
|
||||||
If STRUCTURE isn't provided but SPECIAL is set to `item', it will
|
If STRUCTURE isn't provided but SPECIAL is set to `item', it will
|
||||||
be computed.
|
be computed.
|
||||||
|
@ -2765,7 +2852,6 @@ Unlike to `org-element-at-point', this function assumes point is
|
||||||
always at the beginning of the element it has to parse. As such,
|
always at the beginning of the element it has to parse. As such,
|
||||||
it is quicker than its counterpart, albeit more restrictive."
|
it is quicker than its counterpart, albeit more restrictive."
|
||||||
(save-excursion
|
(save-excursion
|
||||||
(beginning-of-line)
|
|
||||||
;; If point is at an affiliated keyword, try moving to the
|
;; If point is at an affiliated keyword, try moving to the
|
||||||
;; beginning of the associated element. If none is found, the
|
;; beginning of the associated element. If none is found, the
|
||||||
;; keyword is orphaned and will be treated as plain text.
|
;; keyword is orphaned and will be treated as plain text.
|
||||||
|
@ -2779,12 +2865,18 @@ it is quicker than its counterpart, albeit more restrictive."
|
||||||
;; `org-element-secondary-value-alist'.
|
;; `org-element-secondary-value-alist'.
|
||||||
(raw-secondary-p (and granularity (not (eq granularity 'object)))))
|
(raw-secondary-p (and granularity (not (eq granularity 'object)))))
|
||||||
(cond
|
(cond
|
||||||
|
;; Item
|
||||||
|
((eq special 'item)
|
||||||
|
(org-element-item-parser (or structure (org-list-struct))
|
||||||
|
raw-secondary-p))
|
||||||
|
;; Quote section.
|
||||||
|
((eq special 'quote-section) (org-element-quote-section-parser))
|
||||||
|
;; Table Row
|
||||||
|
((eq special 'table-row) (org-element-table-row-parser))
|
||||||
;; Headline.
|
;; Headline.
|
||||||
((org-with-limited-levels (org-at-heading-p))
|
((org-with-limited-levels (org-at-heading-p))
|
||||||
(org-element-headline-parser raw-secondary-p))
|
(org-element-headline-parser raw-secondary-p))
|
||||||
;; Quote section.
|
;; Section (must be checked after headline)
|
||||||
((eq special 'quote-section) (org-element-quote-section-parser))
|
|
||||||
;; Section.
|
|
||||||
((eq special 'section) (org-element-section-parser))
|
((eq special 'section) (org-element-section-parser))
|
||||||
;; Non-recursive block.
|
;; Non-recursive block.
|
||||||
((when (looking-at org-element--element-block-re)
|
((when (looking-at org-element--element-block-re)
|
||||||
|
@ -2806,18 +2898,18 @@ it is quicker than its counterpart, albeit more restrictive."
|
||||||
(org-element-paragraph-parser)))))
|
(org-element-paragraph-parser)))))
|
||||||
;; Inlinetask.
|
;; Inlinetask.
|
||||||
((org-at-heading-p) (org-element-inlinetask-parser raw-secondary-p))
|
((org-at-heading-p) (org-element-inlinetask-parser raw-secondary-p))
|
||||||
;; LaTeX Environment or paragraph if incomplete.
|
;; LaTeX Environment or Paragraph if incomplete.
|
||||||
((looking-at "^[ \t]*\\\\begin{")
|
((looking-at "^[ \t]*\\\\begin{")
|
||||||
(if (save-excursion
|
(if (save-excursion
|
||||||
(re-search-forward "^[ \t]*\\\\end{[^}]*}[ \t]*" nil t))
|
(re-search-forward "^[ \t]*\\\\end{[^}]*}[ \t]*" nil t))
|
||||||
(org-element-latex-environment-parser)
|
(org-element-latex-environment-parser)
|
||||||
(org-element-paragraph-parser)))
|
(org-element-paragraph-parser)))
|
||||||
;; Property drawer.
|
;; Property Drawer.
|
||||||
((looking-at org-property-start-re)
|
((looking-at org-property-start-re)
|
||||||
(if (save-excursion (re-search-forward org-property-end-re nil t))
|
(if (save-excursion (re-search-forward org-property-end-re nil t))
|
||||||
(org-element-property-drawer-parser)
|
(org-element-property-drawer-parser)
|
||||||
(org-element-paragraph-parser)))
|
(org-element-paragraph-parser)))
|
||||||
;; Recursive block, or paragraph if incomplete.
|
;; Recursive Block, or Paragraph if incomplete.
|
||||||
((looking-at "[ \t]*#\\+BEGIN_\\([-A-Za-z0-9]+\\)\\(?: \\|$\\)")
|
((looking-at "[ \t]*#\\+BEGIN_\\([-A-Za-z0-9]+\\)\\(?: \\|$\\)")
|
||||||
(let ((type (upcase (match-string 1))))
|
(let ((type (upcase (match-string 1))))
|
||||||
(cond
|
(cond
|
||||||
|
@ -2834,10 +2926,10 @@ it is quicker than its counterpart, albeit more restrictive."
|
||||||
(org-element-drawer-parser)
|
(org-element-drawer-parser)
|
||||||
(org-element-paragraph-parser)))
|
(org-element-paragraph-parser)))
|
||||||
((looking-at "[ \t]*:\\( \\|$\\)") (org-element-fixed-width-parser))
|
((looking-at "[ \t]*:\\( \\|$\\)") (org-element-fixed-width-parser))
|
||||||
;; Babel call.
|
;; Babel Call.
|
||||||
((looking-at org-babel-block-lob-one-liner-regexp)
|
((looking-at org-babel-block-lob-one-liner-regexp)
|
||||||
(org-element-babel-call-parser))
|
(org-element-babel-call-parser))
|
||||||
;; Keyword, or paragraph if at an affiliated keyword.
|
;; Keyword, or Paragraph if at an orphaned affiliated keyword.
|
||||||
((looking-at "[ \t]*#\\+\\([a-z]+\\(:?_[a-z]+\\)*\\):")
|
((looking-at "[ \t]*#\\+\\([a-z]+\\(:?_[a-z]+\\)*\\):")
|
||||||
(let ((key (upcase (match-string 1))))
|
(let ((key (upcase (match-string 1))))
|
||||||
(if (or (string= key "TBLFM")
|
(if (or (string= key "TBLFM")
|
||||||
|
@ -2847,7 +2939,7 @@ it is quicker than its counterpart, albeit more restrictive."
|
||||||
;; Footnote definition.
|
;; Footnote definition.
|
||||||
((looking-at org-footnote-definition-re)
|
((looking-at org-footnote-definition-re)
|
||||||
(org-element-footnote-definition-parser))
|
(org-element-footnote-definition-parser))
|
||||||
;; Dynamic block or paragraph if incomplete.
|
;; Dynamic Block or Paragraph if incomplete.
|
||||||
((looking-at "[ \t]*#\\+BEGIN:\\(?: \\|$\\)")
|
((looking-at "[ \t]*#\\+BEGIN:\\(?: \\|$\\)")
|
||||||
(if (save-excursion
|
(if (save-excursion
|
||||||
(re-search-forward "^[ \t]*#\\+END:\\(?: \\|$\\)" nil t))
|
(re-search-forward "^[ \t]*#\\+END:\\(?: \\|$\\)" nil t))
|
||||||
|
@ -2856,18 +2948,14 @@ it is quicker than its counterpart, albeit more restrictive."
|
||||||
;; Comment.
|
;; Comment.
|
||||||
((looking-at "\\(#\\|[ \t]*#\\+\\(?: \\|$\\)\\)")
|
((looking-at "\\(#\\|[ \t]*#\\+\\(?: \\|$\\)\\)")
|
||||||
(org-element-comment-parser))
|
(org-element-comment-parser))
|
||||||
;; Horizontal rule.
|
;; Horizontal Rule.
|
||||||
((looking-at "[ \t]*-\\{5,\\}[ \t]*$")
|
((looking-at "[ \t]*-\\{5,\\}[ \t]*$")
|
||||||
(org-element-horizontal-rule-parser))
|
(org-element-horizontal-rule-parser))
|
||||||
;; Table.
|
;; Table.
|
||||||
((org-at-table-p t) (org-element-table-parser))
|
((org-at-table-p t) (org-element-table-parser))
|
||||||
;; List or item.
|
;; List or Item.
|
||||||
((looking-at (org-item-re))
|
((looking-at (org-item-re))
|
||||||
(if (eq special 'item)
|
(org-element-plain-list-parser (or structure (org-list-struct))))
|
||||||
(org-element-item-parser
|
|
||||||
(or structure (org-list-struct))
|
|
||||||
raw-secondary-p)
|
|
||||||
(org-element-plain-list-parser (or structure (org-list-struct)))))
|
|
||||||
;; Default element: Paragraph.
|
;; Default element: Paragraph.
|
||||||
(t (org-element-paragraph-parser))))))
|
(t (org-element-paragraph-parser))))))
|
||||||
|
|
||||||
|
@ -2891,7 +2979,7 @@ it is quicker than its counterpart, albeit more restrictive."
|
||||||
|
|
||||||
;; - PARSED prepares a keyword value for export. This is useful for
|
;; - PARSED prepares a keyword value for export. This is useful for
|
||||||
;; "caption". Objects restrictions for such keywords are defined in
|
;; "caption". Objects restrictions for such keywords are defined in
|
||||||
;; `org-element-string-restrictions'.
|
;; `org-element-object-restrictions'.
|
||||||
|
|
||||||
;; - DUALS is used to take care of keywords accepting a main and an
|
;; - DUALS is used to take care of keywords accepting a main and an
|
||||||
;; optional secondary values. For example "results" has its
|
;; optional secondary values. For example "results" has its
|
||||||
|
@ -2956,7 +3044,7 @@ cdr a plist of keywords and values."
|
||||||
(duals (or duals org-element-dual-keywords))
|
(duals (or duals org-element-dual-keywords))
|
||||||
;; RESTRICT is the list of objects allowed in parsed
|
;; RESTRICT is the list of objects allowed in parsed
|
||||||
;; keywords value.
|
;; keywords value.
|
||||||
(restrict (cdr (assq 'keyword org-element-string-restrictions)))
|
(restrict (org-element-restriction 'keyword))
|
||||||
output)
|
output)
|
||||||
(unless (bobp)
|
(unless (bobp)
|
||||||
(while (and (not (bobp))
|
(while (and (not (bobp))
|
||||||
|
@ -3089,10 +3177,7 @@ Nil values returned from FUN do not appear in the results."
|
||||||
(loop for el in org-element-secondary-value-alist
|
(loop for el in org-element-secondary-value-alist
|
||||||
when
|
when
|
||||||
(loop for o in types
|
(loop for o in types
|
||||||
thereis
|
thereis (memq o (org-element-restriction (car el))))
|
||||||
(memq o (cdr
|
|
||||||
(assq (car el)
|
|
||||||
org-element-string-restrictions))))
|
|
||||||
collect (car el))))
|
collect (car el))))
|
||||||
--acc
|
--acc
|
||||||
(--walk-tree
|
(--walk-tree
|
||||||
|
@ -3130,13 +3215,13 @@ Nil values returned from FUN do not appear in the results."
|
||||||
(not (eq --category 'greater-elements)))
|
(not (eq --category 'greater-elements)))
|
||||||
(and (memq --type org-element-all-elements)
|
(and (memq --type org-element-all-elements)
|
||||||
(not (eq --category 'elements)))
|
(not (eq --category 'elements)))
|
||||||
(memq --type org-element-recursive-objects))
|
(org-element-contents --blob))
|
||||||
(funcall --walk-tree --blob))))))
|
(funcall --walk-tree --blob))))))
|
||||||
(org-element-contents --data))))))
|
(org-element-contents --data))))))
|
||||||
(catch 'first-match
|
(catch 'first-match
|
||||||
(funcall --walk-tree data)
|
(funcall --walk-tree data)
|
||||||
;; Return value in a proper order.
|
;; Return value in a proper order.
|
||||||
(reverse --acc))))
|
(nreverse --acc))))
|
||||||
|
|
||||||
;; The following functions are internal parts of the parser.
|
;; The following functions are internal parts of the parser.
|
||||||
|
|
||||||
|
@ -3159,11 +3244,11 @@ Nil values returned from FUN do not appear in the results."
|
||||||
(beg end special structure granularity visible-only acc)
|
(beg end special structure granularity visible-only acc)
|
||||||
"Parse elements between BEG and END positions.
|
"Parse elements between BEG and END positions.
|
||||||
|
|
||||||
SPECIAL prioritize some elements over the others. It can set to
|
SPECIAL prioritize some elements over the others. It can be set
|
||||||
`quote-section', `section' or `item', which will focus search,
|
to `quote-section', `section' `item' or `table-row', which will
|
||||||
respectively, on quote sections, sections and items. Moreover,
|
focus search, respectively, on quote sections, sections, items
|
||||||
when value is `item', STRUCTURE will be used as the current list
|
and table-rows. Moreover, when value is `item', STRUCTURE will
|
||||||
structure.
|
be used as the current list structure.
|
||||||
|
|
||||||
GRANULARITY determines the depth of the recursion. See
|
GRANULARITY determines the depth of the recursion. See
|
||||||
`org-element-parse-buffer' for more information.
|
`org-element-parse-buffer' for more information.
|
||||||
|
@ -3176,68 +3261,55 @@ Elements are accumulated into ACC."
|
||||||
(save-restriction
|
(save-restriction
|
||||||
(narrow-to-region beg end)
|
(narrow-to-region beg end)
|
||||||
(goto-char beg)
|
(goto-char beg)
|
||||||
;; When parsing only headlines, skip any text before first one.
|
;; When parsing only headlines, skip any text before first one.
|
||||||
(when (and (eq granularity 'headline) (not (org-at-heading-p)))
|
(when (and (eq granularity 'headline) (not (org-at-heading-p)))
|
||||||
(org-with-limited-levels (outline-next-heading)))
|
(org-with-limited-levels (outline-next-heading)))
|
||||||
;; Main loop start.
|
;; Main loop start.
|
||||||
(while (not (eobp))
|
(while (not (eobp))
|
||||||
(push
|
(push
|
||||||
;; 1. Item mode is active: point must be at an item. Parse it
|
;; Find current element's type and parse it accordingly to
|
||||||
;; directly, skipping `org-element-current-element'.
|
;; its category.
|
||||||
(if (eq special 'item)
|
|
||||||
(let ((element
|
|
||||||
(org-element-item-parser
|
|
||||||
structure
|
|
||||||
(and granularity (not (eq granularity 'object))))))
|
|
||||||
(goto-char (org-element-property :end element))
|
|
||||||
(org-element-parse-elements
|
|
||||||
(org-element-property :contents-begin element)
|
|
||||||
(org-element-property :contents-end element)
|
|
||||||
nil structure granularity visible-only (reverse element)))
|
|
||||||
;; 2. When ITEM is nil, find current element's type and parse
|
|
||||||
;; it accordingly to its category.
|
|
||||||
(let* ((element (org-element-current-element
|
(let* ((element (org-element-current-element
|
||||||
granularity special structure))
|
granularity special structure))
|
||||||
(type (org-element-type element)))
|
(type (org-element-type element))
|
||||||
|
(cbeg (org-element-property :contents-begin element)))
|
||||||
(goto-char (org-element-property :end element))
|
(goto-char (org-element-property :end element))
|
||||||
(cond
|
(cond
|
||||||
;; Case 1. ELEMENT is a paragraph. Parse objects inside,
|
;; Case 1. Simply accumulate element if VISIBLE-ONLY is
|
||||||
;; if GRANULARITY allows it.
|
;; true and element is hidden or if it has no contents
|
||||||
((and (eq type 'paragraph)
|
;; anyway.
|
||||||
(or (not granularity) (eq granularity 'object)))
|
((or (and visible-only (org-element-property :hiddenp element))
|
||||||
(org-element-parse-objects
|
(not cbeg)) element)
|
||||||
(org-element-property :contents-begin element)
|
;; Case 2. Greater element: parse it between
|
||||||
(org-element-property :contents-end element)
|
|
||||||
(reverse element) nil))
|
|
||||||
;; Case 2. ELEMENT is recursive: parse it between
|
|
||||||
;; `contents-begin' and `contents-end'. Make sure
|
;; `contents-begin' and `contents-end'. Make sure
|
||||||
;; GRANULARITY allows the recursion, or ELEMENT is an
|
;; GRANULARITY allows the recursion, or ELEMENT is an
|
||||||
;; headline, in which case going inside is mandatory, in
|
;; headline, in which case going inside is mandatory, in
|
||||||
;; order to get sub-level headings. If VISIBLE-ONLY is
|
;; order to get sub-level headings.
|
||||||
;; true and element is hidden, do not recurse into it.
|
|
||||||
((and (memq type org-element-greater-elements)
|
((and (memq type org-element-greater-elements)
|
||||||
(or (not granularity)
|
(or (memq granularity '(element object nil))
|
||||||
(memq granularity '(element object))
|
(and (eq granularity 'greater-element)
|
||||||
(and (eq granularity 'greater-element) (eq type 'section))
|
(eq type 'section))
|
||||||
(eq type 'headline))
|
(eq type 'headline)))
|
||||||
(not (and visible-only
|
|
||||||
(org-element-property :hiddenp element))))
|
|
||||||
(org-element-parse-elements
|
(org-element-parse-elements
|
||||||
(org-element-property :contents-begin element)
|
cbeg (org-element-property :contents-end element)
|
||||||
(org-element-property :contents-end element)
|
;; Possibly move to a special mode.
|
||||||
;; At a plain list, switch to item mode. At an
|
|
||||||
;; headline, switch to section mode. Any other
|
|
||||||
;; element turns off special modes.
|
|
||||||
(case type
|
(case type
|
||||||
(plain-list 'item)
|
(headline
|
||||||
(headline (if (org-element-property :quotedp element)
|
(if (org-element-property :quotedp element) 'quote-section
|
||||||
'quote-section
|
'section))
|
||||||
'section)))
|
(table 'table-row)
|
||||||
|
(plain-list 'item))
|
||||||
(org-element-property :structure element)
|
(org-element-property :structure element)
|
||||||
granularity visible-only (reverse element)))
|
granularity visible-only (nreverse element)))
|
||||||
;; Case 3. Else, just accumulate ELEMENT.
|
;; Case 3. ELEMENT has contents. Parse objects inside,
|
||||||
(t element))))
|
;; if GRANULARITY allows it.
|
||||||
acc)))
|
((and cbeg (memq granularity '(object nil)))
|
||||||
|
(org-element-parse-objects
|
||||||
|
cbeg (org-element-property :contents-end element)
|
||||||
|
(nreverse element) (org-element-restriction type)))
|
||||||
|
;; Case 4. Else, just accumulate ELEMENT.
|
||||||
|
(t element)))
|
||||||
|
acc)))
|
||||||
;; Return result.
|
;; Return result.
|
||||||
(nreverse acc)))
|
(nreverse acc)))
|
||||||
|
|
||||||
|
@ -3246,14 +3318,14 @@ Elements are accumulated into ACC."
|
||||||
|
|
||||||
Objects are accumulated in ACC.
|
Objects are accumulated in ACC.
|
||||||
|
|
||||||
RESTRICTION, when non-nil, is a list of object types which are
|
RESTRICTION is a list of object types which are allowed in the
|
||||||
allowed in the current object."
|
current object."
|
||||||
(let ((get-next-object
|
(let ((get-next-object
|
||||||
(function
|
(function
|
||||||
(lambda (cand)
|
(lambda (cand)
|
||||||
;; Return the parsing function associated to the nearest
|
;; Return the parsing function associated to the nearest
|
||||||
;; object among list of candidates CAND.
|
;; object among list of candidates CAND.
|
||||||
(let ((pos (apply #'min (mapcar #'cdr cand))))
|
(let ((pos (apply 'min (mapcar 'cdr cand))))
|
||||||
(save-excursion
|
(save-excursion
|
||||||
(goto-char pos)
|
(goto-char pos)
|
||||||
(funcall
|
(funcall
|
||||||
|
@ -3285,18 +3357,11 @@ allowed in the current object."
|
||||||
cont-beg
|
cont-beg
|
||||||
(org-element-property :contents-end next-object))
|
(org-element-property :contents-end next-object))
|
||||||
(org-element-parse-objects
|
(org-element-parse-objects
|
||||||
(point-min) (point-max) (reverse next-object)
|
(point-min) (point-max)
|
||||||
;; Restrict allowed objects. This is the
|
(nreverse next-object)
|
||||||
;; intersection of current restriction and next
|
;; Restrict allowed objects.
|
||||||
;; object's restriction.
|
(org-element-restriction next-object)))
|
||||||
(let ((new-restr
|
;; ... not recursive. Accumulate the object.
|
||||||
(cdr (assq (car next-object)
|
|
||||||
org-element-object-restrictions))))
|
|
||||||
(if (not restriction) new-restr
|
|
||||||
(delq nil (mapcar
|
|
||||||
(lambda (e) (and (memq e restriction) e))
|
|
||||||
new-restr))))))
|
|
||||||
;; ... not recursive.
|
|
||||||
next-object)
|
next-object)
|
||||||
acc)
|
acc)
|
||||||
(goto-char obj-end)))
|
(goto-char obj-end)))
|
||||||
|
@ -3312,17 +3377,14 @@ allowed in the current object."
|
||||||
(defun org-element-get-next-object-candidates (limit restriction objects)
|
(defun org-element-get-next-object-candidates (limit restriction objects)
|
||||||
"Return an alist of candidates for the next object.
|
"Return an alist of candidates for the next object.
|
||||||
|
|
||||||
LIMIT bounds the search, and RESTRICTION, when non-nil, bounds
|
LIMIT bounds the search, and RESTRICTION narrows candidates to
|
||||||
the possible object types.
|
some object types.
|
||||||
|
|
||||||
Return value is an alist whose car is position and cdr the object
|
Return value is an alist whose CAR is position and CDR the object
|
||||||
type, as a string. There is an association for the closest
|
type, as a symbol.
|
||||||
object of each type within RESTRICTION when non-nil, or for every
|
|
||||||
type otherwise.
|
|
||||||
|
|
||||||
OBJECTS is the previous candidates alist."
|
OBJECTS is the previous candidates alist."
|
||||||
(let ((restriction (or restriction org-element-all-successors))
|
(let (next-candidates types-to-search)
|
||||||
next-candidates types-to-search)
|
|
||||||
;; If no previous result, search every object type in RESTRICTION.
|
;; If no previous result, search every object type in RESTRICTION.
|
||||||
;; Otherwise, keep potential candidates (old objects located after
|
;; Otherwise, keep potential candidates (old objects located after
|
||||||
;; point) and ask to search again those which had matched before.
|
;; point) and ask to search again those which had matched before.
|
||||||
|
@ -3331,8 +3393,8 @@ OBJECTS is the previous candidates alist."
|
||||||
(if (< (cdr obj) (point)) (push (car obj) types-to-search)
|
(if (< (cdr obj) (point)) (push (car obj) types-to-search)
|
||||||
(push obj next-candidates)))
|
(push obj next-candidates)))
|
||||||
objects))
|
objects))
|
||||||
;; Call the appropriate "get-next" function for each type to
|
;; Call the appropriate successor function for each type to search
|
||||||
;; search and accumulate matches.
|
;; and accumulate matches.
|
||||||
(mapc
|
(mapc
|
||||||
(lambda (type)
|
(lambda (type)
|
||||||
(let* ((successor-fun
|
(let* ((successor-fun
|
||||||
|
@ -3388,30 +3450,25 @@ Return Org syntax as a string."
|
||||||
(intern (format "org-element-%s-interpreter" type))))
|
(intern (format "org-element-%s-interpreter" type))))
|
||||||
(contents
|
(contents
|
||||||
(cond
|
(cond
|
||||||
|
;; Elements or objects without contents.
|
||||||
|
((not (org-element-contents blob)) nil)
|
||||||
;; Full Org document.
|
;; Full Org document.
|
||||||
((eq type 'org-data)
|
((eq type 'org-data)
|
||||||
(org-element-interpret-data blob genealogy previous))
|
(org-element-interpret-data blob genealogy previous))
|
||||||
;; Recursive objects.
|
;; Greater elements.
|
||||||
((memq type org-element-recursive-objects)
|
|
||||||
(org-element-interpret-data
|
|
||||||
blob (cons type genealogy) nil))
|
|
||||||
;; Recursive elements.
|
|
||||||
((memq type org-element-greater-elements)
|
((memq type org-element-greater-elements)
|
||||||
(org-element-normalize-string
|
(org-element-interpret-data blob (cons type genealogy) nil))
|
||||||
(org-element-interpret-data
|
(t
|
||||||
blob (cons type genealogy) nil)))
|
(org-element-interpret-data
|
||||||
;; Paragraphs.
|
(org-element-normalize-contents
|
||||||
((eq type 'paragraph)
|
blob
|
||||||
(let ((paragraph
|
;; When normalizing first paragraph of an item or
|
||||||
(org-element-normalize-contents
|
;; a footnote-definition, ignore first line's
|
||||||
blob
|
;; indentation.
|
||||||
;; When normalizing contents of an item,
|
(and (eq type 'paragraph)
|
||||||
;; ignore first line's indentation.
|
(not previous)
|
||||||
(and (not previous)
|
(memq (car genealogy) '(footnote-definiton item))))
|
||||||
(memq (car genealogy)
|
(cons type genealogy) nil))))
|
||||||
'(footnote-definiton item))))))
|
|
||||||
(org-element-interpret-data
|
|
||||||
paragraph (cons type genealogy) nil)))))
|
|
||||||
(results (funcall interpreter blob contents)))
|
(results (funcall interpreter blob contents)))
|
||||||
;; Update PREVIOUS.
|
;; Update PREVIOUS.
|
||||||
(setq previous type)
|
(setq previous type)
|
||||||
|
@ -3499,7 +3556,7 @@ newline character at its end."
|
||||||
((not (stringp s)) s)
|
((not (stringp s)) s)
|
||||||
((string= "" s) "")
|
((string= "" s) "")
|
||||||
(t (and (string-match "\\(\n[ \t]*\\)*\\'" s)
|
(t (and (string-match "\\(\n[ \t]*\\)*\\'" s)
|
||||||
(replace-match "\n" nil nil s)))))
|
(replace-match "\n" nil nil s)))))
|
||||||
|
|
||||||
(defun org-element-normalize-contents (element &optional ignore-first)
|
(defun org-element-normalize-contents (element &optional ignore-first)
|
||||||
"Normalize plain text in ELEMENT's contents.
|
"Normalize plain text in ELEMENT's contents.
|
||||||
|
@ -3595,8 +3652,10 @@ element. Possible types are defined in
|
||||||
`org-element-all-elements'.
|
`org-element-all-elements'.
|
||||||
|
|
||||||
As a special case, if point is at the very beginning of a list or
|
As a special case, if point is at the very beginning of a list or
|
||||||
sub-list, element returned will be that list instead of the first
|
sub-list, returned element will be that list instead of the first
|
||||||
item.
|
item. In the same way, if point is at the beginning of the first
|
||||||
|
row of a table, returned element will be the table instead of the
|
||||||
|
first row.
|
||||||
|
|
||||||
If optional argument KEEP-TRAIL is non-nil, the function returns
|
If optional argument KEEP-TRAIL is non-nil, the function returns
|
||||||
a list of of elements leading to element at point. The list's
|
a list of of elements leading to element at point. The list's
|
||||||
|
@ -3615,7 +3674,7 @@ in-between, if any, are siblings of the element at point."
|
||||||
(list (org-element-headline-parser t)))
|
(list (org-element-headline-parser t)))
|
||||||
;; Otherwise move at the beginning of the section containing
|
;; Otherwise move at the beginning of the section containing
|
||||||
;; point.
|
;; point.
|
||||||
(let ((origin (point)) element type item-flag trail struct prevs)
|
(let ((origin (point)) element type special-flag trail struct prevs)
|
||||||
(org-with-limited-levels
|
(org-with-limited-levels
|
||||||
(if (org-before-first-heading-p) (goto-char (point-min))
|
(if (org-before-first-heading-p) (goto-char (point-min))
|
||||||
(org-back-to-heading)
|
(org-back-to-heading)
|
||||||
|
@ -3627,7 +3686,8 @@ in-between, if any, are siblings of the element at point."
|
||||||
;; original position.
|
;; original position.
|
||||||
(catch 'exit
|
(catch 'exit
|
||||||
(while t
|
(while t
|
||||||
(setq element (org-element-current-element 'element item-flag struct)
|
(setq element (org-element-current-element
|
||||||
|
'element special-flag struct)
|
||||||
type (car element))
|
type (car element))
|
||||||
(when keep-trail (push element trail))
|
(when keep-trail (push element trail))
|
||||||
(cond
|
(cond
|
||||||
|
@ -3645,34 +3705,45 @@ in-between, if any, are siblings of the element at point."
|
||||||
(setq struct (org-element-property :structure element)
|
(setq struct (org-element-property :structure element)
|
||||||
prevs (or prevs (org-list-prevs-alist struct)))
|
prevs (or prevs (org-list-prevs-alist struct)))
|
||||||
(let ((beg (org-element-property :contents-begin element)))
|
(let ((beg (org-element-property :contents-begin element)))
|
||||||
(if (= beg origin) (throw 'exit (or trail element))
|
(if (<= origin beg) (throw 'exit (or trail element))
|
||||||
;; Find the item at this level containing ORIGIN.
|
;; Find the item at this level containing ORIGIN.
|
||||||
(let ((items (org-list-get-all-items beg struct prevs)))
|
(let ((items (org-list-get-all-items beg struct prevs))
|
||||||
(let (parent)
|
parent)
|
||||||
(catch 'local
|
(catch 'local
|
||||||
(mapc
|
(mapc
|
||||||
(lambda (pos)
|
(lambda (pos)
|
||||||
(cond
|
(cond
|
||||||
;; Item ends before point: skip it.
|
;; Item ends before point: skip it.
|
||||||
((<= (org-list-get-item-end pos struct) origin))
|
((<= (org-list-get-item-end pos struct) origin))
|
||||||
;; Item contains point: store is in PARENT.
|
;; Item contains point: store is in PARENT.
|
||||||
((<= pos origin) (setq parent pos))
|
((<= pos origin) (setq parent pos))
|
||||||
;; We went too far: return PARENT.
|
;; We went too far: return PARENT.
|
||||||
(t (throw 'local nil)))) items))
|
(t (throw 'local nil)))) items))
|
||||||
;; No parent: no item contained point, though
|
;; No parent: no item contained point, though the
|
||||||
;; the plain list does. Point is in the blank
|
;; plain list does. Point is in the blank lines
|
||||||
;; lines after the list: return plain list.
|
;; after the list: return plain list.
|
||||||
(if (not parent) (throw 'exit (or trail element))
|
(if (not parent) (throw 'exit (or trail element))
|
||||||
(setq item-flag 'item)
|
(setq special-flag 'item)
|
||||||
(goto-char parent)))))))
|
(goto-char parent))))))
|
||||||
|
;; 4. At a table.
|
||||||
|
((eq type 'table)
|
||||||
|
(if (eq (org-element-property :type element) 'table.el)
|
||||||
|
(throw 'exit (or trail element))
|
||||||
|
(let ((beg (org-element-property :contents-begin element))
|
||||||
|
(end (org-element-property :contents-end element)))
|
||||||
|
(if (or (<= origin beg) (>= origin end))
|
||||||
|
(throw 'exit (or trail element))
|
||||||
|
(when keep-trail (setq trail (list element)))
|
||||||
|
(setq special-flag 'table-row)
|
||||||
|
(narrow-to-region beg end)))))
|
||||||
;; 4. At any other greater element type, if point is
|
;; 4. At any other greater element type, if point is
|
||||||
;; within contents, move into it. Otherwise, return
|
;; within contents, move into it. Otherwise, return
|
||||||
;; that element.
|
;; that element.
|
||||||
(t
|
(t
|
||||||
(when (eq type 'item) (setq item-flag nil))
|
(when (eq type 'item) (setq special-flag nil))
|
||||||
(let ((beg (org-element-property :contents-begin element))
|
(let ((beg (org-element-property :contents-begin element))
|
||||||
(end (org-element-property :contents-end element)))
|
(end (org-element-property :contents-end element)))
|
||||||
(if (or (> beg origin) (< end origin))
|
(if (or (not beg) (not end) (> beg origin) (< end origin))
|
||||||
(throw 'exit (or trail element))
|
(throw 'exit (or trail element))
|
||||||
;; Reset trail, since we found a parent.
|
;; Reset trail, since we found a parent.
|
||||||
(when keep-trail (setq trail (list element)))
|
(when keep-trail (setq trail (list element)))
|
||||||
|
@ -3981,7 +4052,8 @@ modified."
|
||||||
(interactive)
|
(interactive)
|
||||||
(let ((element (org-element-at-point)))
|
(let ((element (org-element-at-point)))
|
||||||
(cond
|
(cond
|
||||||
((eq (org-element-type element) 'plain-list)
|
((memq (org-element-type element) '(plain-list table))
|
||||||
|
(goto-char (org-element-property :contents-begin element))
|
||||||
(forward-char))
|
(forward-char))
|
||||||
((memq (org-element-type element) org-element-greater-elements)
|
((memq (org-element-type element) org-element-greater-elements)
|
||||||
;; If contents are hidden, first disclose them.
|
;; If contents are hidden, first disclose them.
|
||||||
|
|
|
@ -599,7 +599,14 @@ Outside."
|
||||||
(goto-line 2)
|
(goto-line 2)
|
||||||
(org-element-down)
|
(org-element-down)
|
||||||
(should (looking-at " - Item 1.1")))
|
(should (looking-at " - Item 1.1")))
|
||||||
;; 3. Otherwise, move inside the greater element.
|
(org-test-with-temp-text "#+NAME: list\n- Item 1"
|
||||||
|
(org-element-down)
|
||||||
|
(should (looking-at " Item 1")))
|
||||||
|
;; 3. When at a table, move to first row
|
||||||
|
(org-test-with-temp-text "#+NAME: table\n| a | b |"
|
||||||
|
(org-element-down)
|
||||||
|
(should (looking-at " a | b |")))
|
||||||
|
;; 4. Otherwise, move inside the greater element.
|
||||||
(org-test-with-temp-text "#+BEGIN_CENTER\nParagraph.\n#+END_CENTER"
|
(org-test-with-temp-text "#+BEGIN_CENTER\nParagraph.\n#+END_CENTER"
|
||||||
(org-element-down)
|
(org-element-down)
|
||||||
(should (looking-at "Paragraph"))))
|
(should (looking-at "Paragraph"))))
|
||||||
|
|
Loading…
Reference in New Issue