|
@@ -46,9 +46,8 @@
|
|
|
;; `comment-block', `example-block', `export-block', `fixed-width',
|
|
|
;; `horizontal-rule', `keyword', `latex-environment', `paragraph',
|
|
|
;; `planning', `property-drawer', `quote-section', `src-block',
|
|
|
-;; `table', `table-cell', `table-row' and `verse-block'. Among them,
|
|
|
-;; `paragraph', `table-cell' and `verse-block' types can contain Org
|
|
|
-;; objects and plain text.
|
|
|
+;; `table', `table-row' and `verse-block'. Among them, `paragraph'
|
|
|
+;; and `verse-block' types can contain Org objects and plain text.
|
|
|
;;
|
|
|
;; Objects are related to document's contents. Some of them are
|
|
|
;; recursive. Associated types are of the following: `bold', `code',
|
|
@@ -295,9 +294,9 @@ Assume point is at the beginning of the footnote definition."
|
|
|
(re-search-forward
|
|
|
(concat org-outline-regexp-bol "\\|"
|
|
|
org-footnote-definition-re "\\|"
|
|
|
- "^[ \t]*$") nil t))
|
|
|
+ "^[ \t]*$") nil 'move))
|
|
|
(match-beginning 0)
|
|
|
- (point-max)))
|
|
|
+ (point)))
|
|
|
(end (progn (org-skip-whitespace)
|
|
|
(if (eobp) (point) (point-at-bol)))))
|
|
|
`(footnote-definition
|
|
@@ -709,8 +708,7 @@ the plain list being parsed.
|
|
|
|
|
|
Return a list whose CAR is `plain-list' and CDR is a plist
|
|
|
containing `:type', `:begin', `:end', `:contents-begin' and
|
|
|
-`:contents-end', `:level', `:structure' and `:post-blank'
|
|
|
-keywords.
|
|
|
+`:contents-end', `:structure' and `:post-blank' keywords.
|
|
|
|
|
|
Assume point is at the beginning of the list."
|
|
|
(save-excursion
|
|
@@ -724,17 +722,9 @@ Assume point is at the beginning of the list."
|
|
|
(contents-end
|
|
|
(goto-char (org-list-get-list-end (point) struct prevs)))
|
|
|
(end (save-excursion (org-skip-whitespace)
|
|
|
- (if (eobp) (point) (point-at-bol))))
|
|
|
- (level 0))
|
|
|
- ;; Get list level.
|
|
|
- (let ((item contents-begin))
|
|
|
- (while (setq item
|
|
|
- (org-list-get-parent
|
|
|
- (org-list-get-list-begin item struct prevs)
|
|
|
- struct parents))
|
|
|
- (incf level)))
|
|
|
+ (if (eobp) (point) (point-at-bol)))))
|
|
|
;; Blank lines below list belong to the top-level list only.
|
|
|
- (when (> level 0)
|
|
|
+ (unless (= (org-list-get-top-point struct) contents-begin)
|
|
|
(setq end (min (org-list-get-bottom-point struct)
|
|
|
(progn (org-skip-whitespace)
|
|
|
(if (eobp) (point) (point-at-bol))))))
|
|
@@ -745,7 +735,6 @@ Assume point is at the beginning of the list."
|
|
|
:end ,end
|
|
|
:contents-begin ,contents-begin
|
|
|
:contents-end ,contents-end
|
|
|
- :level ,level
|
|
|
:structure ,struct
|
|
|
:post-blank ,(count-lines contents-end end)
|
|
|
,@(cadr keywords))))))
|
|
@@ -879,8 +868,7 @@ CONTENTS is the contents of the element."
|
|
|
;; type and add that new type to `org-element-all-elements'.
|
|
|
|
|
|
;; As a special case, when the newly defined type is a block type,
|
|
|
-;; `org-element-non-recursive-block-alist' has to be modified
|
|
|
-;; accordingly.
|
|
|
+;; `org-element-block-name-alist' has to be modified accordingly.
|
|
|
|
|
|
|
|
|
;;;; Babel Call
|
|
@@ -892,7 +880,8 @@ Return a list whose CAR is `babel-call' and CDR is a plist
|
|
|
containing `:begin', `:end', `:info' and `:post-blank' as
|
|
|
keywords."
|
|
|
(save-excursion
|
|
|
- (let ((info (progn (looking-at org-babel-block-lob-one-liner-regexp)
|
|
|
+ (let ((case-fold-search t)
|
|
|
+ (info (progn (looking-at org-babel-block-lob-one-liner-regexp)
|
|
|
(org-babel-lob-get-info)))
|
|
|
(begin (point-at-bol))
|
|
|
(pos-before-blank (progn (forward-line) (point)))
|
|
@@ -2851,17 +2840,21 @@ regexp matching one object can also match the other object.")
|
|
|
table-cell underline)
|
|
|
"List of recursive object types.")
|
|
|
|
|
|
-(defconst org-element-non-recursive-block-alist
|
|
|
- '(("ASCII" . export-block)
|
|
|
- ("COMMENT" . comment-block)
|
|
|
- ("DOCBOOK" . export-block)
|
|
|
- ("EXAMPLE" . example-block)
|
|
|
- ("HTML" . export-block)
|
|
|
- ("LATEX" . export-block)
|
|
|
- ("ODT" . export-block)
|
|
|
- ("SRC" . src-block)
|
|
|
- ("VERSE" . verse-block))
|
|
|
- "Alist between non-recursive block name and their element type.")
|
|
|
+(defconst org-element-block-name-alist
|
|
|
+ '(("ASCII" . org-element-export-block-parser)
|
|
|
+ ("CENTER" . org-element-center-block-parser)
|
|
|
+ ("COMMENT" . org-element-comment-block-parser)
|
|
|
+ ("DOCBOOK" . org-element-export-block-parser)
|
|
|
+ ("EXAMPLE" . org-element-example-block-parser)
|
|
|
+ ("HTML" . org-element-export-block-parser)
|
|
|
+ ("LATEX" . org-element-export-block-parser)
|
|
|
+ ("ODT" . org-element-export-block-parser)
|
|
|
+ ("QUOTE" . org-element-quote-block-parser)
|
|
|
+ ("SRC" . org-element-src-block-parser)
|
|
|
+ ("VERSE" . org-element-verse-block-parser))
|
|
|
+ "Alist between block names and the associated parsing function.
|
|
|
+Names must be uppercase. Any block whose name has no association
|
|
|
+is parsed with `org-element-special-block-parser'.")
|
|
|
|
|
|
(defconst org-element-affiliated-keywords
|
|
|
'("ATTR_ASCII" "ATTR_DOCBOOK" "ATTR_HTML" "ATTR_LATEX" "ATTR_ODT" "CAPTION"
|
|
@@ -3006,8 +2999,7 @@ element or object type."
|
|
|
;;
|
|
|
;; `org-element-current-element' is the core function of this section.
|
|
|
;; It returns the Lisp representation of the element starting at
|
|
|
-;; point. It uses `org-element--element-block-re' for quick access to
|
|
|
-;; a common regexp.
|
|
|
+;; point.
|
|
|
;;
|
|
|
;; `org-element-current-element' makes use of special modes. They are
|
|
|
;; activated for fixed element chaining (i.e. `plain-list' > `item')
|
|
@@ -3015,14 +3007,6 @@ element or object type."
|
|
|
;; `section'). Special modes are: `section', `quote-section', `item'
|
|
|
;; and `table-row'.
|
|
|
|
|
|
-(defconst org-element--element-block-re
|
|
|
- (format "[ \t]*#\\+BEGIN_\\(%s\\)\\(?: \\|$\\)"
|
|
|
- (mapconcat
|
|
|
- 'regexp-quote
|
|
|
- (mapcar 'car org-element-non-recursive-block-alist) "\\|"))
|
|
|
- "Regexp matching the beginning of a non-recursive block type.
|
|
|
-Used internally by `org-element-current-element'.")
|
|
|
-
|
|
|
(defun org-element-current-element (&optional granularity special structure)
|
|
|
"Parse the element starting at point.
|
|
|
|
|
@@ -3044,9 +3028,8 @@ Optional argument SPECIAL, when non-nil, can be either `section',
|
|
|
If STRUCTURE isn't provided but SPECIAL is set to `item', it will
|
|
|
be computed.
|
|
|
|
|
|
-Unlike to `org-element-at-point', this function assumes point is
|
|
|
-always at the beginning of the element it has to parse. As such,
|
|
|
-it is quicker than its counterpart, albeit more restrictive."
|
|
|
+This function assumes point is always at the beginning of the
|
|
|
+element it has to parse."
|
|
|
(save-excursion
|
|
|
;; If point is at an affiliated keyword, try moving to the
|
|
|
;; beginning of the associated element. If none is found, the
|
|
@@ -3061,7 +3044,7 @@ it is quicker than its counterpart, albeit more restrictive."
|
|
|
;; `org-element-secondary-value-alist'.
|
|
|
(raw-secondary-p (and granularity (not (eq granularity 'object)))))
|
|
|
(cond
|
|
|
- ;; Item
|
|
|
+ ;; Item.
|
|
|
((eq special 'item)
|
|
|
(org-element-item-parser (or structure (org-list-struct))
|
|
|
raw-secondary-p))
|
|
@@ -3079,67 +3062,49 @@ it is quicker than its counterpart, albeit more restrictive."
|
|
|
(if (equal (match-string 1) org-clock-string)
|
|
|
(org-element-clock-parser)
|
|
|
(org-element-planning-parser)))
|
|
|
- ;; Non-recursive block.
|
|
|
- ((when (looking-at org-element--element-block-re)
|
|
|
- (let ((type (upcase (match-string 1))))
|
|
|
- (if (save-excursion
|
|
|
- (re-search-forward
|
|
|
- (format "^[ \t]*#\\+END_%s\\(?: \\|$\\)" type) nil t))
|
|
|
- (funcall
|
|
|
- (intern
|
|
|
- (format
|
|
|
- "org-element-%s-parser"
|
|
|
- (cdr (assoc type org-element-non-recursive-block-alist)))))
|
|
|
- (org-element-paragraph-parser)))))
|
|
|
+ ;; Blocks.
|
|
|
+ ((when (looking-at "[ \t]*#\\+BEGIN_\\([-A-Za-z0-9]+\\)\\(?: \\|$\\)")
|
|
|
+ (let ((name (upcase (match-string 1))) parser)
|
|
|
+ (cond
|
|
|
+ ((not (save-excursion
|
|
|
+ (re-search-forward
|
|
|
+ (format "^[ \t]*#\\+END_%s\\(?: \\|$\\)" name) nil t)))
|
|
|
+ (org-element-paragraph-parser))
|
|
|
+ ((setq parser (assoc name org-element-block-name-alist))
|
|
|
+ (funcall (cdr parser)))
|
|
|
+ (t (org-element-special-block-parser))))))
|
|
|
;; Inlinetask.
|
|
|
((org-at-heading-p) (org-element-inlinetask-parser raw-secondary-p))
|
|
|
- ;; LaTeX Environment or Paragraph if incomplete.
|
|
|
+ ;; LaTeX Environment.
|
|
|
((looking-at "[ \t]*\\\\begin{")
|
|
|
(if (save-excursion
|
|
|
(re-search-forward "[ \t]*\\\\end{[^}]*}[ \t]*" nil t))
|
|
|
(org-element-latex-environment-parser)
|
|
|
(org-element-paragraph-parser)))
|
|
|
- ;; Property Drawer.
|
|
|
- ((looking-at org-property-start-re)
|
|
|
- (if (save-excursion (re-search-forward org-property-end-re nil t))
|
|
|
- (org-element-property-drawer-parser)
|
|
|
- (org-element-paragraph-parser)))
|
|
|
- ;; Recursive Block, or Paragraph if incomplete.
|
|
|
- ((looking-at "[ \t]*#\\+BEGIN_\\([-A-Za-z0-9]+\\)\\(?: \\|$\\)")
|
|
|
- (let ((type (upcase (match-string 1))))
|
|
|
- (cond
|
|
|
- ((not (save-excursion
|
|
|
- (re-search-forward
|
|
|
- (format "^[ \t]*#\\+END_%s\\(?: \\|$\\)" type) nil t)))
|
|
|
- (org-element-paragraph-parser))
|
|
|
- ((string= type "CENTER") (org-element-center-block-parser))
|
|
|
- ((string= type "QUOTE") (org-element-quote-block-parser))
|
|
|
- (t (org-element-special-block-parser)))))
|
|
|
- ;; Drawer.
|
|
|
+ ;; Drawer and Property Drawer.
|
|
|
((looking-at org-drawer-regexp)
|
|
|
- (if (save-excursion (re-search-forward "^[ \t]*:END:[ \t]*$" nil t))
|
|
|
- (org-element-drawer-parser)
|
|
|
- (org-element-paragraph-parser)))
|
|
|
+ (let ((name (match-string 1)))
|
|
|
+ (cond
|
|
|
+ ((not (save-excursion (re-search-forward "^[ \t]*:END:[ \t]*$" nil t)))
|
|
|
+ (org-element-paragraph-parser))
|
|
|
+ ((equal "PROPERTIES" name) (org-element-property-drawer-parser))
|
|
|
+ (t (org-element-drawer-parser)))))
|
|
|
+ ;; Fixed Width
|
|
|
((looking-at "[ \t]*:\\( \\|$\\)") (org-element-fixed-width-parser))
|
|
|
- ;; Babel Call.
|
|
|
- ((looking-at org-babel-block-lob-one-liner-regexp)
|
|
|
- (org-element-babel-call-parser))
|
|
|
- ;; Dynamic Block or Paragraph if incomplete. This must be
|
|
|
- ;; checked before regular keywords since their regexp matches
|
|
|
- ;; dynamic blocks too.
|
|
|
- ((looking-at "[ \t]*#\\+BEGIN:\\(?: \\|$\\)")
|
|
|
- (if (save-excursion
|
|
|
- (re-search-forward "^[ \t]*#\\+END:\\(?: \\|$\\)" nil t))
|
|
|
- (org-element-dynamic-block-parser)
|
|
|
- (org-element-paragraph-parser)))
|
|
|
- ;; Keyword, or Paragraph if at an orphaned affiliated keyword.
|
|
|
+ ;; Babel Call, Dynamic Block and Keyword.
|
|
|
((looking-at "[ \t]*#\\+\\([a-z]+\\(:?_[a-z]+\\)*\\):")
|
|
|
(let ((key (upcase (match-string 1))))
|
|
|
- (if (or (string= key "TBLFM")
|
|
|
- (member key org-element-affiliated-keywords))
|
|
|
- (org-element-paragraph-parser)
|
|
|
- (org-element-keyword-parser))))
|
|
|
- ;; Footnote definition.
|
|
|
+ (cond
|
|
|
+ ((equal key "CALL") (org-element-babel-call-parser))
|
|
|
+ ((and (equal key "BEGIN")
|
|
|
+ (save-excursion
|
|
|
+ (re-search-forward "^[ \t]*#\\+END:\\(?: \\|$\\)" nil t)))
|
|
|
+ (org-element-dynamic-block-parser))
|
|
|
+ ((and (not (equal key "TBLFM"))
|
|
|
+ (not (member key org-element-affiliated-keywords)))
|
|
|
+ (org-element-keyword-parser))
|
|
|
+ (t (org-element-paragraph-parser)))))
|
|
|
+ ;; Footnote Definition.
|
|
|
((looking-at org-footnote-definition-re)
|
|
|
(org-element-footnote-definition-parser))
|
|
|
;; Comment.
|
|
@@ -3150,7 +3115,7 @@ it is quicker than its counterpart, albeit more restrictive."
|
|
|
(org-element-horizontal-rule-parser))
|
|
|
;; Table.
|
|
|
((org-at-table-p t) (org-element-table-parser))
|
|
|
- ;; List or Item.
|
|
|
+ ;; List.
|
|
|
((looking-at (org-item-re))
|
|
|
(org-element-plain-list-parser (or structure (org-list-struct))))
|
|
|
;; Default element: Paragraph.
|
|
@@ -3846,19 +3811,18 @@ first row.
|
|
|
|
|
|
If optional argument KEEP-TRAIL is non-nil, the function returns
|
|
|
a list of of elements leading to element at point. The list's
|
|
|
-CAR is always the element at point. Its last item will be the
|
|
|
-element's parent, unless element was either the first in its
|
|
|
-section (in which case the last item in the list is the first
|
|
|
-element of section) or an headline (in which case the list
|
|
|
-contains that headline as its single element). Elements
|
|
|
-in-between, if any, are siblings of the element at point."
|
|
|
+CAR is always the element at point. Following positions contain
|
|
|
+element's siblings, then parents, siblings of parents, until the
|
|
|
+first element of current section."
|
|
|
(org-with-wide-buffer
|
|
|
;; If at an headline, parse it. It is the sole element that
|
|
|
;; doesn't require to know about context. Be sure to disallow
|
|
|
;; secondary string parsing, though.
|
|
|
(if (org-with-limited-levels (org-at-heading-p))
|
|
|
- (if (not keep-trail) (org-element-headline-parser t)
|
|
|
- (list (org-element-headline-parser t)))
|
|
|
+ (progn
|
|
|
+ (beginning-of-line)
|
|
|
+ (if (not keep-trail) (org-element-headline-parser t)
|
|
|
+ (list (org-element-headline-parser t))))
|
|
|
;; Otherwise move at the beginning of the section containing
|
|
|
;; point.
|
|
|
(let ((origin (point)) element type special-flag trail struct prevs)
|
|
@@ -3868,72 +3832,39 @@ in-between, if any, are siblings of the element at point."
|
|
|
(forward-line)))
|
|
|
(org-skip-whitespace)
|
|
|
(beginning-of-line)
|
|
|
- ;; Starting parsing successively each element with
|
|
|
- ;; `org-element-current-element'. Skip those ending before
|
|
|
- ;; original position.
|
|
|
+ ;; Parse successively each element, skipping those ending
|
|
|
+ ;; before original position.
|
|
|
(catch 'exit
|
|
|
(while t
|
|
|
(setq element (org-element-current-element
|
|
|
'element special-flag struct)
|
|
|
type (car element))
|
|
|
- (when keep-trail (push element trail))
|
|
|
+ (push element trail)
|
|
|
(cond
|
|
|
;; 1. Skip any element ending before point or at point.
|
|
|
((let ((end (org-element-property :end element)))
|
|
|
(when (<= end origin)
|
|
|
(if (> (point-max) end) (goto-char end)
|
|
|
- (throw 'exit (or trail element))))))
|
|
|
+ (throw 'exit (if keep-trail trail element))))))
|
|
|
;; 2. An element containing point is always the element at
|
|
|
;; point.
|
|
|
((not (memq type org-element-greater-elements))
|
|
|
(throw 'exit (if keep-trail trail element)))
|
|
|
- ;; 3. At a plain list.
|
|
|
- ((eq type 'plain-list)
|
|
|
- (setq struct (org-element-property :structure element)
|
|
|
- prevs (or prevs (org-list-prevs-alist struct)))
|
|
|
- (let ((beg (org-element-property :contents-begin element)))
|
|
|
- (if (<= origin beg) (throw 'exit (or trail element))
|
|
|
- ;; Find the item at this level containing ORIGIN.
|
|
|
- (let ((items (org-list-get-all-items beg struct prevs))
|
|
|
- parent)
|
|
|
- (catch 'local
|
|
|
- (mapc
|
|
|
- (lambda (pos)
|
|
|
- (cond
|
|
|
- ;; Item ends before point: skip it.
|
|
|
- ((<= (org-list-get-item-end pos struct) origin))
|
|
|
- ;; Item contains point: store is in PARENT.
|
|
|
- ((<= pos origin) (setq parent pos))
|
|
|
- ;; We went too far: return PARENT.
|
|
|
- (t (throw 'local nil)))) items))
|
|
|
- ;; No parent: no item contained point, though the
|
|
|
- ;; plain list does. Point is in the blank lines
|
|
|
- ;; after the list: return plain list.
|
|
|
- (if (not parent) (throw 'exit (or trail element))
|
|
|
- (setq special-flag 'item)
|
|
|
- (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
|
|
|
+ ;; 3. At any other greater element type, if point is
|
|
|
;; within contents, move into it. Otherwise, return
|
|
|
;; that element.
|
|
|
(t
|
|
|
- (when (eq type 'item) (setq special-flag nil))
|
|
|
(let ((beg (org-element-property :contents-begin element))
|
|
|
(end (org-element-property :contents-end element)))
|
|
|
- (if (or (not beg) (not end) (> beg origin) (< end origin))
|
|
|
- (throw 'exit (or trail element))
|
|
|
- ;; Reset trail, since we found a parent.
|
|
|
- (when keep-trail (setq trail (list element)))
|
|
|
+ (if (or (not beg) (not end) (> beg origin) (<= end origin)
|
|
|
+ (and (= beg origin) (memq type '(plain-list table))))
|
|
|
+ (throw 'exit (if keep-trail trail element))
|
|
|
+ (case type
|
|
|
+ (plain-list
|
|
|
+ (setq special-flag 'item
|
|
|
+ struct (org-element-property :structure element)))
|
|
|
+ (table (setq special-flag 'table-row))
|
|
|
+ (otherwise (setq special-flag nil)))
|
|
|
(narrow-to-region beg end)
|
|
|
(goto-char beg)))))))))))
|
|
|
|
|
@@ -3967,84 +3898,139 @@ in-between, if any, are siblings of the element at point."
|
|
|
|
|
|
(defun org-element-swap-A-B (elem-A elem-B)
|
|
|
"Swap elements ELEM-A and ELEM-B.
|
|
|
-
|
|
|
-Leave point at the end of ELEM-A."
|
|
|
+Assume ELEM-B is after ELEM-A in the buffer. Leave point at the
|
|
|
+end of ELEM-A."
|
|
|
(goto-char (org-element-property :begin elem-A))
|
|
|
- (let* ((beg-A (org-element-property :begin elem-A))
|
|
|
- (end-A (save-excursion
|
|
|
- (goto-char (org-element-property :end elem-A))
|
|
|
- (skip-chars-backward " \r\t\n")
|
|
|
- (point-at-eol)))
|
|
|
- (beg-B (org-element-property :begin elem-B))
|
|
|
- (end-B (save-excursion
|
|
|
- (goto-char (org-element-property :end elem-B))
|
|
|
- (skip-chars-backward " \r\t\n")
|
|
|
- (point-at-eol)))
|
|
|
- (body-A (buffer-substring beg-A end-A))
|
|
|
- (body-B (delete-and-extract-region beg-B end-B)))
|
|
|
- (goto-char beg-B)
|
|
|
- (insert body-A)
|
|
|
- (goto-char beg-A)
|
|
|
- (delete-region beg-A end-A)
|
|
|
- (insert body-B)
|
|
|
- (goto-char (org-element-property :end elem-B))))
|
|
|
+ ;; There are two special cases when an element doesn't start at bol:
|
|
|
+ ;; the first paragraph in an item or in a footnote definition.
|
|
|
+ (let ((specialp (not (bolp))))
|
|
|
+ ;; Only a paragraph without any affiliated keyword can be moved at
|
|
|
+ ;; 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"))
|
|
|
+ ;; 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)))
|
|
|
+ (beg-A (org-element-property :begin elem-A))
|
|
|
+ (end-A (save-excursion
|
|
|
+ (goto-char (org-element-property :end elem-A))
|
|
|
+ (skip-chars-backward " \r\t\n")
|
|
|
+ (point-at-eol)))
|
|
|
+ (beg-B (org-element-property :begin elem-B))
|
|
|
+ (end-B (save-excursion
|
|
|
+ (goto-char (org-element-property :end elem-B))
|
|
|
+ (skip-chars-backward " \r\t\n")
|
|
|
+ (point-at-eol)))
|
|
|
+ (body-A (buffer-substring beg-A end-A))
|
|
|
+ (body-B (delete-and-extract-region beg-B end-B)))
|
|
|
+ (goto-char beg-B)
|
|
|
+ (when specialp
|
|
|
+ (setq body-B (replace-regexp-in-string "\\`[ \t]*" "" body-B))
|
|
|
+ (org-indent-to-column ind-B))
|
|
|
+ (insert body-A)
|
|
|
+ (goto-char beg-A)
|
|
|
+ (delete-region beg-A end-A)
|
|
|
+ (insert body-B)
|
|
|
+ (goto-char (org-element-property :end elem-B)))))
|
|
|
+
|
|
|
+(defun org-element-forward ()
|
|
|
+ "Move forward by one element.
|
|
|
+Move to the next element at the same level, when possible."
|
|
|
+ (interactive)
|
|
|
+ (if (org-with-limited-levels (org-at-heading-p))
|
|
|
+ (let ((origin (point)))
|
|
|
+ (org-forward-same-level 1)
|
|
|
+ (unless (org-with-limited-levels (org-at-heading-p))
|
|
|
+ (goto-char origin)
|
|
|
+ (error "Cannot move further down")))
|
|
|
+ (let* ((trail (org-element-at-point 'keep-trail))
|
|
|
+ (elem (pop trail))
|
|
|
+ (end (org-element-property :end elem))
|
|
|
+ (parent (loop for prev in trail
|
|
|
+ when (>= (org-element-property :end prev) end)
|
|
|
+ return prev)))
|
|
|
+ (cond
|
|
|
+ ((eobp) (error "Cannot move further down"))
|
|
|
+ ((and parent (= (org-element-property :contents-end parent) end))
|
|
|
+ (goto-char (org-element-property :end parent)))
|
|
|
+ (t (goto-char end))))))
|
|
|
|
|
|
(defun org-element-backward ()
|
|
|
"Move backward by one element.
|
|
|
Move to the previous element at the same level, when possible."
|
|
|
(interactive)
|
|
|
- (if (save-excursion (skip-chars-backward " \r\t\n") (bobp))
|
|
|
- (error "Cannot move further up")
|
|
|
+ (if (org-with-limited-levels (org-at-heading-p))
|
|
|
+ ;; At an headline, move to the previous one, if any, or stay
|
|
|
+ ;; here.
|
|
|
+ (let ((origin (point)))
|
|
|
+ (org-backward-same-level 1)
|
|
|
+ (unless (org-with-limited-levels (org-at-heading-p))
|
|
|
+ (goto-char origin)
|
|
|
+ (error "Cannot move further up")))
|
|
|
(let* ((trail (org-element-at-point 'keep-trail))
|
|
|
- (element (car trail))
|
|
|
- (beg (org-element-property :begin element)))
|
|
|
- ;; Move to beginning of current element if point isn't there.
|
|
|
- (if (/= (point) beg) (goto-char beg)
|
|
|
- (let ((type (org-element-type element)))
|
|
|
- (cond
|
|
|
- ;; At an headline: move to previous headline at the same
|
|
|
- ;; level, a parent, or BOB.
|
|
|
- ((eq type 'headline)
|
|
|
- (let ((dest (save-excursion (org-backward-same-level 1) (point))))
|
|
|
- (if (= (point-min) dest) (error "Cannot move further up")
|
|
|
- (goto-char dest))))
|
|
|
- ;; At an item: try to move to the previous item, if any.
|
|
|
- ((and (eq type 'item)
|
|
|
- (let* ((struct (org-element-property :structure element))
|
|
|
- (prev (org-list-get-prev-item
|
|
|
- beg struct (org-list-prevs-alist struct))))
|
|
|
- (when prev (goto-char prev)))))
|
|
|
- ;; In any other case, find the previous element in the
|
|
|
- ;; trail and move to its beginning. If no previous element
|
|
|
- ;; can be found, move to headline.
|
|
|
- (t (let ((prev (nth 1 trail)))
|
|
|
- (if prev (goto-char (org-element-property :begin prev))
|
|
|
- (org-back-to-heading))))))))))
|
|
|
+ (elem (car trail))
|
|
|
+ (prev-elem (nth 1 trail))
|
|
|
+ (beg (org-element-property :begin elem)))
|
|
|
+ (cond
|
|
|
+ ;; Move to beginning of current element if point isn't there
|
|
|
+ ;; already.
|
|
|
+ ((/= (point) beg) (goto-char beg))
|
|
|
+ ((not prev-elem) (error "Cannot move further up"))
|
|
|
+ (t (goto-char (org-element-property :begin prev-elem)))))))
|
|
|
+
|
|
|
+(defun org-element-up ()
|
|
|
+ "Move to upper element."
|
|
|
+ (interactive)
|
|
|
+ (if (org-with-limited-levels (org-at-heading-p))
|
|
|
+ (unless (org-up-heading-safe)
|
|
|
+ (error "No surrounding element"))
|
|
|
+ (let* ((trail (org-element-at-point 'keep-trail))
|
|
|
+ (elem (pop trail))
|
|
|
+ (end (org-element-property :end elem))
|
|
|
+ (parent (loop for prev in trail
|
|
|
+ when (>= (org-element-property :end prev) end)
|
|
|
+ return prev)))
|
|
|
+ (cond
|
|
|
+ (parent (goto-char (org-element-property :begin parent)))
|
|
|
+ ((org-before-first-heading-p) (error "No surrounding element"))
|
|
|
+ (t (org-back-to-heading))))))
|
|
|
+
|
|
|
+(defun org-element-down ()
|
|
|
+ "Move to inner element."
|
|
|
+ (interactive)
|
|
|
+ (let ((element (org-element-at-point)))
|
|
|
+ (cond
|
|
|
+ ((memq (org-element-type element) '(plain-list table))
|
|
|
+ (goto-char (org-element-property :contents-begin element))
|
|
|
+ (forward-char))
|
|
|
+ ((memq (org-element-type element) org-element-greater-elements)
|
|
|
+ ;; If contents are hidden, first disclose them.
|
|
|
+ (when (org-element-property :hiddenp element) (org-cycle))
|
|
|
+ (goto-char (org-element-property :contents-begin element)))
|
|
|
+ (t (error "No inner element")))))
|
|
|
|
|
|
(defun org-element-drag-backward ()
|
|
|
- "Drag backward element at point."
|
|
|
+ "Move backward element at point."
|
|
|
(interactive)
|
|
|
- (let* ((pos (point))
|
|
|
- (elem (org-element-at-point)))
|
|
|
- (when (= (progn (goto-char (point-min))
|
|
|
- (org-skip-whitespace)
|
|
|
- (point-at-bol))
|
|
|
- (org-element-property :end elem))
|
|
|
- (error "Cannot drag element backward"))
|
|
|
- (goto-char (org-element-property :begin elem))
|
|
|
- (org-element-backward)
|
|
|
- (let ((prev-elem (org-element-at-point)))
|
|
|
- (when (or (org-element-nested-p elem prev-elem)
|
|
|
- (and (eq (org-element-type elem) 'headline)
|
|
|
- (not (eq (org-element-type prev-elem) 'headline))))
|
|
|
- (goto-char pos)
|
|
|
- (error "Cannot drag element backward"))
|
|
|
- ;; Compute new position of point: it's shifted by PREV-ELEM
|
|
|
- ;; body's length.
|
|
|
- (let ((size-prev (- (org-element-property :end prev-elem)
|
|
|
- (org-element-property :begin prev-elem))))
|
|
|
- (org-element-swap-A-B prev-elem elem)
|
|
|
- (goto-char (- pos size-prev))))))
|
|
|
+ (if (org-with-limited-levels (org-at-heading-p)) (org-move-subtree-up)
|
|
|
+ (let* ((trail (org-element-at-point 'keep-trail))
|
|
|
+ (elem (car trail))
|
|
|
+ (prev-elem (nth 1 trail)))
|
|
|
+ ;; Error out if no previous element or previous element is
|
|
|
+ ;; a parent of the current one.
|
|
|
+ (if (or (not prev-elem) (org-element-nested-p elem prev-elem))
|
|
|
+ (error "Cannot drag element backward")
|
|
|
+ (let ((pos (point)))
|
|
|
+ (org-element-swap-A-B prev-elem elem)
|
|
|
+ (goto-char (+ (org-element-property :begin prev-elem)
|
|
|
+ (- pos (org-element-property :begin elem)))))))))
|
|
|
|
|
|
(defun org-element-drag-forward ()
|
|
|
"Move forward element at point."
|
|
@@ -4067,7 +4053,9 @@ Move to the previous element at the same level, when possible."
|
|
|
(goto-char (org-element-property :end next-elem))
|
|
|
(skip-chars-backward " \r\t\n")
|
|
|
(forward-line)
|
|
|
- (point))
|
|
|
+ ;; Small correction if buffer doesn't end
|
|
|
+ ;; with a newline character.
|
|
|
+ (if (and (eolp) (not (bolp))) (1+ (point)) (point)))
|
|
|
(org-element-property :begin next-elem)))
|
|
|
(size-blank (- (org-element-property :end elem)
|
|
|
(save-excursion
|
|
@@ -4078,43 +4066,6 @@ Move to the previous element at the same level, when possible."
|
|
|
(org-element-swap-A-B elem next-elem)
|
|
|
(goto-char (+ pos size-next size-blank))))))
|
|
|
|
|
|
-(defun org-element-forward ()
|
|
|
- "Move forward by one element.
|
|
|
-Move to the next element at the same level, when possible."
|
|
|
- (interactive)
|
|
|
- (if (eobp) (error "Cannot move further down")
|
|
|
- (let* ((trail (org-element-at-point 'keep-trail))
|
|
|
- (element (car trail))
|
|
|
- (type (org-element-type element))
|
|
|
- (end (org-element-property :end element)))
|
|
|
- (cond
|
|
|
- ;; At an headline, move to next headline at the same level.
|
|
|
- ((eq type 'headline) (goto-char end))
|
|
|
- ;; At an item. Move to the next item, if possible.
|
|
|
- ((and (eq type 'item)
|
|
|
- (let* ((struct (org-element-property :structure element))
|
|
|
- (prevs (org-list-prevs-alist struct))
|
|
|
- (beg (org-element-property :begin element))
|
|
|
- (next-item (org-list-get-next-item beg struct prevs)))
|
|
|
- (when next-item (goto-char next-item)))))
|
|
|
- ;; In any other case, move to element's end, unless this
|
|
|
- ;; position is also the end of its parent's contents, in which
|
|
|
- ;; case, directly jump to parent's end.
|
|
|
- (t
|
|
|
- (let ((parent
|
|
|
- ;; Determine if TRAIL contains the real parent of ELEMENT.
|
|
|
- (and (> (length trail) 1)
|
|
|
- (let* ((parent-candidate (car (last trail))))
|
|
|
- (and (memq (org-element-type parent-candidate)
|
|
|
- org-element-greater-elements)
|
|
|
- (>= (org-element-property
|
|
|
- :contents-end parent-candidate) end)
|
|
|
- parent-candidate)))))
|
|
|
- (cond ((not parent) (goto-char end))
|
|
|
- ((= (org-element-property :contents-end parent) end)
|
|
|
- (goto-char (org-element-property :end parent)))
|
|
|
- (t (goto-char end)))))))))
|
|
|
-
|
|
|
(defun org-element-mark-element ()
|
|
|
"Put point at beginning of this element, mark at end.
|
|
|
|
|
@@ -4152,102 +4103,40 @@ ones already marked."
|
|
|
(org-element-property :begin elem)
|
|
|
(org-element-property :end elem))))))
|
|
|
|
|
|
-(defun org-transpose-elements ()
|
|
|
+(defun org-element-transpose ()
|
|
|
"Transpose current and previous elements, keeping blank lines between.
|
|
|
Point is moved after both elements."
|
|
|
(interactive)
|
|
|
(org-skip-whitespace)
|
|
|
- (let ((pos (point))
|
|
|
- (cur (org-element-at-point)))
|
|
|
- (when (= (save-excursion (goto-char (point-min))
|
|
|
- (org-skip-whitespace)
|
|
|
- (point-at-bol))
|
|
|
- (org-element-property :begin cur))
|
|
|
- (error "No previous element"))
|
|
|
- (goto-char (org-element-property :begin cur))
|
|
|
- (forward-line -1)
|
|
|
- (let ((prev (org-element-at-point)))
|
|
|
- (when (org-element-nested-p cur prev)
|
|
|
- (goto-char pos)
|
|
|
- (error "Cannot transpose nested elements"))
|
|
|
- (org-element-swap-A-B prev cur))))
|
|
|
+ (let ((end (org-element-property :end (org-element-at-point))))
|
|
|
+ (org-element-drag-backward)
|
|
|
+ (goto-char end)))
|
|
|
|
|
|
(defun org-element-unindent-buffer ()
|
|
|
"Un-indent the visible part of the buffer.
|
|
|
-Relative indentation \(between items, inside blocks, etc.\) isn't
|
|
|
+Relative indentation (between items, inside blocks, etc.) isn't
|
|
|
modified."
|
|
|
(interactive)
|
|
|
(unless (eq major-mode 'org-mode)
|
|
|
(error "Cannot un-indent a buffer not in Org mode"))
|
|
|
(let* ((parse-tree (org-element-parse-buffer 'greater-element))
|
|
|
- unindent-tree ; For byte-compiler.
|
|
|
+ unindent-tree ; For byte-compiler.
|
|
|
(unindent-tree
|
|
|
(function
|
|
|
(lambda (contents)
|
|
|
- (mapc (lambda (element)
|
|
|
- (if (eq (org-element-type element) 'headline)
|
|
|
- (funcall unindent-tree
|
|
|
- (org-element-contents element))
|
|
|
- (save-excursion
|
|
|
- (save-restriction
|
|
|
- (narrow-to-region
|
|
|
- (org-element-property :begin element)
|
|
|
- (org-element-property :end element))
|
|
|
- (org-do-remove-indentation)))))
|
|
|
- (reverse contents))))))
|
|
|
+ (mapc
|
|
|
+ (lambda (element)
|
|
|
+ (if (memq (org-element-type element) '(headline section))
|
|
|
+ (funcall unindent-tree (org-element-contents element))
|
|
|
+ (save-excursion
|
|
|
+ (save-restriction
|
|
|
+ (narrow-to-region
|
|
|
+ (org-element-property :begin element)
|
|
|
+ (org-element-property :end element))
|
|
|
+ (org-do-remove-indentation)))))
|
|
|
+ (reverse contents))))))
|
|
|
(funcall unindent-tree (org-element-contents parse-tree))))
|
|
|
|
|
|
-(defun org-element-up ()
|
|
|
- "Move to upper element."
|
|
|
- (interactive)
|
|
|
- (cond
|
|
|
- ((bobp) (error "No surrounding element"))
|
|
|
- ((org-with-limited-levels (org-at-heading-p))
|
|
|
- (or (org-up-heading-safe) (error "No surronding element")))
|
|
|
- (t
|
|
|
- (let* ((trail (org-element-at-point 'keep-trail))
|
|
|
- (element (car trail))
|
|
|
- (type (org-element-type element)))
|
|
|
- (cond
|
|
|
- ;; At an item, with a parent in the list: move to that parent.
|
|
|
- ((and (eq type 'item)
|
|
|
- (let* ((beg (org-element-property :begin element))
|
|
|
- (struct (org-element-property :structure element))
|
|
|
- (parents (org-list-parents-alist struct))
|
|
|
- (parentp (org-list-get-parent beg struct parents)))
|
|
|
- (and parentp (goto-char parentp)))))
|
|
|
- ;; Determine parent in the trail.
|
|
|
- (t
|
|
|
- (let ((parent
|
|
|
- (and (> (length trail) 1)
|
|
|
- (let ((parentp (car (last trail))))
|
|
|
- (and (memq (org-element-type parentp)
|
|
|
- org-element-greater-elements)
|
|
|
- (>= (org-element-property :contents-end parentp)
|
|
|
- (org-element-property :end element))
|
|
|
- parentp)))))
|
|
|
- (cond
|
|
|
- ;; When parent is found move to its beginning.
|
|
|
- (parent (goto-char (org-element-property :begin parent)))
|
|
|
- ;; If no parent was found, move to headline above, if any
|
|
|
- ;; or return an error.
|
|
|
- ((org-before-first-heading-p) (error "No surrounding element"))
|
|
|
- (t (org-back-to-heading))))))))))
|
|
|
-
|
|
|
-(defun org-element-down ()
|
|
|
- "Move to inner element."
|
|
|
- (interactive)
|
|
|
- (let ((element (org-element-at-point)))
|
|
|
- (cond
|
|
|
- ((memq (org-element-type element) '(plain-list table))
|
|
|
- (goto-char (org-element-property :contents-begin element))
|
|
|
- (forward-char))
|
|
|
- ((memq (org-element-type element) org-element-greater-elements)
|
|
|
- ;; If contents are hidden, first disclose them.
|
|
|
- (when (org-element-property :hiddenp element) (org-cycle))
|
|
|
- (goto-char (org-element-property :contents-begin element)))
|
|
|
- (t (error "No inner element")))))
|
|
|
-
|
|
|
|
|
|
(provide 'org-element)
|
|
|
;;; org-element.el ends here
|