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~.
|
||||
|
||||
** 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
|
||||
The caller is now responsible for the check. It can use, e.g.,
|
||||
~org-at-table-p~.
|
||||
|
|
434
lisp/org.el
434
lisp/org.el
|
@ -20512,156 +20512,300 @@ With ARG, repeats or can move forward if negative."
|
|||
(interactive "p")
|
||||
(org-next-visible-heading (- arg)))
|
||||
|
||||
(defun org-forward-paragraph ()
|
||||
"Move forward to beginning of next paragraph or equivalent.
|
||||
(defun org-forward-paragraph (&optional arg)
|
||||
"Move forward by a paragraph, or equivalent, unit.
|
||||
|
||||
The function moves point to the beginning of the next visible
|
||||
structural element, which can be a paragraph, a table, a list
|
||||
item, etc. It also provides some special moves for convenience:
|
||||
With argument ARG, do it ARG times;
|
||||
a negative argument ARG = -N means move backward N paragraphs.
|
||||
|
||||
- On an affiliated keyword, jump to the beginning of the
|
||||
relative element.
|
||||
- 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."
|
||||
The function moves point between two structural
|
||||
elements (paragraphs, tables, lists, etc.).
|
||||
|
||||
It also provides the following special moves for convenience:
|
||||
|
||||
- on a table or a property drawer, move to its beginning;
|
||||
- on comment, example, export, source and verse blocks, stop
|
||||
at blank lines;
|
||||
- skip consecutive clocks, diary S-exps, and keywords."
|
||||
(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))
|
||||
|
||||
(defun org-backward-paragraph (&optional arg)
|
||||
"Move backward by a paragraph, or equivalent, unit.
|
||||
|
||||
With argument ARG, do it ARG times;
|
||||
a negative argument ARG = -N means move forward N paragraphs.
|
||||
|
||||
The function moves point between two structural
|
||||
elements (paragraphs, tables, lists, etc.).
|
||||
|
||||
It also provides the following special moves for convenience:
|
||||
|
||||
- on a table or a property drawer, move to its beginning;
|
||||
- on comment, example, export, source and verse blocks, stop
|
||||
at blank lines;
|
||||
- skip consecutive clocks, diary S-exps, and keywords."
|
||||
(interactive "^p")
|
||||
(unless arg (setq arg 1))
|
||||
(if (< arg 0) (org-forward-paragraph (- arg))
|
||||
(while (and (> arg 0) (not (bobp)))
|
||||
(org--backward-paragraph-once)
|
||||
(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
|
||||
((memq type '(table property-drawer))
|
||||
(list (org-element-property :begin e)
|
||||
(org-element-property :end e)
|
||||
(org-element-property :parent e)))
|
||||
((memq type '(node-property table-row))
|
||||
(let ((e (org-element-property :parent e)))
|
||||
(list (org-element-property :begin e)
|
||||
(org-element-property :end e)
|
||||
(org-element-property :parent e))))
|
||||
((memq type '(clock diary-sexp keyword))
|
||||
(let* ((regexp (pcase type
|
||||
(`clock org-clock-line-re)
|
||||
(`diary-sexp "%%(")
|
||||
(_ org-keyword-regexp)))
|
||||
(end (if (< 0 (org-element-property :post-blank e))
|
||||
(org-element-property :end e)
|
||||
(org-with-wide-buffer
|
||||
(forward-line)
|
||||
(while (looking-at regexp) (forward-line))
|
||||
(skip-chars-forward " \t\n")
|
||||
(line-beginning-position))))
|
||||
(begin (org-with-point-at (org-element-property :begin e)
|
||||
(while (and (not (bobp)) (looking-at regexp))
|
||||
(forward-line -1))
|
||||
;; We may have gotten one line too far.
|
||||
(if (looking-at regexp)
|
||||
(point)
|
||||
(line-beginning-position 2)))))
|
||||
(list begin end (org-element-property :parent e))))
|
||||
;; Find the full plain list containing point, the check it
|
||||
;; contains exactly one line per item.
|
||||
((let ((l (org-element-lineage e '(plain-list) t)))
|
||||
(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)
|
||||
(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))))))
|
||||
(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 ()
|
||||
"Move backward to start of previous paragraph or equivalent.
|
||||
|
||||
The function moves point to the beginning of the current
|
||||
structural element, which can be a paragraph, a table, a list
|
||||
item, etc., or to the beginning of the previous visible one if
|
||||
point is already there. It also provides some special moves for
|
||||
convenience:
|
||||
|
||||
- On an affiliated keyword, jump to the first one.
|
||||
- On a table or a property drawer, move to its beginning.
|
||||
- On comment, example, export, src and verse blocks, stop
|
||||
before blank lines."
|
||||
(defun org--backward-paragraph-once ()
|
||||
"Move backward to start of paragraph or equivalent, once.
|
||||
See `org-backward-paragraph'."
|
||||
(interactive)
|
||||
(unless (bobp)
|
||||
(let* ((deactivate-mark nil)
|
||||
(element (org-element-at-point))
|
||||
(type (org-element-type element))
|
||||
(contents-end (org-element-property :contents-end element))
|
||||
(post-affiliated (org-element-property :post-affiliated element))
|
||||
(begin (org-element-property :begin element))
|
||||
(special? ;blocks handled specially
|
||||
(memq type '(comment-block example-block export-block src-block
|
||||
verse-block)))
|
||||
(contents-begin
|
||||
(if special?
|
||||
;; These types have no proper contents. Fake line
|
||||
;; below the block opening line as contents beginning.
|
||||
(save-excursion (goto-char begin) (line-beginning-position 2))
|
||||
(org-element-property :contents-begin element))))
|
||||
(cond
|
||||
((not element) (goto-char (point-min)))
|
||||
((= (point) begin)
|
||||
(backward-char)
|
||||
(org-backward-paragraph))
|
||||
((<= (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))
|
||||
(goto-char (org-element-property
|
||||
:post-affiliated (org-element-property :parent element))))
|
||||
(special?
|
||||
(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))))))
|
||||
((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.
|
||||
((and contents-end (>= (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)))))
|
||||
(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 ()
|
||||
"Move forward by one element.
|
||||
|
|
|
@ -3700,45 +3700,46 @@ SCHEDULED: <2017-05-06 Sat>
|
|||
t))
|
||||
;; Standard test.
|
||||
(should
|
||||
(org-test-with-temp-text "P1\n\nP2\n\nP3"
|
||||
(org-forward-paragraph)
|
||||
(looking-at "P2")))
|
||||
;; Ignore depth.
|
||||
(= 2
|
||||
(org-test-with-temp-text "P1\n\nP2"
|
||||
(org-forward-paragraph)
|
||||
(org-current-line))))
|
||||
(should
|
||||
(org-test-with-temp-text "#+BEGIN_CENTER\nP1\n#+END_CENTER\nP2"
|
||||
(org-forward-paragraph)
|
||||
(looking-at "P1")))
|
||||
(= 2
|
||||
(org-test-with-temp-text "P1\n\nP2\n\nP3"
|
||||
(org-forward-paragraph)
|
||||
(org-current-line))))
|
||||
;; Enter greater elements.
|
||||
(should
|
||||
(= 2
|
||||
(org-test-with-temp-text "#+begin_center\nP1\n#+end_center\nP2"
|
||||
(org-forward-paragraph)
|
||||
(org-current-line))))
|
||||
;; Do not enter elements with invisible contents.
|
||||
(should
|
||||
(org-test-with-temp-text "#+BEGIN_CENTER\nP1\n\nP2\n#+END_CENTER\nP3"
|
||||
(org-hide-block-toggle)
|
||||
(org-forward-paragraph)
|
||||
(looking-at "P3")))
|
||||
;; On an affiliated keyword, jump to the beginning of the element.
|
||||
(= 4
|
||||
(org-test-with-temp-text "* H1\n P1\n\n* H2"
|
||||
(org-cycle)
|
||||
(org-forward-paragraph)
|
||||
(org-current-line))))
|
||||
(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
|
||||
(= 6
|
||||
(org-test-with-temp-text "#+begin_center\nP1\n\nP2\n#+end_center\nP3"
|
||||
(org-hide-block-toggle)
|
||||
(org-forward-paragraph)
|
||||
(org-current-line))))
|
||||
;; On an item or a footnote definition, move past the first element
|
||||
;; inside, if any.
|
||||
(should
|
||||
(org-test-with-temp-text "- Item1\n\n Paragraph\n- Item2"
|
||||
(org-forward-paragraph)
|
||||
(looking-at " Paragraph")))
|
||||
(= 2
|
||||
(org-test-with-temp-text "- Item1\n\n Paragraph\n- Item2"
|
||||
(org-forward-paragraph)
|
||||
(org-current-line))))
|
||||
(should
|
||||
(org-test-with-temp-text "[fn:1] Def1\n\nParagraph\n\n[fn:2] Def2"
|
||||
(org-forward-paragraph)
|
||||
(looking-at "Paragraph")))
|
||||
;; 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")))
|
||||
(= 2
|
||||
(org-test-with-temp-text "[fn:1] Def1\n\nParagraph\n\n[fn:2] Def2"
|
||||
(org-forward-paragraph)
|
||||
(org-current-line))))
|
||||
;; On a table (resp. a property drawer) do not move through table
|
||||
;; rows (resp. node properties).
|
||||
(should
|
||||
|
@ -3750,15 +3751,59 @@ SCHEDULED: <2017-05-06 Sat>
|
|||
"* H\n<point>:PROPERTIES:\n:prop: value\n:END:\nParagraph"
|
||||
(org-forward-paragraph)
|
||||
(looking-at "Paragraph")))
|
||||
;; On a verse or source block, stop after blank lines.
|
||||
;; Skip consecutive keywords, clocks and diary S-exps.
|
||||
(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)
|
||||
(looking-at "L2")))
|
||||
(eobp)))
|
||||
(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)
|
||||
(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 ()
|
||||
"Test `org-backward-paragraph' specifications."
|
||||
|
@ -3767,44 +3812,65 @@ SCHEDULED: <2017-05-06 Sat>
|
|||
(org-test-with-temp-text "Paragraph"
|
||||
(org-backward-paragraph)
|
||||
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.
|
||||
(should
|
||||
(org-test-with-temp-text "P1\n\nP2\n\nP3<point>"
|
||||
(org-backward-paragraph)
|
||||
(looking-at "P3")))
|
||||
(= 2
|
||||
(org-test-with-temp-text "P1\n\nP2<point>"
|
||||
(org-backward-paragraph)
|
||||
(org-current-line))))
|
||||
(should
|
||||
(org-test-with-temp-text "P1\n\nP2\n\n<point>P3"
|
||||
(org-backward-paragraph)
|
||||
(looking-at-p "P2")))
|
||||
;; Ignore depth.
|
||||
(= 4
|
||||
(org-test-with-temp-text "P1\n\nP2\n\nP3<point>"
|
||||
(org-backward-paragraph)
|
||||
(org-current-line))))
|
||||
;; Try to move on the line above current element.
|
||||
(should
|
||||
(org-test-with-temp-text "P1\n\n#+BEGIN_CENTER\nP2\n#+END_CENTER\n<point>P3"
|
||||
(org-backward-paragraph)
|
||||
(looking-at-p "P2")))
|
||||
;; Ignore invisible elements.
|
||||
(= 2
|
||||
(org-test-with-temp-text "\n\n<point>Paragraph"
|
||||
(org-backward-paragraph)
|
||||
(org-current-line))))
|
||||
;; Do not leave point in an invisible area.
|
||||
(should
|
||||
(org-test-with-temp-text "* H1\n P1\n* H2"
|
||||
(org-test-with-temp-text "* H1\n P1\n\n* H2"
|
||||
(org-cycle)
|
||||
(goto-char (point-max))
|
||||
(beginning-of-line)
|
||||
(org-backward-paragraph)
|
||||
(bobp)))
|
||||
;; On an affiliated keyword, jump to the first one.
|
||||
(should
|
||||
(org-test-with-temp-text
|
||||
"P1\n#+name: n\n#+caption: c1\n#+caption: <point>c2\nP2"
|
||||
(org-test-with-temp-text "#+begin_center\nP1\n\nP2\n#+end_center\n"
|
||||
(org-hide-block-toggle)
|
||||
(goto-char (point-max))
|
||||
(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
|
||||
;; to item or the definition.
|
||||
(should
|
||||
(org-test-with-temp-text "- line1\n\n<point> line2"
|
||||
(org-backward-paragraph)
|
||||
(looking-at-p "- line1")))
|
||||
(= 2
|
||||
(org-test-with-temp-text "- line1\n\n<point> line2"
|
||||
(org-backward-paragraph)
|
||||
(org-current-line))))
|
||||
(should
|
||||
(org-test-with-temp-text "[fn:1] line1\n\n<point> line2"
|
||||
(org-backward-paragraph)
|
||||
(looking-at-p "\\[fn:1\\] line1")))
|
||||
(= 2
|
||||
(org-test-with-temp-text "[fn:1] line1\n\n<point> line2"
|
||||
(org-backward-paragraph)
|
||||
(org-current-line))))
|
||||
;; On a table (resp. a property drawer), ignore table rows
|
||||
;; (resp. node properties).
|
||||
(should
|
||||
|
@ -3812,38 +3878,75 @@ SCHEDULED: <2017-05-06 Sat>
|
|||
(org-backward-paragraph)
|
||||
(bobp)))
|
||||
(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-current-line))))
|
||||
;; 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)
|
||||
(looking-at-p ":PROPERTIES:")))
|
||||
;; On a comment, example, src and verse blocks, stop before blank
|
||||
(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.
|
||||
(should
|
||||
(org-test-with-temp-text "#+BEGIN_VERSE\nL1\n\nL2\n\n<point>L3\n#+END_VERSE"
|
||||
(org-backward-paragraph)
|
||||
(looking-at-p "L2")))
|
||||
(= 1
|
||||
(org-test-with-temp-text
|
||||
"#+begin_comment\n<point>L1\n\nL2\n\nL3\n#+end_comment"
|
||||
(org-backward-paragraph)
|
||||
(org-current-line))))
|
||||
(should
|
||||
(org-test-with-temp-text "#+BEGIN_SRC\nL1\n\nL2\n\n<point>L3#+END_SRC"
|
||||
(org-backward-paragraph)
|
||||
(looking-at-p "L2")))
|
||||
;; In comment, example, export, src and verse blocks, stop below
|
||||
;; opening line when called from within the block.
|
||||
(= 2
|
||||
(org-test-with-temp-text
|
||||
"#+begin_verse\nL1\n\n<point>L2\n\nL3\n#+end_verse"
|
||||
(org-backward-paragraph)
|
||||
(org-current-line))))
|
||||
(should
|
||||
(org-test-with-temp-text "#+BEGIN_VERSE\nL1\nL2<point>\n#+END_VERSE"
|
||||
(org-backward-paragraph)
|
||||
(looking-at-p "L1")))
|
||||
(should
|
||||
(org-test-with-temp-text "#+BEGIN_EXAMPLE\nL1\nL2<point>\n#+END_EXAMPLE"
|
||||
(org-backward-paragraph)
|
||||
(looking-at-p "L1")))
|
||||
(= 3
|
||||
(org-test-with-temp-text
|
||||
"#+begin_src emacs-lisp\nL1\n\nL2\n\n<point>L3\n#+end_src"
|
||||
(org-backward-paragraph)
|
||||
(org-current-line))))
|
||||
;; When called from the opening line itself, however, move to
|
||||
;; beginning of block.
|
||||
(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)
|
||||
(bobp)))
|
||||
;; Pathological case: on an empty heading, move to its beginning.
|
||||
;; On an empty heading, move above it.
|
||||
(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)
|
||||
(bobp))))
|
||||
|
||||
|
|
Loading…
Reference in New Issue