forked from mirrors/org-mode
Rewrite `org-forward-paragraph' and `org-backward-paragraph'
* lisp/org.el (org-forward-paragraph): (org-backward-paragraph): Rewrite functions. Add repeat argument. Mimic more closely regular `forward|backward-paragraph' functions. (org--forward-paragraph-once): (org--backward-paragraph-once): (org--paragraph-at-point): New functions. * testing/lisp/test-org.el (test-org/forward-paragraph): (test-org/backward-paragraph): Update tests. Add some. Signed-off-by: Nicolas Goaziou <mail@nicolasgoaziou.fr>
This commit is contained in:
parent
6882478cac
commit
e2b62b4da8
|
@ -385,6 +385,15 @@ From ~org-enable-priority-commands~ to ~org-priority-enable-commands~.
|
||||||
From ~org-show-priority~ to ~org-priority-show~.
|
From ~org-show-priority~ to ~org-priority-show~.
|
||||||
|
|
||||||
** Miscellaneous
|
** Miscellaneous
|
||||||
|
*** Forward/backward paragraph functions in line with the rest of Emacs
|
||||||
|
~org-forward-paragraph~ and ~org-backward-paragraph~, bound to
|
||||||
|
~<C-UP>~ and ~<C-DOWN>~ functions mimic more closely behaviour of
|
||||||
|
~forward-paragraph~ and ~backward-paragraph~ functions when
|
||||||
|
available.
|
||||||
|
|
||||||
|
They also accept an optional argument for multiple calls.
|
||||||
|
|
||||||
|
See their docstring for details.
|
||||||
*** ~org-table-to-lisp~ no longer checks if point is at a table
|
*** ~org-table-to-lisp~ no longer checks if point is at a table
|
||||||
The caller is now responsible for the check. It can use, e.g.,
|
The caller is now responsible for the check. It can use, e.g.,
|
||||||
~org-at-table-p~.
|
~org-at-table-p~.
|
||||||
|
|
430
lisp/org.el
430
lisp/org.el
|
@ -20512,156 +20512,300 @@ With ARG, repeats or can move forward if negative."
|
||||||
(interactive "p")
|
(interactive "p")
|
||||||
(org-next-visible-heading (- arg)))
|
(org-next-visible-heading (- arg)))
|
||||||
|
|
||||||
(defun org-forward-paragraph ()
|
(defun org-forward-paragraph (&optional arg)
|
||||||
"Move forward to beginning of next paragraph or equivalent.
|
"Move forward by a paragraph, or equivalent, unit.
|
||||||
|
|
||||||
The function moves point to the beginning of the next visible
|
With argument ARG, do it ARG times;
|
||||||
structural element, which can be a paragraph, a table, a list
|
a negative argument ARG = -N means move backward N paragraphs.
|
||||||
item, etc. It also provides some special moves for convenience:
|
|
||||||
|
|
||||||
- On an affiliated keyword, jump to the beginning of the
|
The function moves point between two structural
|
||||||
relative element.
|
elements (paragraphs, tables, lists, etc.).
|
||||||
- On an item or a footnote definition, move to the second
|
|
||||||
element inside, if any.
|
|
||||||
- On a table or a property drawer, jump after it.
|
|
||||||
- On a verse or source block, stop after blank lines."
|
|
||||||
(interactive)
|
|
||||||
(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 ()
|
It also provides the following special moves for convenience:
|
||||||
"Move backward to start of previous paragraph or equivalent.
|
|
||||||
|
|
||||||
The function moves point to the beginning of the current
|
- on a table or a property drawer, move to its beginning;
|
||||||
structural element, which can be a paragraph, a table, a list
|
- on comment, example, export, source and verse blocks, stop
|
||||||
item, etc., or to the beginning of the previous visible one if
|
at blank lines;
|
||||||
point is already there. It also provides some special moves for
|
- skip consecutive clocks, diary S-exps, and keywords."
|
||||||
convenience:
|
(interactive "^p")
|
||||||
|
(unless arg (setq arg 1))
|
||||||
|
(if (< arg 0) (org-backward-paragraph (- arg))
|
||||||
|
(while (and (> arg 0) (not (eobp)))
|
||||||
|
(org--forward-paragraph-once)
|
||||||
|
(cl-decf arg))
|
||||||
|
;; Return moves left.
|
||||||
|
arg))
|
||||||
|
|
||||||
- On an affiliated keyword, jump to the first one.
|
(defun org-backward-paragraph (&optional arg)
|
||||||
- On a table or a property drawer, move to its beginning.
|
"Move backward by a paragraph, or equivalent, unit.
|
||||||
- On comment, example, export, src and verse blocks, stop
|
|
||||||
before blank lines."
|
With argument ARG, do it ARG times;
|
||||||
(interactive)
|
a negative argument ARG = -N means move forward N paragraphs.
|
||||||
(unless (bobp)
|
|
||||||
(let* ((deactivate-mark nil)
|
The function moves point between two structural
|
||||||
(element (org-element-at-point))
|
elements (paragraphs, tables, lists, etc.).
|
||||||
(type (org-element-type element))
|
|
||||||
(contents-end (org-element-property :contents-end element))
|
It also provides the following special moves for convenience:
|
||||||
(post-affiliated (org-element-property :post-affiliated element))
|
|
||||||
(begin (org-element-property :begin element))
|
- on a table or a property drawer, move to its beginning;
|
||||||
(special? ;blocks handled specially
|
- on comment, example, export, source and verse blocks, stop
|
||||||
(memq type '(comment-block example-block export-block src-block
|
at blank lines;
|
||||||
verse-block)))
|
- skip consecutive clocks, diary S-exps, and keywords."
|
||||||
(contents-begin
|
(interactive "^p")
|
||||||
(if special?
|
(unless arg (setq arg 1))
|
||||||
;; These types have no proper contents. Fake line
|
(if (< arg 0) (org-forward-paragraph (- arg))
|
||||||
;; below the block opening line as contents beginning.
|
(while (and (> arg 0) (not (bobp)))
|
||||||
(save-excursion (goto-char begin) (line-beginning-position 2))
|
(org--backward-paragraph-once)
|
||||||
(org-element-property :contents-begin element))))
|
(cl-decf arg))
|
||||||
|
;; Return moves left.
|
||||||
|
arg))
|
||||||
|
|
||||||
|
(defun org--paragraph-at-point ()
|
||||||
|
"Return paragraph, or equivalent, element at point.
|
||||||
|
|
||||||
|
Paragraph element at point is the element at point, with the
|
||||||
|
following special cases:
|
||||||
|
|
||||||
|
- treat table rows (resp. node properties) as the table
|
||||||
|
\(resp. property drawer) containing them.
|
||||||
|
|
||||||
|
- treat plain lists with an item every line as a whole.
|
||||||
|
|
||||||
|
- treat consecutive keywords, clocks, and diary-sexps as a single
|
||||||
|
block.
|
||||||
|
|
||||||
|
Function may return a real element, or a pseudo-element with type
|
||||||
|
`pseudo-paragraph'."
|
||||||
|
(let* ((e (org-element-at-point))
|
||||||
|
(type (org-element-type e))
|
||||||
|
;; If we need to fake a new pseudo-element, triplet is
|
||||||
|
;;
|
||||||
|
;; (BEG END PARENT)
|
||||||
|
;;
|
||||||
|
;; where BEG and END are element boundaries, and PARENT the
|
||||||
|
;; element containing it, or nil.
|
||||||
|
(triplet
|
||||||
(cond
|
(cond
|
||||||
((not element) (goto-char (point-min)))
|
((memq type '(table property-drawer))
|
||||||
((= (point) begin)
|
(list (org-element-property :begin e)
|
||||||
(backward-char)
|
(org-element-property :end e)
|
||||||
(org-backward-paragraph))
|
(org-element-property :parent e)))
|
||||||
((<= (point) post-affiliated) (goto-char begin))
|
|
||||||
;; Special behavior: on a table or a property drawer, move to
|
|
||||||
;; its beginning.
|
|
||||||
((memq type '(node-property table-row))
|
((memq type '(node-property table-row))
|
||||||
(goto-char (org-element-property
|
(let ((e (org-element-property :parent e)))
|
||||||
:post-affiliated (org-element-property :parent element))))
|
(list (org-element-property :begin e)
|
||||||
(special?
|
(org-element-property :end e)
|
||||||
(if (<= (point) contents-begin) (goto-char post-affiliated)
|
(org-element-property :parent e))))
|
||||||
;; Inside a verse block, see blank lines as paragraph
|
((memq type '(clock diary-sexp keyword))
|
||||||
;; separators.
|
(let* ((regexp (pcase type
|
||||||
(let ((origin (point)))
|
(`clock org-clock-line-re)
|
||||||
(skip-chars-backward " \r\t\n" contents-begin)
|
(`diary-sexp "%%(")
|
||||||
(when (re-search-backward "^[ \t]*$" contents-begin 'move)
|
(_ org-keyword-regexp)))
|
||||||
(skip-chars-forward " \r\t\n" origin)
|
(end (if (< 0 (org-element-property :post-blank e))
|
||||||
(if (= (point) origin) (goto-char contents-begin)
|
(org-element-property :end e)
|
||||||
(beginning-of-line))))))
|
(org-with-wide-buffer
|
||||||
((eq type 'paragraph) (goto-char contents-begin)
|
(forward-line)
|
||||||
;; When at first paragraph in an item or a footnote definition,
|
(while (looking-at regexp) (forward-line))
|
||||||
;; move directly to beginning of line.
|
(skip-chars-forward " \t\n")
|
||||||
(let ((parent-contents
|
(line-beginning-position))))
|
||||||
(org-element-property
|
(begin (org-with-point-at (org-element-property :begin e)
|
||||||
:contents-begin (org-element-property :parent element))))
|
(while (and (not (bobp)) (looking-at regexp))
|
||||||
(when (and parent-contents (= parent-contents contents-begin))
|
(forward-line -1))
|
||||||
(beginning-of-line))))
|
;; We may have gotten one line too far.
|
||||||
;; At the end of a greater element, move to the beginning of
|
(if (looking-at regexp)
|
||||||
;; the last element within.
|
(point)
|
||||||
((and contents-end (>= (point) contents-end))
|
(line-beginning-position 2)))))
|
||||||
(goto-char (1- contents-end))
|
(list begin end (org-element-property :parent e))))
|
||||||
(org-backward-paragraph))
|
;; Find the full plain list containing point, the check it
|
||||||
(t (goto-char (or post-affiliated begin))))
|
;; contains exactly one line per item.
|
||||||
;; Ensure we never leave point invisible.
|
((let ((l (org-element-lineage e '(plain-list) t)))
|
||||||
(when (org-invisible-p (point)) (beginning-of-visual-line)))))
|
(while (memq (org-element-type (org-element-property :parent l))
|
||||||
|
'(item plain-list))
|
||||||
|
(setq l (org-element-property :parent l)))
|
||||||
|
(and l
|
||||||
|
(org-with-point-at (org-element-property :post-affiliated l)
|
||||||
|
(forward-line (length (org-element-property :structure l)))
|
||||||
|
(= (point) (org-element-property :contents-end l)))
|
||||||
|
;; Return value.
|
||||||
|
(list (org-element-property :begin l)
|
||||||
|
(org-element-property :end l)
|
||||||
|
(org-element-property :parent l)))))
|
||||||
|
(t nil)))) ;no triplet: return element
|
||||||
|
(pcase triplet
|
||||||
|
(`(,b ,e ,p)
|
||||||
|
(org-element-create
|
||||||
|
'pseudo-paragraph
|
||||||
|
(list :begin b :end e :parent p :post-blank 0 :post-affiliated b)))
|
||||||
|
(_ e))))
|
||||||
|
|
||||||
|
(defun org--forward-paragraph-once ()
|
||||||
|
"Move forward to end of paragraph or equivalent, once.
|
||||||
|
See `org-forward-paragraph'."
|
||||||
|
(interactive)
|
||||||
|
(save-restriction
|
||||||
|
(widen)
|
||||||
|
(skip-chars-forward " \t\n")
|
||||||
|
(cond
|
||||||
|
((eobp) nil)
|
||||||
|
;; When inside a folded part, move out of it.
|
||||||
|
((pcase (get-char-property-and-overlay (point) 'invisible)
|
||||||
|
(`(,(or `outline `org-hide-block `org-hide-drawer) . ,o)
|
||||||
|
(goto-char (overlay-end o))
|
||||||
|
(forward-line)
|
||||||
|
t)
|
||||||
|
(_ nil)))
|
||||||
|
(t
|
||||||
|
(let* ((element (org--paragraph-at-point))
|
||||||
|
(type (org-element-type element))
|
||||||
|
(contents-begin (org-element-property :contents-begin element))
|
||||||
|
(end (org-element-property :end element))
|
||||||
|
(post-affiliated (org-element-property :post-affiliated element)))
|
||||||
|
(cond
|
||||||
|
((eq type 'plain-list)
|
||||||
|
(forward-char)
|
||||||
|
(org--forward-paragraph-once))
|
||||||
|
;; If the element is folded, skip it altogether.
|
||||||
|
((pcase (org-with-point-at post-affiliated
|
||||||
|
(get-char-property-and-overlay (line-end-position)
|
||||||
|
'invisible))
|
||||||
|
(`(,(or `outline `org-hide-block `org-hide-drawer) . ,o)
|
||||||
|
(goto-char (overlay-end o))
|
||||||
|
(forward-line)
|
||||||
|
t)
|
||||||
|
(_ nil)))
|
||||||
|
;; At a greater element, move inside.
|
||||||
|
((and contents-begin
|
||||||
|
(> contents-begin (point))
|
||||||
|
(not (eq type 'paragraph)))
|
||||||
|
(goto-char contents-begin)
|
||||||
|
;; Items and footnote definitions contents may not start at
|
||||||
|
;; the beginning of the line. In this case, skip until the
|
||||||
|
;; next paragraph.
|
||||||
|
(cond
|
||||||
|
((not (bolp)) (org--forward-paragraph-once))
|
||||||
|
((org-previous-line-empty-p) (forward-line -1))
|
||||||
|
(t nil)))
|
||||||
|
;; Move between empty lines in some blocks.
|
||||||
|
((memq type '(comment-block example-block export-block src-block
|
||||||
|
verse-block))
|
||||||
|
(let ((contents-start
|
||||||
|
(org-with-point-at post-affiliated
|
||||||
|
(line-beginning-position 2))))
|
||||||
|
(if (< (point) contents-start)
|
||||||
|
(goto-char contents-start)
|
||||||
|
(let ((contents-end
|
||||||
|
(org-with-point-at end
|
||||||
|
(skip-chars-backward " \t\n")
|
||||||
|
(line-beginning-position))))
|
||||||
|
(cond
|
||||||
|
((>= (point) contents-end)
|
||||||
|
(goto-char end)
|
||||||
|
(skip-chars-backward " \t\n")
|
||||||
|
(forward-line))
|
||||||
|
((re-search-forward "^[ \t]*\n" contents-end :move)
|
||||||
|
(forward-line -1))
|
||||||
|
(t nil))))))
|
||||||
|
(t
|
||||||
|
;; Move to element's end.
|
||||||
|
(goto-char end)
|
||||||
|
(skip-chars-backward " \t\n")
|
||||||
|
(forward-line))))))))
|
||||||
|
|
||||||
|
(defun org--backward-paragraph-once ()
|
||||||
|
"Move backward to start of paragraph or equivalent, once.
|
||||||
|
See `org-backward-paragraph'."
|
||||||
|
(interactive)
|
||||||
|
(save-restriction
|
||||||
|
(widen)
|
||||||
|
(cond
|
||||||
|
((bobp) nil)
|
||||||
|
;; Blank lines at the beginning of the buffer.
|
||||||
|
((and (org-match-line "^[ \t]*$")
|
||||||
|
(save-excursion (skip-chars-backward " \t\n") (bobp)))
|
||||||
|
(goto-char (point-min)))
|
||||||
|
;; When inside a folded part, move out of it.
|
||||||
|
((pcase (get-char-property-and-overlay (1- (point)) 'invisible)
|
||||||
|
(`(,(or `outline `org-hide-block `org-hide-drawer) . ,o)
|
||||||
|
(goto-char (1- (overlay-start o)))
|
||||||
|
(org--backward-paragraph-once)
|
||||||
|
t)
|
||||||
|
(_ nil)))
|
||||||
|
(t
|
||||||
|
(let* ((element (org--paragraph-at-point))
|
||||||
|
(type (org-element-type element))
|
||||||
|
(begin (org-element-property :begin element))
|
||||||
|
(post-affiliated (org-element-property :post-affiliated element))
|
||||||
|
(contents-end (org-element-property :contents-end element))
|
||||||
|
(end (org-element-property :end element))
|
||||||
|
(parent (org-element-property :parent element))
|
||||||
|
(reach
|
||||||
|
;; Move to the visible empty line above position P, or
|
||||||
|
;; to position P. Return t.
|
||||||
|
(lambda (p)
|
||||||
|
(goto-char p)
|
||||||
|
(when (and (org-previous-line-empty-p)
|
||||||
|
(let ((end (line-end-position 0)))
|
||||||
|
(or (= end (point-min))
|
||||||
|
(not (org-invisible-p (1- end))))))
|
||||||
|
(forward-line -1))
|
||||||
|
t)))
|
||||||
|
(cond
|
||||||
|
;; Already at the beginning of an element.
|
||||||
|
((= begin (point))
|
||||||
|
(cond
|
||||||
|
;; There is a blank line above. Move there.
|
||||||
|
((and (org-previous-line-empty-p)
|
||||||
|
(not (org-invisible-p (1- (line-end-position 0)))))
|
||||||
|
(forward-line -1))
|
||||||
|
;; At the beginning of the first element within a greater
|
||||||
|
;; element. Move to the beginning of the greater element.
|
||||||
|
((and parent (= begin (org-element-property :contents-begin parent)))
|
||||||
|
(funcall reach (org-element-property :begin parent)))
|
||||||
|
;; Since we have to move anyway, find the beginning
|
||||||
|
;; position of the element above.
|
||||||
|
(t
|
||||||
|
(forward-char -1)
|
||||||
|
(org--backward-paragraph-once))))
|
||||||
|
;; Skip paragraphs at the very beginning of footnote
|
||||||
|
;; definitions or items.
|
||||||
|
((and (eq type 'paragraph)
|
||||||
|
(org-with-point-at begin (not (bolp))))
|
||||||
|
(funcall reach (progn (goto-char begin) (line-beginning-position))))
|
||||||
|
;; If the element is folded, skip it altogether.
|
||||||
|
((org-with-point-at post-affiliated
|
||||||
|
(org-invisible-p (line-end-position) t))
|
||||||
|
(funcall reach begin))
|
||||||
|
;; At the end of a greater element, move inside.
|
||||||
|
((and contents-end
|
||||||
|
(<= contents-end (point))
|
||||||
|
(not (eq type 'paragraph)))
|
||||||
|
(cond
|
||||||
|
((memq type '(footnote-definition plain-list))
|
||||||
|
(skip-chars-backward " \t\n")
|
||||||
|
(org--backward-paragraph-once))
|
||||||
|
((= contents-end (point))
|
||||||
|
(forward-char -1)
|
||||||
|
(org--backward-paragraph-once))
|
||||||
|
(t
|
||||||
|
(goto-char contents-end))))
|
||||||
|
;; Move between empty lines in some blocks.
|
||||||
|
((and (memq type '(comment-block example-block export-block src-block
|
||||||
|
verse-block))
|
||||||
|
(let ((contents-start
|
||||||
|
(org-with-point-at post-affiliated
|
||||||
|
(line-beginning-position 2))))
|
||||||
|
(when (> (point) contents-start)
|
||||||
|
(let ((contents-end
|
||||||
|
(org-with-point-at end
|
||||||
|
(skip-chars-backward " \t\n")
|
||||||
|
(line-beginning-position))))
|
||||||
|
(if (> (point) contents-end)
|
||||||
|
(progn (goto-char contents-end) t)
|
||||||
|
(skip-chars-backward " \t\n" begin)
|
||||||
|
(re-search-backward "^[ \t]*\n" contents-start :move)
|
||||||
|
t))))))
|
||||||
|
;; Move to element's start.
|
||||||
|
(t
|
||||||
|
(funcall reach begin))))))))
|
||||||
|
|
||||||
(defun org-forward-element ()
|
(defun org-forward-element ()
|
||||||
"Move forward by one element.
|
"Move forward by one element.
|
||||||
|
|
|
@ -3700,45 +3700,46 @@ SCHEDULED: <2017-05-06 Sat>
|
||||||
t))
|
t))
|
||||||
;; Standard test.
|
;; Standard test.
|
||||||
(should
|
(should
|
||||||
|
(= 2
|
||||||
|
(org-test-with-temp-text "P1\n\nP2"
|
||||||
|
(org-forward-paragraph)
|
||||||
|
(org-current-line))))
|
||||||
|
(should
|
||||||
|
(= 2
|
||||||
(org-test-with-temp-text "P1\n\nP2\n\nP3"
|
(org-test-with-temp-text "P1\n\nP2\n\nP3"
|
||||||
(org-forward-paragraph)
|
(org-forward-paragraph)
|
||||||
(looking-at "P2")))
|
(org-current-line))))
|
||||||
;; Ignore depth.
|
;; Enter greater elements.
|
||||||
(should
|
(should
|
||||||
(org-test-with-temp-text "#+BEGIN_CENTER\nP1\n#+END_CENTER\nP2"
|
(= 2
|
||||||
|
(org-test-with-temp-text "#+begin_center\nP1\n#+end_center\nP2"
|
||||||
(org-forward-paragraph)
|
(org-forward-paragraph)
|
||||||
(looking-at "P1")))
|
(org-current-line))))
|
||||||
;; Do not enter elements with invisible contents.
|
;; Do not enter elements with invisible contents.
|
||||||
(should
|
(should
|
||||||
(org-test-with-temp-text "#+BEGIN_CENTER\nP1\n\nP2\n#+END_CENTER\nP3"
|
(= 4
|
||||||
|
(org-test-with-temp-text "* H1\n P1\n\n* H2"
|
||||||
|
(org-cycle)
|
||||||
|
(org-forward-paragraph)
|
||||||
|
(org-current-line))))
|
||||||
|
(should
|
||||||
|
(= 6
|
||||||
|
(org-test-with-temp-text "#+begin_center\nP1\n\nP2\n#+end_center\nP3"
|
||||||
(org-hide-block-toggle)
|
(org-hide-block-toggle)
|
||||||
(org-forward-paragraph)
|
(org-forward-paragraph)
|
||||||
(looking-at "P3")))
|
(org-current-line))))
|
||||||
;; On an affiliated keyword, jump to the beginning of the element.
|
;; On an item or a footnote definition, move past the first element
|
||||||
(should
|
|
||||||
(org-test-with-temp-text "#+name: para\n#+caption: caption\nPara"
|
|
||||||
(org-forward-paragraph)
|
|
||||||
(looking-at "Para")))
|
|
||||||
;; On an item or a footnote definition, move to the second element
|
|
||||||
;; inside, if any.
|
;; inside, if any.
|
||||||
(should
|
(should
|
||||||
|
(= 2
|
||||||
(org-test-with-temp-text "- Item1\n\n Paragraph\n- Item2"
|
(org-test-with-temp-text "- Item1\n\n Paragraph\n- Item2"
|
||||||
(org-forward-paragraph)
|
(org-forward-paragraph)
|
||||||
(looking-at " Paragraph")))
|
(org-current-line))))
|
||||||
(should
|
(should
|
||||||
|
(= 2
|
||||||
(org-test-with-temp-text "[fn:1] Def1\n\nParagraph\n\n[fn:2] Def2"
|
(org-test-with-temp-text "[fn:1] Def1\n\nParagraph\n\n[fn:2] Def2"
|
||||||
(org-forward-paragraph)
|
(org-forward-paragraph)
|
||||||
(looking-at "Paragraph")))
|
(org-current-line))))
|
||||||
;; On an item, or a footnote definition, when the first line is
|
|
||||||
;; empty, move to the first item.
|
|
||||||
(should
|
|
||||||
(org-test-with-temp-text "- \n\n Paragraph\n- Item2"
|
|
||||||
(org-forward-paragraph)
|
|
||||||
(looking-at " Paragraph")))
|
|
||||||
(should
|
|
||||||
(org-test-with-temp-text "[fn:1]\n\nParagraph\n\n[fn:2] Def2"
|
|
||||||
(org-forward-paragraph)
|
|
||||||
(looking-at "Paragraph")))
|
|
||||||
;; On a table (resp. a property drawer) do not move through table
|
;; On a table (resp. a property drawer) do not move through table
|
||||||
;; rows (resp. node properties).
|
;; rows (resp. node properties).
|
||||||
(should
|
(should
|
||||||
|
@ -3750,15 +3751,59 @@ SCHEDULED: <2017-05-06 Sat>
|
||||||
"* H\n<point>:PROPERTIES:\n:prop: value\n:END:\nParagraph"
|
"* H\n<point>:PROPERTIES:\n:prop: value\n:END:\nParagraph"
|
||||||
(org-forward-paragraph)
|
(org-forward-paragraph)
|
||||||
(looking-at "Paragraph")))
|
(looking-at "Paragraph")))
|
||||||
;; On a verse or source block, stop after blank lines.
|
;; Skip consecutive keywords, clocks and diary S-exps.
|
||||||
(should
|
(should
|
||||||
(org-test-with-temp-text "#+BEGIN_VERSE\nL1\n\nL2\n#+END_VERSE"
|
(org-test-with-temp-text "#+key: val\n #+key2: val\n#+key3: val\n"
|
||||||
(org-forward-paragraph)
|
(org-forward-paragraph)
|
||||||
(looking-at "L2")))
|
(eobp)))
|
||||||
(should
|
(should
|
||||||
(org-test-with-temp-text "#+BEGIN_SRC\nL1\n\nL2\n#+END_SRC"
|
(org-test-with-temp-text "CLOCK: val\n CLOCK: val\nCLOCK: val\n"
|
||||||
(org-forward-paragraph)
|
(org-forward-paragraph)
|
||||||
(looking-at "L2"))))
|
(eobp)))
|
||||||
|
(should
|
||||||
|
(org-test-with-temp-text "%%(foo)\n%%(bar)\n%%(baz)\n"
|
||||||
|
(org-forward-paragraph)
|
||||||
|
(eobp)))
|
||||||
|
(should-not
|
||||||
|
(org-test-with-temp-text "#+key: val\n #+key2: val\n\n#+key3: val\n"
|
||||||
|
(org-forward-paragraph)
|
||||||
|
(eobp)))
|
||||||
|
(should-not
|
||||||
|
(org-test-with-temp-text "#+key: val\nCLOCK: ...\n"
|
||||||
|
(org-forward-paragraph)
|
||||||
|
(eobp)))
|
||||||
|
;; In a plain list with one item every line, skip the whole list,
|
||||||
|
;; even with point in the middle of the list.
|
||||||
|
(should
|
||||||
|
(org-test-with-temp-text "- A\n - B\n- C\n"
|
||||||
|
(org-forward-paragraph)
|
||||||
|
(eobp)))
|
||||||
|
(should
|
||||||
|
(org-test-with-temp-text "- A\n - <point>B\n- C\n"
|
||||||
|
(org-forward-paragraph)
|
||||||
|
(eobp)))
|
||||||
|
;; On a comment, verse or source block, stop at "contents"
|
||||||
|
;; boundaries and blank lines.
|
||||||
|
(should
|
||||||
|
(= 2
|
||||||
|
(org-test-with-temp-text "#+begin_src emacs-lisp\nL1\n\nL2\n#+end_src"
|
||||||
|
(org-forward-paragraph)
|
||||||
|
(org-current-line))))
|
||||||
|
(should
|
||||||
|
(= 3
|
||||||
|
(org-test-with-temp-text "#+begin_verse\n<point>L1\n\nL2\n#+end_verse"
|
||||||
|
(org-forward-paragraph)
|
||||||
|
(org-current-line))))
|
||||||
|
(should
|
||||||
|
(= 5
|
||||||
|
(org-test-with-temp-text "#+begin_comment\nL1\n\n<point>L2\n#+end_comment"
|
||||||
|
(org-forward-paragraph)
|
||||||
|
(org-current-line))))
|
||||||
|
;; Being on an affiliated keyword shouldn't make any difference.
|
||||||
|
(should
|
||||||
|
(org-test-with-temp-text "#+name: para\n#+caption: caption\nPara"
|
||||||
|
(org-forward-paragraph)
|
||||||
|
(eobp))))
|
||||||
|
|
||||||
(ert-deftest test-org/backward-paragraph ()
|
(ert-deftest test-org/backward-paragraph ()
|
||||||
"Test `org-backward-paragraph' specifications."
|
"Test `org-backward-paragraph' specifications."
|
||||||
|
@ -3767,44 +3812,65 @@ SCHEDULED: <2017-05-06 Sat>
|
||||||
(org-test-with-temp-text "Paragraph"
|
(org-test-with-temp-text "Paragraph"
|
||||||
(org-backward-paragraph)
|
(org-backward-paragraph)
|
||||||
t))
|
t))
|
||||||
|
;; At blank lines at the very beginning of a buffer, move to
|
||||||
|
;; point-min.
|
||||||
|
(should
|
||||||
|
(org-test-with-temp-text "\n\n<point>\n\nParagraph"
|
||||||
|
(org-backward-paragraph)
|
||||||
|
(bobp)))
|
||||||
;; Regular test.
|
;; Regular test.
|
||||||
(should
|
(should
|
||||||
|
(= 2
|
||||||
|
(org-test-with-temp-text "P1\n\nP2<point>"
|
||||||
|
(org-backward-paragraph)
|
||||||
|
(org-current-line))))
|
||||||
|
(should
|
||||||
|
(= 4
|
||||||
(org-test-with-temp-text "P1\n\nP2\n\nP3<point>"
|
(org-test-with-temp-text "P1\n\nP2\n\nP3<point>"
|
||||||
(org-backward-paragraph)
|
(org-backward-paragraph)
|
||||||
(looking-at "P3")))
|
(org-current-line))))
|
||||||
|
;; Try to move on the line above current element.
|
||||||
(should
|
(should
|
||||||
(org-test-with-temp-text "P1\n\nP2\n\n<point>P3"
|
(= 2
|
||||||
|
(org-test-with-temp-text "\n\n<point>Paragraph"
|
||||||
(org-backward-paragraph)
|
(org-backward-paragraph)
|
||||||
(looking-at-p "P2")))
|
(org-current-line))))
|
||||||
;; Ignore depth.
|
;; Do not leave point in an invisible area.
|
||||||
(should
|
(should
|
||||||
(org-test-with-temp-text "P1\n\n#+BEGIN_CENTER\nP2\n#+END_CENTER\n<point>P3"
|
(org-test-with-temp-text "* H1\n P1\n\n* H2"
|
||||||
(org-backward-paragraph)
|
|
||||||
(looking-at-p "P2")))
|
|
||||||
;; Ignore invisible elements.
|
|
||||||
(should
|
|
||||||
(org-test-with-temp-text "* H1\n P1\n* H2"
|
|
||||||
(org-cycle)
|
(org-cycle)
|
||||||
(goto-char (point-max))
|
(goto-char (point-max))
|
||||||
(beginning-of-line)
|
(beginning-of-line)
|
||||||
(org-backward-paragraph)
|
(org-backward-paragraph)
|
||||||
(bobp)))
|
(bobp)))
|
||||||
;; On an affiliated keyword, jump to the first one.
|
|
||||||
(should
|
(should
|
||||||
(org-test-with-temp-text
|
(org-test-with-temp-text "#+begin_center\nP1\n\nP2\n#+end_center\n"
|
||||||
"P1\n#+name: n\n#+caption: c1\n#+caption: <point>c2\nP2"
|
(org-hide-block-toggle)
|
||||||
|
(goto-char (point-max))
|
||||||
(org-backward-paragraph)
|
(org-backward-paragraph)
|
||||||
(looking-at-p "#\\+name")))
|
(bobp)))
|
||||||
|
;; On the first element in an item or a footnote definition, jump
|
||||||
|
;; before the footnote or the item.
|
||||||
|
(should
|
||||||
|
(org-test-with-temp-text "- line1<point>"
|
||||||
|
(org-backward-paragraph)
|
||||||
|
(bobp)))
|
||||||
|
(should
|
||||||
|
(org-test-with-temp-text "[fn:1] line1n<point>"
|
||||||
|
(org-backward-paragraph)
|
||||||
|
(bobp)))
|
||||||
;; On the second element in an item or a footnote definition, jump
|
;; On the second element in an item or a footnote definition, jump
|
||||||
;; to item or the definition.
|
;; to item or the definition.
|
||||||
(should
|
(should
|
||||||
|
(= 2
|
||||||
(org-test-with-temp-text "- line1\n\n<point> line2"
|
(org-test-with-temp-text "- line1\n\n<point> line2"
|
||||||
(org-backward-paragraph)
|
(org-backward-paragraph)
|
||||||
(looking-at-p "- line1")))
|
(org-current-line))))
|
||||||
(should
|
(should
|
||||||
|
(= 2
|
||||||
(org-test-with-temp-text "[fn:1] line1\n\n<point> line2"
|
(org-test-with-temp-text "[fn:1] line1\n\n<point> line2"
|
||||||
(org-backward-paragraph)
|
(org-backward-paragraph)
|
||||||
(looking-at-p "\\[fn:1\\] line1")))
|
(org-current-line))))
|
||||||
;; On a table (resp. a property drawer), ignore table rows
|
;; On a table (resp. a property drawer), ignore table rows
|
||||||
;; (resp. node properties).
|
;; (resp. node properties).
|
||||||
(should
|
(should
|
||||||
|
@ -3812,38 +3878,75 @@ SCHEDULED: <2017-05-06 Sat>
|
||||||
(org-backward-paragraph)
|
(org-backward-paragraph)
|
||||||
(bobp)))
|
(bobp)))
|
||||||
(should
|
(should
|
||||||
(org-test-with-temp-text "* H\n:PROPERTIES:\n:prop: value\n:END:\n<point>P1"
|
(= 2
|
||||||
|
(org-test-with-temp-text
|
||||||
|
"* H\n:PROPERTIES:\n:prop: value\n:END:\n<point>P1"
|
||||||
(org-backward-paragraph)
|
(org-backward-paragraph)
|
||||||
(looking-at-p ":PROPERTIES:")))
|
(org-current-line))))
|
||||||
;; On a comment, example, src and verse blocks, stop before blank
|
;; In a plain list with one item every line, skip the whole list,
|
||||||
|
;; even with point in the middle of the list.
|
||||||
|
(should
|
||||||
|
(org-test-with-temp-text "- A\n - B\n- C\n<point>"
|
||||||
|
(org-backward-paragraph)
|
||||||
|
(bobp)))
|
||||||
|
(should
|
||||||
|
(org-test-with-temp-text "- A\n - B\n- <point>C\n"
|
||||||
|
(org-backward-paragraph)
|
||||||
|
(bobp)))
|
||||||
|
;; Skip consecutive keywords, clocks and diary S-exps.
|
||||||
|
(should
|
||||||
|
(org-test-with-temp-text "#+key: val\n #+key2: val\n#+key3: val\n<point>"
|
||||||
|
(org-backward-paragraph)
|
||||||
|
(bobp)))
|
||||||
|
(should
|
||||||
|
(org-test-with-temp-text "CLOCK: val\n CLOCK: val\nCLOCK: val\n<point>"
|
||||||
|
(org-backward-paragraph)
|
||||||
|
(bobp)))
|
||||||
|
(should
|
||||||
|
(org-test-with-temp-text "%%(foo)\n%%(bar)\n%%(baz)\n<point>"
|
||||||
|
(org-backward-paragraph)
|
||||||
|
(bobp)))
|
||||||
|
(should-not
|
||||||
|
(org-test-with-temp-text "#+key: val\n #+key2: val\n\n#+key3: val\n<point>"
|
||||||
|
(org-backward-paragraph)
|
||||||
|
(bobp)))
|
||||||
|
(should-not
|
||||||
|
(org-test-with-temp-text "#+key: val\nCLOCK: ...\n<point>"
|
||||||
|
(org-backward-paragraph)
|
||||||
|
(bobp)))
|
||||||
|
;; On a comment, example, source and verse blocks, stop at blank
|
||||||
;; lines.
|
;; lines.
|
||||||
(should
|
(should
|
||||||
(org-test-with-temp-text "#+BEGIN_VERSE\nL1\n\nL2\n\n<point>L3\n#+END_VERSE"
|
(= 1
|
||||||
|
(org-test-with-temp-text
|
||||||
|
"#+begin_comment\n<point>L1\n\nL2\n\nL3\n#+end_comment"
|
||||||
(org-backward-paragraph)
|
(org-backward-paragraph)
|
||||||
(looking-at-p "L2")))
|
(org-current-line))))
|
||||||
(should
|
(should
|
||||||
(org-test-with-temp-text "#+BEGIN_SRC\nL1\n\nL2\n\n<point>L3#+END_SRC"
|
(= 2
|
||||||
|
(org-test-with-temp-text
|
||||||
|
"#+begin_verse\nL1\n\n<point>L2\n\nL3\n#+end_verse"
|
||||||
(org-backward-paragraph)
|
(org-backward-paragraph)
|
||||||
(looking-at-p "L2")))
|
(org-current-line))))
|
||||||
;; In comment, example, export, src and verse blocks, stop below
|
|
||||||
;; opening line when called from within the block.
|
|
||||||
(should
|
(should
|
||||||
(org-test-with-temp-text "#+BEGIN_VERSE\nL1\nL2<point>\n#+END_VERSE"
|
(= 3
|
||||||
|
(org-test-with-temp-text
|
||||||
|
"#+begin_src emacs-lisp\nL1\n\nL2\n\n<point>L3\n#+end_src"
|
||||||
(org-backward-paragraph)
|
(org-backward-paragraph)
|
||||||
(looking-at-p "L1")))
|
(org-current-line))))
|
||||||
(should
|
|
||||||
(org-test-with-temp-text "#+BEGIN_EXAMPLE\nL1\nL2<point>\n#+END_EXAMPLE"
|
|
||||||
(org-backward-paragraph)
|
|
||||||
(looking-at-p "L1")))
|
|
||||||
;; When called from the opening line itself, however, move to
|
;; When called from the opening line itself, however, move to
|
||||||
;; beginning of block.
|
;; beginning of block.
|
||||||
(should
|
(should
|
||||||
(org-test-with-temp-text "#+BEGIN_<point>EXAMPLE\nL1\n#+END_EXAMPLE"
|
(org-test-with-temp-text "#+begin_<point>example\nL1\n#+end_example"
|
||||||
(org-backward-paragraph)
|
(org-backward-paragraph)
|
||||||
(bobp)))
|
(bobp)))
|
||||||
;; Pathological case: on an empty heading, move to its beginning.
|
;; On an empty heading, move above it.
|
||||||
(should
|
(should
|
||||||
(org-test-with-temp-text "* <point>H"
|
(org-test-with-temp-text "\n* <point>"
|
||||||
|
(org-backward-paragraph)
|
||||||
|
(bobp)))
|
||||||
|
(should
|
||||||
|
(org-test-with-temp-text "\n* \n<point>"
|
||||||
(org-backward-paragraph)
|
(org-backward-paragraph)
|
||||||
(bobp))))
|
(bobp))))
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue