summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicolas Goaziou <mail@nicolasgoaziou.fr>2017-07-28 10:07:53 +0200
committerNicolas Goaziou <mail@nicolasgoaziou.fr>2017-07-28 10:07:53 +0200
commit808089ee049915be3bd00eebcbfb0abef860e244 (patch)
tree0d23bb3bc9f4a9c7bc1cbc4c970802eca0992259
parentf203d378bdc156ee5c0cde521fa0f64d831d1bb5 (diff)
downloadorg-mode-808089ee049915be3bd00eebcbfb0abef860e244.tar.gz
`org-forward/backward-paragraph' do not error at buffer boundaries
* lisp/org.el (org-forward-paragraph): (org-backward-paragraph): Do not error at buffer boundaries. Reported-by: Omar AntolĂ­n Camarena <omar.antolin@gmail.com> <http://lists.gnu.org/archive/html/emacs-orgmode/2017-07/msg00478.html>
-rw-r--r--lisp/org.el234
-rw-r--r--testing/lisp/test-org.el14
2 files changed, 125 insertions, 123 deletions
diff --git a/lisp/org.el b/lisp/org.el
index 458ec63..bf74812 100644
--- a/lisp/org.el
+++ b/lisp/org.el
@@ -24432,74 +24432,74 @@ item, etc. It also provides some special moves for convenience:
- On a table or a property drawer, jump after it.
- On a verse or source block, stop after blank lines."
(interactive)
- (when (eobp) (user-error "Cannot move further down"))
- (let* ((deactivate-mark nil)
- (element (org-element-at-point))
- (type (org-element-type element))
- (post-affiliated (org-element-property :post-affiliated element))
- (contents-begin (org-element-property :contents-begin element))
- (contents-end (org-element-property :contents-end element))
- (end (let ((end (org-element-property :end element)) (parent element))
- (while (and (setq parent (org-element-property :parent parent))
- (= (org-element-property :contents-end parent) end))
- (setq end (org-element-property :end parent)))
- end)))
- (cond ((not element)
- (skip-chars-forward " \r\t\n")
- (or (eobp) (beginning-of-line)))
- ;; On affiliated keywords, move to element's beginning.
- ((< (point) post-affiliated)
- (goto-char post-affiliated))
- ;; At a table row, move to the end of the table. Similarly,
- ;; at a node property, move to the end of the property
- ;; drawer.
- ((memq type '(node-property table-row))
- (goto-char (org-element-property
- :end (org-element-property :parent element))))
- ((memq type '(property-drawer table)) (goto-char end))
- ;; Consider blank lines as separators in verse and source
- ;; blocks to ease editing.
- ((memq type '(src-block verse-block))
- (when (eq type 'src-block)
- (setq contents-end
- (save-excursion (goto-char end)
- (skip-chars-backward " \r\t\n")
- (line-beginning-position))))
- (beginning-of-line)
- (when (looking-at "[ \t]*$") (skip-chars-forward " \r\t\n"))
- (if (not (re-search-forward "^[ \t]*$" contents-end t))
- (goto-char end)
- (skip-chars-forward " \r\t\n")
- (if (= (point) contents-end) (goto-char end)
- (beginning-of-line))))
- ;; With no contents, just skip element.
- ((not contents-begin) (goto-char end))
- ;; If contents are invisible, skip the element altogether.
- ((org-invisible-p (line-end-position))
- (cl-case type
- (headline
- (org-with-limited-levels (outline-next-visible-heading 1)))
- ;; At a plain list, make sure we move to the next item
- ;; instead of skipping the whole list.
- (plain-list (forward-char)
- (org-forward-paragraph))
- (otherwise (goto-char end))))
- ((>= (point) contents-end) (goto-char end))
- ((>= (point) contents-begin)
- ;; This can only happen on paragraphs and plain lists.
- (cl-case type
- (paragraph (goto-char end))
- ;; At a plain list, try to move to second element in
- ;; first item, if possible.
- (plain-list (end-of-line)
- (org-forward-paragraph))))
- ;; When contents start on the middle of a line (e.g. in
- ;; items and footnote definitions), try to reach first
- ;; element starting after current line.
- ((> (line-end-position) contents-begin)
- (end-of-line)
- (org-forward-paragraph))
- (t (goto-char contents-begin)))))
+ (unless (eobp)
+ (let* ((deactivate-mark nil)
+ (element (org-element-at-point))
+ (type (org-element-type element))
+ (post-affiliated (org-element-property :post-affiliated element))
+ (contents-begin (org-element-property :contents-begin element))
+ (contents-end (org-element-property :contents-end element))
+ (end (let ((end (org-element-property :end element)) (parent element))
+ (while (and (setq parent (org-element-property :parent parent))
+ (= (org-element-property :contents-end parent) end))
+ (setq end (org-element-property :end parent)))
+ end)))
+ (cond ((not element)
+ (skip-chars-forward " \r\t\n")
+ (or (eobp) (beginning-of-line)))
+ ;; On affiliated keywords, move to element's beginning.
+ ((< (point) post-affiliated)
+ (goto-char post-affiliated))
+ ;; At a table row, move to the end of the table. Similarly,
+ ;; at a node property, move to the end of the property
+ ;; drawer.
+ ((memq type '(node-property table-row))
+ (goto-char (org-element-property
+ :end (org-element-property :parent element))))
+ ((memq type '(property-drawer table)) (goto-char end))
+ ;; Consider blank lines as separators in verse and source
+ ;; blocks to ease editing.
+ ((memq type '(src-block verse-block))
+ (when (eq type 'src-block)
+ (setq contents-end
+ (save-excursion (goto-char end)
+ (skip-chars-backward " \r\t\n")
+ (line-beginning-position))))
+ (beginning-of-line)
+ (when (looking-at "[ \t]*$") (skip-chars-forward " \r\t\n"))
+ (if (not (re-search-forward "^[ \t]*$" contents-end t))
+ (goto-char end)
+ (skip-chars-forward " \r\t\n")
+ (if (= (point) contents-end) (goto-char end)
+ (beginning-of-line))))
+ ;; With no contents, just skip element.
+ ((not contents-begin) (goto-char end))
+ ;; If contents are invisible, skip the element altogether.
+ ((org-invisible-p (line-end-position))
+ (cl-case type
+ (headline
+ (org-with-limited-levels (outline-next-visible-heading 1)))
+ ;; At a plain list, make sure we move to the next item
+ ;; instead of skipping the whole list.
+ (plain-list (forward-char)
+ (org-forward-paragraph))
+ (otherwise (goto-char end))))
+ ((>= (point) contents-end) (goto-char end))
+ ((>= (point) contents-begin)
+ ;; This can only happen on paragraphs and plain lists.
+ (cl-case type
+ (paragraph (goto-char end))
+ ;; At a plain list, try to move to second element in
+ ;; first item, if possible.
+ (plain-list (end-of-line)
+ (org-forward-paragraph))))
+ ;; When contents start on the middle of a line (e.g. in
+ ;; items and footnote definitions), try to reach first
+ ;; element starting after current line.
+ ((> (line-end-position) contents-begin)
+ (end-of-line)
+ (org-forward-paragraph))
+ (t (goto-char contents-begin))))))
(defun org-backward-paragraph ()
"Move backward to start of previous paragraph or equivalent.
@@ -24514,55 +24514,55 @@ convenience:
- On a table or a property drawer, move to its beginning.
- On a verse or source block, stop before blank lines."
(interactive)
- (when (bobp) (user-error "Cannot move further up"))
- (let* ((deactivate-mark nil)
- (element (org-element-at-point))
- (type (org-element-type element))
- (contents-begin (org-element-property :contents-begin element))
- (contents-end (org-element-property :contents-end element))
- (post-affiliated (org-element-property :post-affiliated element))
- (begin (org-element-property :begin element)))
- (cond
- ((not element) (goto-char (point-min)))
- ((= (point) begin)
- (backward-char)
- (org-backward-paragraph))
- ((<= (point) post-affiliated) (goto-char begin))
- ((memq type '(node-property table-row))
- (goto-char (org-element-property
- :post-affiliated (org-element-property :parent element))))
- ((memq type '(property-drawer table)) (goto-char begin))
- ((memq type '(src-block verse-block))
- (when (eq type 'src-block)
- (setq contents-begin
- (save-excursion (goto-char begin) (forward-line) (point))))
- (if (= (point) contents-begin) (goto-char post-affiliated)
- ;; Inside a verse block, see blank lines as paragraph
- ;; separators.
- (let ((origin (point)))
- (skip-chars-backward " \r\t\n" contents-begin)
- (when (re-search-backward "^[ \t]*$" contents-begin 'move)
- (skip-chars-forward " \r\t\n" origin)
- (if (= (point) origin) (goto-char contents-begin)
- (beginning-of-line))))))
- ((not contents-begin) (goto-char (or post-affiliated begin)))
- ((eq type 'paragraph)
- (goto-char contents-begin)
- ;; When at first paragraph in an item or a footnote definition,
- ;; move directly to beginning of line.
- (let ((parent-contents
- (org-element-property
- :contents-begin (org-element-property :parent element))))
- (when (and parent-contents (= parent-contents contents-begin))
- (beginning-of-line))))
- ;; At the end of a greater element, move to the beginning of the
- ;; last element within.
- ((>= (point) contents-end)
- (goto-char (1- contents-end))
- (org-backward-paragraph))
- (t (goto-char (or post-affiliated begin))))
- ;; Ensure we never leave point invisible.
- (when (org-invisible-p (point)) (beginning-of-visual-line))))
+ (unless (bobp)
+ (let* ((deactivate-mark nil)
+ (element (org-element-at-point))
+ (type (org-element-type element))
+ (contents-begin (org-element-property :contents-begin element))
+ (contents-end (org-element-property :contents-end element))
+ (post-affiliated (org-element-property :post-affiliated element))
+ (begin (org-element-property :begin element)))
+ (cond
+ ((not element) (goto-char (point-min)))
+ ((= (point) begin)
+ (backward-char)
+ (org-backward-paragraph))
+ ((<= (point) post-affiliated) (goto-char begin))
+ ((memq type '(node-property table-row))
+ (goto-char (org-element-property
+ :post-affiliated (org-element-property :parent element))))
+ ((memq type '(property-drawer table)) (goto-char begin))
+ ((memq type '(src-block verse-block))
+ (when (eq type 'src-block)
+ (setq contents-begin
+ (save-excursion (goto-char begin) (forward-line) (point))))
+ (if (= (point) contents-begin) (goto-char post-affiliated)
+ ;; Inside a verse block, see blank lines as paragraph
+ ;; separators.
+ (let ((origin (point)))
+ (skip-chars-backward " \r\t\n" contents-begin)
+ (when (re-search-backward "^[ \t]*$" contents-begin 'move)
+ (skip-chars-forward " \r\t\n" origin)
+ (if (= (point) origin) (goto-char contents-begin)
+ (beginning-of-line))))))
+ ((not contents-begin) (goto-char (or post-affiliated begin)))
+ ((eq type 'paragraph)
+ (goto-char contents-begin)
+ ;; When at first paragraph in an item or a footnote definition,
+ ;; move directly to beginning of line.
+ (let ((parent-contents
+ (org-element-property
+ :contents-begin (org-element-property :parent element))))
+ (when (and parent-contents (= parent-contents contents-begin))
+ (beginning-of-line))))
+ ;; At the end of a greater element, move to the beginning of the
+ ;; last element within.
+ ((>= (point) contents-end)
+ (goto-char (1- contents-end))
+ (org-backward-paragraph))
+ (t (goto-char (or post-affiliated begin))))
+ ;; Ensure we never leave point invisible.
+ (when (org-invisible-p (point)) (beginning-of-visual-line)))))
(defun org-forward-element ()
"Move forward by one element.
diff --git a/testing/lisp/test-org.el b/testing/lisp/test-org.el
index 2c06522..a952c80 100644
--- a/testing/lisp/test-org.el
+++ b/testing/lisp/test-org.el
@@ -3259,11 +3259,12 @@ SCHEDULED: <2017-05-06 Sat>
(ert-deftest test-org/forward-paragraph ()
"Test `org-forward-paragraph' specifications."
- ;; At end of buffer, return an error.
- (should-error
+ ;; At end of buffer, do not return an error.
+ (should
(org-test-with-temp-text "Paragraph"
(goto-char (point-max))
- (org-forward-paragraph)))
+ (org-forward-paragraph)
+ t))
;; Standard test.
(should
(org-test-with-temp-text "P1\n\nP2\n\nP3"
@@ -3328,10 +3329,11 @@ SCHEDULED: <2017-05-06 Sat>
(ert-deftest test-org/backward-paragraph ()
"Test `org-backward-paragraph' specifications."
- ;; Error at beginning of buffer.
- (should-error
+ ;; Do not error at beginning of buffer.
+ (should
(org-test-with-temp-text "Paragraph"
- (org-backward-paragraph)))
+ (org-backward-paragraph)
+ t))
;; Regular test.
(should
(org-test-with-temp-text "P1\n\nP2\n\nP3"