org-element: Change return value for element at point in some corner cases

* lisp/org-element.el (org-element-at-point): When point is before any
  element, in the first blank lines of the buffer, return nil.  When
  point is within blank lines just after a headline, return that
  headline.
(org-element-context): Return nil when point is within the blank at
the beginning of the buffer.
* testing/lisp/test-org-element.el: Add tests.
This commit is contained in:
Nicolas Goaziou 2013-01-19 15:29:39 +01:00
parent c300a50402
commit 13e49a6385
2 changed files with 146 additions and 117 deletions

View File

@ -4529,7 +4529,8 @@ As a special case, if point is at the very beginning of a list or
sub-list, returned element will be that list instead of the first sub-list, returned element will be that list instead of the first
item. In the same way, if point is at the beginning of the first 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 row of a table, returned element will be the table instead of the
first row. first row. Also, if point is within the first blank lines of
a buffer, return nil.
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
@ -4545,25 +4546,36 @@ first element of current section."
(beginning-of-line) (beginning-of-line)
(if (not keep-trail) (org-element-headline-parser (point-max) t) (if (not keep-trail) (org-element-headline-parser (point-max) t)
(list (org-element-headline-parser (point-max) t)))) (list (org-element-headline-parser (point-max) t))))
;; Otherwise move at the beginning of the section containing ;; Otherwise try to move at the beginning of the section
;; point. ;; containing point.
(let ((origin (point)) (let ((origin (point))
(end (save-excursion (end (save-excursion
(org-with-limited-levels (outline-next-heading)) (point))) (org-with-limited-levels (outline-next-heading)) (point)))
element type special-flag trail struct prevs parent) element type special-flag trail struct prevs parent)
(org-with-limited-levels (org-with-limited-levels
(if (org-with-limited-levels (org-before-first-heading-p)) (if (org-before-first-heading-p) (goto-char (point-min))
(goto-char (point-min))
(org-back-to-heading) (org-back-to-heading)
(forward-line))) (forward-line)))
(org-skip-whitespace) (skip-chars-forward " \r\t\n" origin)
(beginning-of-line) (beginning-of-line)
(if (looking-at "[ \t]*$")
;; If point is still at a blank line, we didn't reach
;; section beginning. it means we started either at the
;; beginning of the buffer, before any element, or in the
;; blank area after an headline. In the first case, return
;; a dummy `org-data' element. In the second case, return
;; the headline.
(progn (skip-chars-backward " \r\t\n")
(cond ((bobp) nil)
(keep-trail
(list (org-element-headline-parser (point-max) t)))
(t (org-element-headline-parser (point-max) t))))
;; Parse successively each element, skipping those ending ;; Parse successively each element, skipping those ending
;; before original position. ;; before original position.
(catch 'exit (catch 'exit
(while t (while t
(setq element (setq element (org-element--current-element
(org-element--current-element end 'element special-flag struct) end 'element special-flag struct)
type (car element)) type (car element))
(org-element-put-property element :parent parent) (org-element-put-property element :parent parent)
(when keep-trail (push element trail)) (when keep-trail (push element trail))
@ -4611,7 +4623,7 @@ first element of current section."
(table (setq special-flag 'table-row struct nil)) (table (setq special-flag 'table-row struct nil))
(otherwise (setq special-flag nil struct nil))) (otherwise (setq special-flag nil struct nil)))
(setq end cend) (setq end cend)
(goto-char cbeg))))))))))) (goto-char cbeg))))))))))))
;;;###autoload ;;;###autoload
(defun org-element-context (&optional element) (defun org-element-context (&optional element)
@ -4619,12 +4631,13 @@ first element of current section."
Return value is a list like (TYPE PROPS) where TYPE is the type Return value is a list like (TYPE PROPS) where TYPE is the type
of the element or object and PROPS a plist of properties of the element or object and PROPS a plist of properties
associated to it. associated to it, or nil if point is within the first blank lines
of the buffer.
Possible types are defined in `org-element-all-elements' and Possible types are defined in `org-element-all-elements' and
`org-element-all-objects'. Properties depend on element or `org-element-all-objects'. Properties depend on element or
object type, but always include :begin, :end, :parent object type, but always include `:begin', `:end', `:parent' and
and :post-blank properties. `:post-blank' properties.
Optional argument ELEMENT, when non-nil, is the closest element Optional argument ELEMENT, when non-nil, is the closest element
containing point, as returned by `org-element-at-point'. containing point, as returned by `org-element-at-point'.
@ -4632,12 +4645,16 @@ Providing it allows for quicker computation."
(org-with-wide-buffer (org-with-wide-buffer
(let* ((origin (point)) (let* ((origin (point))
(element (or element (org-element-at-point))) (element (or element (org-element-at-point)))
(type (car element)) (type (org-element-type element))
end) end)
(cond
;; If point is within blank lines at the beginning of the
;; buffer, return nil.
((not element) nil)
;; Check if point is inside an element containing objects or at ;; Check if point is inside an element containing objects or at
;; a secondary string. In that case, move to beginning of the ;; a secondary string. In that case, move to beginning of the
;; element or secondary string and set END to the other side. ;; element or secondary string and set END to the other side.
(if (not (or (let ((post (org-element-property :post-affiliated element))) ((not (or (let ((post (org-element-property :post-affiliated element)))
(and post (> post origin) (and post (> post origin)
(< (org-element-property :begin element) origin) (< (org-element-property :begin element) origin)
(progn (beginning-of-line) (progn (beginning-of-line)
@ -4685,7 +4702,8 @@ Providing it allows for quicker computation."
(search-forward key (line-end-position) t) (search-forward key (line-end-position) t)
(forward-char) (forward-char)
(setq end (line-end-position)))))))) (setq end (line-end-position))))))))
element element)
(t
(let ((restriction (org-element-restriction type)) (let ((restriction (org-element-restriction type))
(parent element) (parent element)
candidates) candidates)
@ -4723,7 +4741,7 @@ Providing it allows for quicker computation."
(setq parent object (setq parent object
restriction (org-element-restriction object) restriction (org-element-restriction object)
end cend))))))) end cend)))))))
parent)))))) parent)))))))
(defsubst org-element-nested-p (elem-A elem-B) (defsubst org-element-nested-p (elem-A elem-B)
"Non-nil when elements ELEM-A and ELEM-B are nested." "Non-nil when elements ELEM-A and ELEM-B are nested."

View File

@ -2661,6 +2661,15 @@ Paragraph \\alpha."
(org-test-with-temp-text "- Para1\n- Para2\n\nPara3" (org-test-with-temp-text "- Para1\n- Para2\n\nPara3"
(progn (forward-line 2) (progn (forward-line 2)
(org-element-type (org-element-at-point)))))) (org-element-type (org-element-at-point))))))
;; Special case: within the first blank lines in buffer, return nil.
(should-not (org-test-with-temp-text "\nParagraph" (org-element-at-point)))
;; Special case: within the blank lines after a headline, return
;; that headline.
(should
(eq 'headline
(org-test-with-temp-text "* Headline\n\nParagraph"
(progn (forward-line)
(org-element-type (org-element-at-point))))))
;; With an optional argument, return trail. ;; With an optional argument, return trail.
(should (should
(equal '(paragraph center-block) (equal '(paragraph center-block)
@ -2733,7 +2742,9 @@ Paragraph \\alpha."
(org-test-with-temp-text "Some *text with _underline_ text*" (org-test-with-temp-text "Some *text with _underline_ text*"
(progn (progn
(search-forward "under") (search-forward "under")
(org-element-type (org-element-context (org-element-at-point)))))))) (org-element-type (org-element-context (org-element-at-point)))))))
;; Return nil when point is within the first blank lines.
(should-not (org-test-with-temp-text "\n* Headline" (org-element-context))))
(provide 'test-org-element) (provide 'test-org-element)