diff --git a/contrib/lisp/org-element.el b/contrib/lisp/org-element.el index a5a273cc9..a08625069 100644 --- a/contrib/lisp/org-element.el +++ b/contrib/lisp/org-element.el @@ -46,9 +46,8 @@ ;; `comment-block', `example-block', `export-block', `fixed-width', ;; `horizontal-rule', `keyword', `latex-environment', `paragraph', ;; `planning', `property-drawer', `quote-section', `src-block', -;; `table', `table-cell', `table-row' and `verse-block'. Among them, -;; `paragraph', `table-cell' and `verse-block' types can contain Org -;; objects and plain text. +;; `table', `table-row' and `verse-block'. Among them, `paragraph' +;; and `verse-block' types can contain Org objects and plain text. ;; ;; Objects are related to document's contents. Some of them are ;; recursive. Associated types are of the following: `bold', `code', @@ -892,7 +891,8 @@ Return a list whose CAR is `babel-call' and CDR is a plist containing `:begin', `:end', `:info' and `:post-blank' as keywords." (save-excursion - (let ((info (progn (looking-at org-babel-block-lob-one-liner-regexp) + (let ((case-fold-search t) + (info (progn (looking-at org-babel-block-lob-one-liner-regexp) (org-babel-lob-get-info))) (begin (point-at-bol)) (pos-before-blank (progn (forward-line) (point))) @@ -2851,17 +2851,21 @@ regexp matching one object can also match the other object.") table-cell underline) "List of recursive object types.") -(defconst org-element-non-recursive-block-alist +(defconst org-element-block-name-alist '(("ASCII" . export-block) + ("CENTER" . center-block) ("COMMENT" . comment-block) ("DOCBOOK" . export-block) ("EXAMPLE" . example-block) ("HTML" . export-block) ("LATEX" . export-block) ("ODT" . export-block) + ("QUOTE" . quote-block) ("SRC" . src-block) ("VERSE" . verse-block)) - "Alist between non-recursive block name and their element type.") + "Alist between block names and their element type. +Any block whose name has no association in the current list has +a `special-block' type.") (defconst org-element-affiliated-keywords '("ATTR_ASCII" "ATTR_DOCBOOK" "ATTR_HTML" "ATTR_LATEX" "ATTR_ODT" "CAPTION" @@ -3044,9 +3048,8 @@ Optional argument SPECIAL, when non-nil, can be either `section', If STRUCTURE isn't provided but SPECIAL is set to `item', it will be computed. -Unlike to `org-element-at-point', this function assumes point is -always at the beginning of the element it has to parse. As such, -it is quicker than its counterpart, albeit more restrictive." +This function assumes point is always at the beginning of the +element it has to parse." (save-excursion ;; If point is at an affiliated keyword, try moving to the ;; beginning of the associated element. If none is found, the @@ -3061,7 +3064,7 @@ it is quicker than its counterpart, albeit more restrictive." ;; `org-element-secondary-value-alist'. (raw-secondary-p (and granularity (not (eq granularity 'object))))) (cond - ;; Item + ;; Item. ((eq special 'item) (org-element-item-parser (or structure (org-list-struct)) raw-secondary-p)) @@ -3079,67 +3082,49 @@ it is quicker than its counterpart, albeit more restrictive." (if (equal (match-string 1) org-clock-string) (org-element-clock-parser) (org-element-planning-parser))) - ;; Non-recursive block. - ((when (looking-at org-element--element-block-re) - (let ((type (upcase (match-string 1)))) - (if (save-excursion - (re-search-forward - (format "^[ \t]*#\\+END_%s\\(?: \\|$\\)" type) nil t)) - (funcall - (intern - (format - "org-element-%s-parser" - (cdr (assoc type org-element-non-recursive-block-alist))))) - (org-element-paragraph-parser))))) + ;; Blocks. + ((when (looking-at "[ \t]*#\\+BEGIN_\\([-A-Za-z0-9]+\\)\\(?: \\|$\\)") + (let ((name (upcase (match-string 1))) type) + (cond + ((not (save-excursion + (re-search-forward + (format "^[ \t]*#\\+END_%s\\(?: \\|$\\)" name) nil t))) + (org-element-paragraph-parser)) + ((setq type (assoc name org-element-block-name-alist)) + (funcall (intern (format "org-element-%s-parser" (cdr type))))) + (t (org-element-special-block-parser)))))) ;; Inlinetask. ((org-at-heading-p) (org-element-inlinetask-parser raw-secondary-p)) - ;; LaTeX Environment or Paragraph if incomplete. + ;; LaTeX Environment. ((looking-at "[ \t]*\\\\begin{") (if (save-excursion (re-search-forward "[ \t]*\\\\end{[^}]*}[ \t]*" nil t)) (org-element-latex-environment-parser) (org-element-paragraph-parser))) - ;; Property Drawer. - ((looking-at org-property-start-re) - (if (save-excursion (re-search-forward org-property-end-re nil t)) - (org-element-property-drawer-parser) - (org-element-paragraph-parser))) - ;; Recursive Block, or Paragraph if incomplete. - ((looking-at "[ \t]*#\\+BEGIN_\\([-A-Za-z0-9]+\\)\\(?: \\|$\\)") - (let ((type (upcase (match-string 1)))) - (cond - ((not (save-excursion - (re-search-forward - (format "^[ \t]*#\\+END_%s\\(?: \\|$\\)" type) nil t))) - (org-element-paragraph-parser)) - ((string= type "CENTER") (org-element-center-block-parser)) - ((string= type "QUOTE") (org-element-quote-block-parser)) - (t (org-element-special-block-parser))))) - ;; Drawer. + ;; Drawer and Property Drawer. ((looking-at org-drawer-regexp) - (if (save-excursion (re-search-forward "^[ \t]*:END:[ \t]*$" nil t)) - (org-element-drawer-parser) - (org-element-paragraph-parser))) + (let ((name (match-string 1))) + (cond + ((not (save-excursion (re-search-forward "^[ \t]*:END:[ \t]*$" nil t))) + (org-element-paragraph-parser)) + ((equal "PROPERTIES" name) (org-element-property-drawer-parser)) + (t (org-element-drawer-parser))))) + ;; Fixed Width ((looking-at "[ \t]*:\\( \\|$\\)") (org-element-fixed-width-parser)) - ;; Babel Call. - ((looking-at org-babel-block-lob-one-liner-regexp) - (org-element-babel-call-parser)) - ;; Dynamic Block or Paragraph if incomplete. This must be - ;; checked before regular keywords since their regexp matches - ;; dynamic blocks too. - ((looking-at "[ \t]*#\\+BEGIN:\\(?: \\|$\\)") - (if (save-excursion - (re-search-forward "^[ \t]*#\\+END:\\(?: \\|$\\)" nil t)) - (org-element-dynamic-block-parser) - (org-element-paragraph-parser))) - ;; Keyword, or Paragraph if at an orphaned affiliated keyword. + ;; Babel Call, Dynamic Block and Keyword. ((looking-at "[ \t]*#\\+\\([a-z]+\\(:?_[a-z]+\\)*\\):") (let ((key (upcase (match-string 1)))) - (if (or (string= key "TBLFM") - (member key org-element-affiliated-keywords)) - (org-element-paragraph-parser) - (org-element-keyword-parser)))) - ;; Footnote definition. + (cond + ((equal key "CALL") (org-element-babel-call-parser)) + ((and (equal key "BEGIN") + (save-excursion + (re-search-forward "^[ \t]*#\\+END:\\(?: \\|$\\)" nil t))) + (org-element-dynamic-block-parser)) + ((and (not (equal key "TBLFM")) + (not (member key org-element-affiliated-keywords))) + (org-element-keyword-parser)) + (t (org-element-paragraph-parser))))) + ;; Footnote Definition. ((looking-at org-footnote-definition-re) (org-element-footnote-definition-parser)) ;; Comment. @@ -3150,7 +3135,7 @@ it is quicker than its counterpart, albeit more restrictive." (org-element-horizontal-rule-parser)) ;; Table. ((org-at-table-p t) (org-element-table-parser)) - ;; List or Item. + ;; List. ((looking-at (org-item-re)) (org-element-plain-list-parser (or structure (org-list-struct)))) ;; Default element: Paragraph. diff --git a/testing/lisp/test-org-element.el b/testing/lisp/test-org-element.el index 6eafb06cf..ab2b446f0 100644 --- a/testing/lisp/test-org-element.el +++ b/testing/lisp/test-org-element.el @@ -36,10 +36,118 @@ Return interpreted string." ;;; Test Parsers -;;;; Comments +;;;; Babel Call + +(ert-deftest test-org-element/babel-call-parser () + "Test `babel-call' parsing." + (should + (equal + (org-test-with-temp-text "#+CALL: test()" + (org-element-map (org-element-parse-buffer) 'babel-call 'identity nil t)) + '(babel-call (:begin 1 :end 15 :info ("test()" nil 0) :post-blank 0))))) + + +;;;; Bold + +(ert-deftest test-org-element/bold-parser () + "Test `bold' parser." + ;; Regular test. + (should + (equal + (org-test-with-temp-text "*bold*" + (org-element-map (org-element-parse-buffer) 'bold 'identity nil t)) + '(bold (:begin 1 :end 7 :contents-begin 2 :contents-end 6 :post-blank 0) + "bold"))) + ;; Multi-line markup. + (should + (equal + (org-test-with-temp-text "*first line\nsecond line*" + (org-element-map (org-element-parse-buffer) 'bold 'identity nil t)) + '(bold (:begin 1 :end 25 :contents-begin 2 :contents-end 24 :post-blank 0) + "first line\nsecond line")))) + + +;;;; Center Block + +(ert-deftest test-org-element/center-block-parser () + "Test `center-block' parser." + ;; Regular test. + (should + (equal + (org-test-with-temp-text "#+BEGIN_CENTER\nText\n#+END_CENTER" + (org-element-map + (org-element-parse-buffer) 'center-block 'identity nil t)) + '(center-block + (:begin 1 :end 33 :hiddenp nil :contents-begin 16 :contents-end 21 + :post-blank 0) + (paragraph + (:begin 16 :end 21 :contents-begin 16 :contents-end 20 :post-blank 0) + "Text")))) + ;; Test folded block. + (org-test-with-temp-text "#+BEGIN_CENTER\nText\n#+END_CENTER" + (org-cycle) + (should + (org-element-property + :hiddenp + (org-element-map + (org-element-parse-buffer) 'center-block 'identity nil t)))) + ;; Ignore incomplete block. + (should-not + (org-test-with-temp-text "#+BEGIN_CENTER" + (org-element-map + (org-element-parse-buffer) 'center-block 'identity nil t)))) + + +;;;; Clock + +(ert-deftest test-org-element/clock-parser () + "Test `clock' parser." + ;; Running clock. + (should + (equal + (let ((org-clock-string "CLOCK:")) + (org-test-with-temp-text "CLOCK: [2012-01-01 sun. 00:01]" + (org-element-map + (org-element-parse-buffer) 'clock 'identity nil t))) + '(clock + (:status running :value "[2012-01-01 sun. 00:01]" :time nil :begin 1 + :end 31 :post-blank 0)))) + ;; Closed clock. + (should + (equal + (let ((org-clock-string "CLOCK:")) + (org-test-with-temp-text " +CLOCK: [2012-01-01 sun. 00:01]--[2012-01-01 sun. 00:02] => 0:01" + (org-element-map + (org-element-parse-buffer) 'clock 'identity nil t))) + '(clock + (:status closed + :value "[2012-01-01 sun. 00:01]--[2012-01-01 sun. 00:02]" + :time "0:01" :begin 2 :end 66 :post-blank 0))))) + + +;;;; Code + +(ert-deftest test-org-element/code-parser () + "Test `code' parser." + ;; Regular test. + (should + (equal + (org-test-with-temp-text "~code~" + (org-element-map (org-element-parse-buffer) 'code 'identity nil t)) + '(code (:value "code" :begin 1 :end 7 :post-blank 0)))) + ;; Multi-line markup. + (should + (equal + (org-test-with-temp-text "~first line\nsecond line~" + (org-element-map (org-element-parse-buffer) 'code 'identity nil t)) + '(code (:value "first line\nsecond line" :begin 1 :end 25 :post-blank 0))))) + + +;;;; Comment (ert-deftest test-org-element/comment-parser () - "Test `comment' parsing." + "Test `comment' parser." ;; Regular comment. (should (equal @@ -64,10 +172,159 @@ Return interpreted string." (org-test-with-temp-text "#+ First part\n#+ \n#+\n#+ Second part" (org-element-map (org-element-parse-buffer) 'comment 'identity nil t)) '(comment - (:begin 1 :end 36 :value "First part\n\n\nSecond part\n" :post-blank 0))))) + (:begin 1 :end 36 :value "First part\n\n\nSecond part\n" + :post-blank 0))))) -;;;; Example-blocks and Src-blocks +;;;; Comment Block + +(ert-deftest test-org-element/comment-block-parser () + "Test `comment-block' parser." + ;; Regular tests. + (should + (equal + (org-test-with-temp-text "#+BEGIN_COMMENT\nText\n#+END_COMMENT" + (org-element-map + (org-element-parse-buffer) 'comment-block 'identity nil t)) + '(comment-block (:begin 1 :end 35 :value "Text\n" :hiddenp nil + :post-blank 0)))) + ;; Test folded block. + (org-test-with-temp-text "#+BEGIN_COMMENT\nText\n#+END_COMMENT" + (org-cycle) + (should + (org-element-property + :hiddenp + (org-element-map + (org-element-parse-buffer) 'comment-block 'identity nil t)))) + ;; Ignore incomplete block. + (should-not + (org-test-with-temp-text "#+BEGIN_COMMENT" + (org-element-map + (org-element-parse-buffer) 'comment-block 'identity nil t)))) + + +;;;; Drawer + +(ert-deftest test-org-element/drawer-parser () + "Test `drawer' parser." + ;; Regular test. + (should + (equal + (let ((org-drawers '("TEST"))) + (org-test-with-temp-text ":TEST:\nText\n:END:" + (org-element-map (org-element-parse-buffer) 'drawer 'identity nil t))) + '(drawer + (:begin 1 :end 18 :drawer-name "TEST" :hiddenp nil :contents-begin 8 + :contents-end 13 :post-blank 0) + (paragraph + (:begin 8 :end 13 :contents-begin 8 :contents-end 12 :post-blank 0) + "Text")))) + ;; Do not mix regular drawers and property drawers. + (should-not + (let ((org-drawers '("PROPERTIES"))) + (org-test-with-temp-text ":PROPERTIES:\n:prop: value\n:END:" + (org-element-map + (org-element-parse-buffer) 'drawer 'identity nil t)))) + ;; Ignore incomplete drawer. + (should-not + (let ((org-drawers '("TEST"))) + (org-test-with-temp-text ":TEST:" + (org-element-map + (org-element-parse-buffer) 'drawer 'identity nil t))))) + + +;;;; Dynamic Block + +(ert-deftest test-org-element/dynamic-block-parser () + "Test `dynamic-block' parser." + ;; Regular test. + (should + (equal + (org-test-with-temp-text + "#+BEGIN: myblock :param1 val1 :param2 val2\nText\n#+END:" + (org-element-map + (org-element-parse-buffer) 'dynamic-block 'identity nil t)) + '(dynamic-block + (:begin 1 :end 55 :block-name "myblock" + :arguments ":param1 val1 :param2 val2" :hiddenp nil + :contents-begin 44 :contents-end 49 :post-blank 0) + (paragraph + (:begin 44 :end 49 :contents-begin 44 :contents-end 48 :post-blank 0) + "Text")))) + ;; Folded view + (org-test-with-temp-text + "#+BEGIN: myblock :param1 val1 :param2 val2\nText\n#+END:" + (org-cycle) + (should + (org-element-property + :hiddenp + (org-element-map + (org-element-parse-buffer) 'dynamic-block 'identity nil t)))) + ;; Ignore incomplete block. + (should-not + (org-test-with-temp-text "#+BEGIN: myblock :param1 val1 :param2 val2" + (org-element-map + (org-element-parse-buffer) 'dynamic-block 'identity nil t)))) + + +;;;; Entity + +(ert-deftest test-org-element/entity-parser () + "Test `entity' parser." + ;; Without brackets. + (should + (equal + (org-test-with-temp-text "\\sin" + (org-element-map (org-element-parse-buffer) 'entity 'identity nil t)) + '(entity + (:name "sin" :latex "\\sin" :latex-math-p t :html "sin" + :ascii "sin" :latin1 "sin" :utf-8 "sin" :begin 1 :end 5 + :use-brackets-p nil :post-blank 0)))) + ;; With brackets. + (should + (org-element-property + :use-brackets-p + (org-test-with-temp-text "\\alpha{}text" + (org-element-map (org-element-parse-buffer) 'entity 'identity nil t)))) + ;; User-defined entity. + (should + (equal + (org-element-property + :name + (let ((org-entities-user + '(("test" "test" nil "test" "test" "test" "test")))) + (org-test-with-temp-text "\\test" + (org-element-map (org-element-parse-buffer) 'entity 'identity nil t)))) + "test"))) + + +;;;; Example Block + +(ert-deftest test-org-element/example-block-parser () + "Test `example-block' parser." + ;; Regular tests. + (should + (equal + (org-test-with-temp-text "#+BEGIN_EXAMPLE\nText\n#+END_EXAMPLE" + (org-element-map + (org-element-parse-buffer) 'example-block 'identity nil t)) + '(example-block + (:begin 1 :end 35 :value "Text\n" :switches nil + :number-lines nil :preserve-indent nil :retain-labels t + :use-labels t :label-fmt nil :hiddenp nil :post-blank 0)))) + ;; Test folded block. + (org-test-with-temp-text "#+BEGIN_EXAMPLE\nText\n#+END_EXAMPLE" + (org-cycle) + (should + (org-element-property + :hiddenp + (org-element-map + (org-element-parse-buffer) 'example-block 'identity nil t)))) + ;; Ignore incomplete block. + (should-not + (org-test-with-temp-text "#+BEGIN_EXAMPLE" + (org-element-map + (org-element-parse-buffer) 'example-block 'identity nil t)))) (ert-deftest test-org-element/block-switches () "Test `example-block' and `src-block' switches parsing." @@ -169,10 +426,38 @@ Return interpreted string." (equal (org-element-property :label-fmt element) "[ref:%s]")))))) -;;;; Export snippets +;;;; Export Block + +(ert-deftest test-org-element/export-block-parser () + "Test `export-block' parser." + ;; Regular tests. + (should + (equal + (org-test-with-temp-text "#+BEGIN_LATEX\nText\n#+END_LATEX" + (org-element-map + (org-element-parse-buffer) 'export-block 'identity nil t)) + '(export-block + (:begin 1 :end 31 :type "LATEX" :value "Text\n" :hiddenp nil + :post-blank 0)))) + ;; Test folded block. + (org-test-with-temp-text "#+BEGIN_LATEX\nText\n#+END_LATEX" + (org-cycle) + (should + (org-element-property + :hiddenp + (org-element-map + (org-element-parse-buffer) 'export-block 'identity nil t)))) + ;; Ignore incomplete block. + (should-not + (org-test-with-temp-text "#+BEGIN_LATEX" + (org-element-map + (org-element-parse-buffer) 'export-block 'identity nil t)))) + + +;;;; Export Snippet (ert-deftest test-org-element/export-snippet-parser () - "Test export-snippet parsing." + "Test `export-snippet' parser." (should (equal (org-test-with-temp-text "" @@ -183,7 +468,7 @@ Return interpreted string." :value "contents" :begin 1 :end 20 :post-blank 0))))) -;;;; Fixed width +;;;; Fixed Width (ert-deftest test-org-element/fixed-width () "Test fixed-width area parsing." @@ -220,10 +505,27 @@ Return interpreted string." (org-element-parse-buffer) 'fixed-width 'identity)))))) -;;;; Footnotes references +;;;; Footnote Definition. + +(ert-deftest test-org-element/footnote-definition-parser () + "Test `footnote-definition' parser." + (should + (equal + (org-test-with-temp-text "[fn:1] Definition" + (org-element-map + (org-element-parse-buffer) 'footnote-definition 'identity nil t)) + '(footnote-definition + (:label "fn:1" :begin 1 :end 18 :contents-begin 8 :contents-end 18 + :post-blank 0) + (paragraph + (:begin 8 :end 18 :contents-begin 8 :contents-end 18 :post-blank 0) + "Definition"))))) + + +;;;; Footnotes Reference (ert-deftest test-org-element/footnote-reference-parser () - "Test footnote-reference parsing." + "Test `footnote-reference' parser." ;; 1. Parse a standard reference. (org-test-with-temp-text "[fn:label]" (should (equal (org-element-footnote-reference-parser) @@ -346,10 +648,142 @@ Return interpreted string." (should (equal (org-element-property :tags headline) '("test"))))))) -;;;; Links +;;;; Inlinetask. + +(ert-deftest test-org-element/inlinetask-parser () + "Test `inlinetask' parser." + (when (featurep 'org-inlinetask) + (let ((org-inlinetask-min-level 15)) + ;; 1. Regular inlinetask. + (should + (equal + (org-test-with-temp-text + "*************** Task\nTest\n*************** END" + (org-element-map + (org-element-parse-buffer) 'inlinetask 'identity nil t)) + '(inlinetask + (:title ("Task") :begin 1 :end 46 :hiddenp nil :contents-begin 22 + :contents-end 27 :level 15 :priority nil :tags nil + :todo-keyword nil :todo-type nil :scheduled nil :deadline nil + :timestamp nil :clock nil :post-blank 0 :category "???") + (paragraph + (:begin 22 :end 27 :contents-begin 22 :contents-end 26 :post-blank 0) + "Test")))) + ;; 2. Degenerate inlinetask. + (should + (equal + (org-test-with-temp-text + "*************** Task" + (org-element-map + (org-element-parse-buffer) 'inlinetask 'identity nil t)) + '(inlinetask + (:title ("Task") :begin 1 :end 21 :hiddenp nil :contents-begin 21 + :contents-end 21 :level 15 :priority nil :tags nil + :todo-keyword nil :todo-type nil :scheduled nil :deadline nil + :timestamp nil :clock nil :post-blank 0 :category nil)))) + ;; TODO keyword. + (should + (equal + "TODO" + (let ((org-todo-keywords '((sequence "TODO" "DONE")))) + (org-test-with-temp-text "*************** TODO Task" + (org-element-property + :todo-keyword + (org-element-map + (org-element-parse-buffer) 'inlinetask 'identity nil t)))))) + ;; Planning info. + (should + (equal + "2012-03-29 thu." + (org-test-with-temp-text " +*************** Task +DEADLINE: <2012-03-29 thu.>" + (org-element-property + :deadline + (org-element-map + (org-element-parse-buffer) 'inlinetask 'identity nil t))))) + ;; Priority. + (should + (equal + ?A + (org-test-with-temp-text " +*************** [#A] Task" + (org-element-property + :priority + (org-element-map + (org-element-parse-buffer) 'inlinetask 'identity nil t))))) + ;; Tags. + (should + (equal + '("test") + (org-test-with-temp-text " +*************** Task :test:" + (org-element-property + :tags + (org-element-map + (org-element-parse-buffer) 'inlinetask 'identity nil t)))))))) + + +;;;; Item. + +(ert-deftest test-org-element/item-parser () + "Test `item' parser." + ;; Standard test. + (should + (equal + (org-test-with-temp-text "- item" + (org-element-map (org-element-parse-buffer) 'item 'identity nil t)) + '(item + (:bullet "- " :begin 1 :end 7 :contents-begin 3 :contents-end 7 + :checkbox nil :counter nil :tag nil :hiddenp nil + :structure ((1 0 "- " nil nil nil 7)) + :post-blank 0) + (paragraph + (:begin 3 :end 7 :contents-begin 3 :contents-end 7 :post-blank 0) + "item")))) + ;; Counter. + (should + (= 6 + (org-element-property + :counter + (org-test-with-temp-text "6. [@6] item" + (org-element-map (org-element-parse-buffer) 'item 'identity nil t))))) + ;; Tag + (should + (equal + '("tag") + (org-element-property + :tag + (org-test-with-temp-text "- tag :: description" + (org-element-map (org-element-parse-buffer) 'item 'identity nil t))))) + ;; Check-boxes + (should + (equal + '(trans on off) + (org-test-with-temp-text " +- [-] item 1 + - [X] item 1.1 + - [ ] item 1.2" + (org-element-map + (org-element-parse-buffer) 'item + (lambda (item) (org-element-property :checkbox item)))))) + ;; Folded state. + (org-test-with-temp-text "* Headline +- item + + paragraph below" + (forward-line) + (let ((org-cycle-include-plain-lists t)) (org-cycle)) + (should + (org-element-property + :hiddenp + (org-element-map (org-element-parse-buffer) 'item 'identity nil t))))) + + +;;;; Link (ert-deftest test-org-element/link-parser () - "Test link parsing." + "Test `link' parser." ;; 1. Radio target. (should (equal (org-test-with-temp-text "A radio link" @@ -436,10 +870,162 @@ Return interpreted string." :raw-link "http://orgmode.org" :begin 9 :end 29 :contents-begin nil :contents-end nil :post-blank 0))))) -;;;; Verse blocks + +;;;; Plain List. + +(ert-deftest test-org-element/plain-list-parser () + "Test `plain-list' parser." + (should + (equal + (org-test-with-temp-text "- item" + (org-element-map (org-element-parse-buffer) 'plain-list 'identity nil t)) + '(plain-list + (:type unordered :begin 1 :end 7 :contents-begin 1 :contents-end 7 + :structure ((1 0 "- " nil nil nil 7)) :post-blank 0) + (item + (:bullet "- " :begin 1 :end 7 :contents-begin 3 :contents-end 7 + :checkbox nil :counter nil :tag nil :hiddenp nil + :structure ((1 0 "- " nil nil nil 7)) :post-blank 0) + (paragraph + (:begin 3 :end 7 :contents-begin 3 :contents-end 7 :post-blank 0) + "item"))))) + ;; Blank lines after the list only belong to outer plain list. + (org-test-with-temp-text " +- outer + - inner + +Outside list" + (let ((endings (org-element-map + (org-element-parse-buffer) 'plain-list + (lambda (pl) (org-element-property :end pl))))) + ;; Move to ending of outer list. + (goto-char (car endings)) + (should (looking-at "Outside list")) + ;; Move to ending of inner list. + (goto-char (nth 1 endings)) + (should (looking-at "^$"))))) + + +;;;; Src Block. + +(ert-deftest test-org-element/src-block-parser () + "Test `src-block' parser." + ;; Regular tests. + (should + (equal + (org-test-with-temp-text "#+BEGIN_SRC\nText\n#+END_SRC" + (org-element-map + (org-element-parse-buffer) 'src-block 'identity nil t)) + '(src-block + (:language nil :switches nil :parameters nil :begin 1 :end 27 + :number-lines nil :preserve-indent nil :retain-labels t + :use-labels t :label-fmt nil :hiddenp nil :value "Text\n" + :post-blank 0)))) + ;; Test folded block. + (org-test-with-temp-text "#+BEGIN_SRC\nText\n#+END_SRC" + (org-cycle) + (should + (org-element-property + :hiddenp + (org-element-map + (org-element-parse-buffer) 'src-block 'identity nil t)))) + ;; Ignore incomplete block. + (should-not + (org-test-with-temp-text "#+BEGIN_SRC" + (org-element-map + (org-element-parse-buffer) 'src-block 'identity nil t)))) + + +;;;; Quote Block + +(ert-deftest test-org-element/quote-block-parser () + "Test `quote-block' parser." + ;; Regular test. + (should + (equal + (org-test-with-temp-text "#+BEGIN_QUOTE\nText\n#+END_QUOTE" + (org-element-map + (org-element-parse-buffer) 'quote-block 'identity nil t)) + '(quote-block + (:begin 1 :end 31 :hiddenp nil :contents-begin 15 :contents-end 20 + :post-blank 0) + (paragraph + (:begin 15 :end 20 :contents-begin 15 :contents-end 19 :post-blank 0) + "Text")))) + ;; Test folded block. + (org-test-with-temp-text "#+BEGIN_QUOTE\nText\n#+END_QUOTE" + (org-cycle) + (should + (org-element-property + :hiddenp + (org-element-map + (org-element-parse-buffer) 'quote-block 'identity nil t)))) + ;; Ignore incomplete block. + (should-not + (org-test-with-temp-text "#+BEGIN_QUOTE" + (org-element-map + (org-element-parse-buffer) 'quote-block 'identity nil t)))) + + +;;;; Section + +(ert-deftest test-org-element/section-parser () + "Test `section' parser." + ;; Standard test. + (should + (equal + (org-test-with-temp-text "* Headline\nText" + (org-element-map (org-element-parse-buffer) 'section 'identity nil t)) + '(section + (:begin 12 :end 16 :contents-begin 12 :contents-end 16 :post-blank 0) + (paragraph + (:begin 12 :end 16 :contents-begin 12 :contents-end 16 :post-blank 0) + "Text")))) + ;; There's a section before the first headline. + (should + (org-test-with-temp-text "Text" + (org-element-map (org-element-parse-buffer) 'section 'identity))) + ;; A section cannot be empty. + (should-not + (org-test-with-temp-text "* Headline 1\n* Headline 2" + (org-element-map (org-element-parse-buffer) 'section 'identity)))) + + +;;;; Special Block + +(ert-deftest test-org-element/special-block-parser () + "Test `special-block' parser." + ;; Regular test. + (should + (equal + (org-test-with-temp-text "#+BEGIN_SPECIAL\nText\n#+END_SPECIAL" + (org-element-map + (org-element-parse-buffer) 'special-block 'identity nil t)) + '(special-block + (:type "SPECIAL" :begin 1 :end 35 :hiddenp nil :contents-begin 17 + :contents-end 22 :post-blank 0) + (paragraph + (:begin 17 :end 22 :contents-begin 17 :contents-end 21 :post-blank 0) + "Text")))) + ;; Test folded block. + (org-test-with-temp-text "#+BEGIN_SPECIAL\nText\n#+END_SPECIAL" + (org-cycle) + (should + (org-element-property + :hiddenp + (org-element-map + (org-element-parse-buffer) 'special-block 'identity nil t)))) + ;; Ignore incomplete block. + (should-not + (org-test-with-temp-text "#+BEGIN_SPECIAL" + (org-element-map + (org-element-parse-buffer) 'special-block 'identity nil t)))) + + +;;;; Verse Block (ert-deftest test-org-element/verse-block-parser () - "Test verse block parsing." + "Test `verse-block' parser." ;; Standard test. (org-test-with-temp-text "#+BEGIN_VERSE\nVerse block\n#+END_VERSE" (should @@ -470,7 +1056,12 @@ Return interpreted string." "Verse block\n")))) ;; Parse objects in verse blocks. (org-test-with-temp-text "#+BEGIN_VERSE\nVerse \\alpha\n#+END_VERSE" - (should (org-element-map (org-element-parse-buffer) 'entity 'identity)))) + (should (org-element-map (org-element-parse-buffer) 'entity 'identity))) + ;; Ignore incomplete verse block. + (should-not + (org-test-with-temp-text "#+BEGIN_VERSE" + (org-element-map + (org-element-parse-buffer) 'verse-block 'identity nil t))))