Prechádzať zdrojové kódy

Fix `org-next-block'

* lisp/org.el (org-next-block): Use Element API.

* testing/lisp/test-org.el (test-org/next-block):
(test-org/previous-block): New tests.
Nicolas Goaziou 10 rokov pred
rodič
commit
0b7721322a
2 zmenil súbory, kde vykonal 120 pridanie a 11 odobranie
  1. 34 11
      lisp/org.el
  2. 86 0
      testing/lisp/test-org.el

+ 34 - 11
lisp/org.el

@@ -24344,19 +24344,42 @@ respect customization of `org-odd-levels-only'."
 
 (defun org-next-block (arg &optional backward block-regexp)
   "Jump to the next block.
-With a prefix argument ARG, jump forward ARG many source blocks.
+
+With a prefix argument ARG, jump forward ARG many blocks.
+
 When BACKWARD is non-nil, jump to the previous block.
-When BLOCK-REGEXP is non-nil, use this regexp to find blocks."
+
+When BLOCK-REGEXP is non-nil, use this regexp to find blocks.
+Match data is set according to this regexp when the function
+returns.
+
+Return point at beginning of the opening line of found block.
+Throw an error if no block is found."
   (interactive "p")
-  (let ((re (or block-regexp org-block-regexp))
-	(re-search-fn (or (and backward 're-search-backward)
-			  're-search-forward)))
-    (if (looking-at re) (forward-char 1))
-    (condition-case nil
-	(funcall re-search-fn re nil nil arg)
-      (error (user-error "No %s code blocks"
-			 (if backward "previous" "further" ))))
-    (goto-char (match-beginning 0)) (org-show-context)))
+  (let ((re (or block-regexp "^[ \t]*#\\+BEGIN"))
+	(case-fold-search t)
+	(search-fn (if backward #'re-search-backward #'re-search-forward))
+	(count (or arg 1))
+	(origin (point))
+	last-element)
+    (if backward (beginning-of-line) (end-of-line))
+    (while (and (> count 0) (funcall search-fn re nil t))
+      (let ((element (save-excursion
+		       (goto-char (match-beginning 0))
+		       (save-match-data (org-element-at-point)))))
+	(when (and (memq (org-element-type element)
+			 '(center-block comment-block dynamic-block
+					example-block export-block quote-block
+					special-block src-block verse-block))
+		   (<= (match-beginning 0)
+		       (org-element-property :post-affiliated element)))
+	  (setq last-element element)
+	  (decf count))))
+    (if (= count 0)
+	(prog1 (goto-char (org-element-property :post-affiliated last-element))
+	  (org-show-context))
+      (goto-char origin)
+      (user-error "No %s code blocks" (if backward "previous" "further")))))
 
 (defun org-previous-block (arg &optional block-regexp)
   "Jump to the previous block.

+ 86 - 0
testing/lisp/test-org.el

@@ -2309,6 +2309,92 @@ Text.
       (mapcar (lambda (ov) (cons (overlay-start ov) (overlay-end ov)))
 	      (overlays-in (point-min) (point-max)))))))
 
+(ert-deftest test-org/next-block ()
+  "Test `org-next-block' specifications."
+  ;; Regular test.
+  (should
+   (org-test-with-temp-text "Paragraph\n#+BEGIN_CENTER\ncontents\n#+END_CENTER"
+     (org-next-block 1)
+     (looking-at "#\\+BEGIN_CENTER")))
+  ;; Ignore case.
+  (should
+   (org-test-with-temp-text "Paragraph\n#+begin_center\ncontents\n#+end_center"
+     (let ((case-fold-search nil))
+       (org-next-block 1)
+       (looking-at "#\\+begin_center"))))
+  ;; Ignore current line.
+  (should
+   (org-test-with-temp-text
+       "#+BEGIN_QUOTE\n#+END_QUOTE\n#+BEGIN_CENTER\n#+END_CENTER"
+     (org-next-block 1)
+     (looking-at "#\\+BEGIN_CENTER")))
+  ;; Throw an error when no block is found.
+  (should-error
+   (org-test-with-temp-text "Paragraph"
+     (org-next-block 1)))
+  ;; With an argument, skip many blocks at once.
+  (should
+   (org-test-with-temp-text
+       "Start\n#+BEGIN_CENTER\nA\n#+END_CENTER\n#+BEGIN_QUOTE\nB\n#+END_QUOTE"
+     (org-next-block 2)
+     (looking-at "#\\+BEGIN_QUOTE")))
+  ;; With optional argument BLOCK-REGEXP, filter matched blocks.
+  (should
+   (org-test-with-temp-text
+       "Start\n#+BEGIN_CENTER\nA\n#+END_CENTER\n#+BEGIN_QUOTE\nB\n#+END_QUOTE"
+     (org-next-block 1 nil "^[ \t]*#\\+BEGIN_QUOTE")
+     (looking-at "#\\+BEGIN_QUOTE")))
+  ;; Optional argument is also case-insensitive.
+  (should
+   (org-test-with-temp-text
+       "Start\n#+BEGIN_CENTER\nA\n#+END_CENTER\n#+begin_quote\nB\n#+end_quote"
+     (let ((case-fold-search nil))
+       (org-next-block 1 nil "^[ \t]*#\\+BEGIN_QUOTE")
+       (looking-at "#\\+begin_quote")))))
+
+(ert-deftest test-org/previous-block ()
+  "Test `org-previous-block' specifications."
+  ;; Regular test.
+  (should
+   (org-test-with-temp-text "#+BEGIN_CENTER\ncontents\n#+END_CENTER\n<point>"
+     (org-previous-block 1)
+     (looking-at "#\\+BEGIN_CENTER")))
+  ;; Ignore case.
+  (should
+   (org-test-with-temp-text "#+begin_center\ncontents\n#+end_center\n<point>"
+     (let ((case-fold-search nil))
+       (org-previous-block 1)
+       (looking-at "#\\+begin_center"))))
+  ;; Ignore current line.
+  (should
+   (org-test-with-temp-text
+       "#+BEGIN_QUOTE\n#+END_QUOTE\n#+BEGIN_CENTER<point>\n#+END_CENTER"
+     (org-previous-block 1)
+     (looking-at "#\\+BEGIN_QUOTE")))
+  ;; Throw an error when no block is found.
+  (should-error
+   (org-test-with-temp-text "Paragraph<point>"
+     (org-previous-block 1)))
+  ;; With an argument, skip many blocks at once.
+  (should
+   (org-test-with-temp-text
+       "#+BEGIN_CENTER\nA\n#+END_CENTER\n#+BEGIN_QUOTE\nB\n#+END_QUOTE\n<point>"
+     (org-previous-block 2)
+     (looking-at "#\\+BEGIN_CENTER")))
+  ;; With optional argument BLOCK-REGEXP, filter matched blocks.
+  (should
+   (org-test-with-temp-text
+       "#+BEGIN_CENTER\nA\n#+END_CENTER\n#+BEGIN_QUOTE\nB\n#+END_QUOTE\n<point>"
+     (org-previous-block 1 "^[ \t]*#\\+BEGIN_QUOTE")
+     (looking-at "#\\+BEGIN_QUOTE")))
+  ;; Optional argument is also case-insensitive.
+  (should
+   (org-test-with-temp-text
+       "#+BEGIN_CENTER\nA\n#+END_CENTER\n#+begin_quote\nB\n#+end_quote\n<point>"
+     (let ((case-fold-search nil))
+       (org-next-block 1 "^[ \t]*#\\+BEGIN_QUOTE")
+       (looking-at "#\\+begin_quote")))))
+
 
 ;;; Outline structure