org-element: Verse blocks now contain objects

* contrib/lisp/org-element.el (org-element-verse-block-parser): Verse
  blocks now contain objects.
(org-element-verse-block-interpreter, org-element-current-element):
Apply changes to verse blocks.
(org-element-secondary-value-alist): Remove verse blocks from elements
with a secondary string.
* contrib/lisp/org-e-odt.el (org-e-odt-verse-block): Apply changes to
  verse blocks.
* contrib/lisp/org-e-latex.el (org-e-latex-verse-block): Apply changes
  to verse blocks.
* contrib/lisp/org-e-html.el (org-e-html-verse-block): Apply changes
  to verse blocks.
* contrib/lisp/org-e-ascii.el (org-e-ascii-verse-block): Apply changes
  to verse blocks.
* testing/lisp/test-org-element.el: Add tests.
This commit is contained in:
Nicolas Goaziou 2012-04-25 22:15:29 +02:00
parent c3d7d21108
commit c6dc6e3d32
6 changed files with 124 additions and 99 deletions

View File

@ -1730,13 +1730,11 @@ CONTENTS is nil. INFO is a plist holding contextual information."
(defun org-e-ascii-verse-block (verse-block contents info)
"Transcode a VERSE-BLOCK element from Org to ASCII.
CONTENTS is nil. INFO is a plist holding contextual information."
CONTENTS is verse block contents. INFO is a plist holding
contextual information."
(let ((verse-width (org-e-ascii--current-text-width verse-block info)))
(org-e-ascii--indent-string
(org-e-ascii--justify-string
(org-export-secondary-string
(org-element-property :value verse-block) 'e-ascii info)
verse-width 'left)
(org-e-ascii--justify-string contents verse-width 'left)
org-e-ascii-quote-margin)))

View File

@ -2949,17 +2949,14 @@ channel."
(defun org-e-html-verse-block (verse-block contents info)
"Transcode a VERSE-BLOCK element from Org to HTML.
CONTENTS is nil. INFO is a plist holding contextual information."
CONTENTS is verse block contents. INFO is a plist holding
contextual information."
;; Replace each newline character with line break. Also replace
;; each blank line with a line break.
(setq contents (replace-regexp-in-string
"^ *\\\\\\\\$" "<br/>\n"
(replace-regexp-in-string
"\\(\\\\\\\\\\)?[ \t]*\n" " <br/>\n"
(org-remove-indentation
(org-export-secondary-string
(org-element-property :value verse-block)
'e-html info)))))
"\\(\\\\\\\\\\)?[ \t]*\n" " <br/>\n" contents)))
;; Replace each white space at beginning of a line with a
;; non-breaking space.
(while (string-match "^[ \t]+" contents)

View File

@ -2118,7 +2118,8 @@ channel."
(defun org-e-latex-verse-block (verse-block contents info)
"Transcode a VERSE-BLOCK element from Org to LaTeX.
CONTENTS is nil. INFO is a plist holding contextual information."
CONTENTS is verse block contents. INFO is a plist holding
contextual information."
(org-e-latex--wrap-label
verse-block
;; In a verse environment, add a line break to each newline
@ -2129,11 +2130,7 @@ CONTENTS is nil. INFO is a plist holding contextual information."
(setq contents (replace-regexp-in-string
"^ *\\\\\\\\$" "\\\\vspace*{1em}"
(replace-regexp-in-string
"\\(\\\\\\\\\\)?[ \t]*\n" " \\\\\\\\\n"
(org-remove-indentation
(org-export-secondary-string
(org-element-property :value verse-block)
'e-latex info)))))
"\\(\\\\\\\\\\)?[ \t]*\n" " \\\\\\\\\n" contents)))
(while (string-match "^[ \t]+" contents)
(let ((new-str (format "\\hspace*{%dem}"
(length (match-string 0 contents)))))

View File

@ -4148,17 +4148,14 @@ channel."
(defun org-e-odt-verse-block (verse-block contents info)
"Transcode a VERSE-BLOCK element from Org to HTML.
CONTENTS is nil. INFO is a plist holding contextual information."
CONTENTS is verse block contents. INFO is a plist holding
contextual information."
;; Replace each newline character with line break. Also replace
;; each blank line with a line break.
(setq contents (replace-regexp-in-string
"^ *\\\\\\\\$" "<br/>\n"
(replace-regexp-in-string
"\\(\\\\\\\\\\)?[ \t]*\n" " <br/>\n"
(org-remove-indentation
(org-export-secondary-string
(org-element-property :value verse-block)
'e-odt info)))))
"\\(\\\\\\\\\\)?[ \t]*\n" " <br/>\n" contents)))
;; Replace each white space at beginning of a line with a
;; non-breaking space.

View File

@ -25,45 +25,51 @@
;; Org syntax can be divided into three categories: "Greater
;; elements", "Elements" and "Objects".
;; An object can be defined anywhere on a line. It may span over more
;; than a line but never contains a blank one. Objects belong to the
;; following types: `emphasis', `entity', `export-snippet',
;; `footnote-reference', `inline-babel-call', `inline-src-block',
;; `latex-fragment', `line-break', `link', `macro', `radio-target',
;; `statistics-cookie', `subscript', `superscript', `table-cell',
;; `target', `time-stamp' and `verbatim'.
;; An element always starts and ends at the beginning of a line
;; (excepted for `table-cell'). The only element's type containing
;; objects is called a `paragraph'. Other types are: `comment',
;; `comment-block', `example-block', `export-block', `fixed-width',
;; `horizontal-rule', `keyword', `latex-environment', `babel-call',
;; `property-drawer', `quote-section', `src-block', `table',
;; `table-row' and `verse-block'.
;; Elements containing paragraphs are called greater elements.
;; Concerned types are: `center-block', `drawer', `dynamic-block',
;; `footnote-definition', `headline', `inlinetask', `item',
;; `plain-list', `quote-block', `section' and `special-block'
;; Greater elements (excepted `headline', `item' and `section' types)
;; and elements (excepted `keyword', `babel-call', `property-drawer'
;; and `table-row' types) can have a fixed set of keywords as
;; attributes. Those are called "affiliated keywords", to distinguish
;; them from others keywords, which are full-fledged elements. In
;; particular, the "name" affiliated keyword allows to label almost
;; any element in an Org buffer.
;; Elements are related to the structure of the document. Indeed, all
;; elements are a cover for the document: each position within belongs
;; to at least one element.
;; An element always starts and ends at the beginning of a line. With
;; a few exceptions (namely `headline', `item', `section', `keyword',
;; `babel-call' and `property-drawer' types), it can also accept
;; a fixed set of keywords as attributes. Those are called
;; "affiliated keywords" to distinguish them from other keywords,
;; which are full-fledged elements.
;;
;; Element containing other elements (and only elements) are called
;; greater elements. Concerned types are: `center-block', `drawer',
;; `dynamic-block', `footnote-definition', `headline', `inlinetask',
;; `item', `plain-list', `quote-block', `section' and `special-block'.
;;
;; Other element types are: `babel-call', `comment', `comment-block',
;; `example-block', `export-block', `fixed-width', `horizontal-rule',
;; `keyword', `latex-environment', `paragraph', `property-drawer',
;; `quote-section', `src-block', `table', `table-cell', `table-row'
;; and `verse-blocks'. Among them, `paragraph', `table-cell' 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: `emphasis',
;; `entity', `export-snippet', `footnote-reference',
;; `inline-babel-call', `inline-src-block', `latex-fragment',
;; `line-break', `link', `macro', `radio-target', `statistics-cookie',
;; `subscript', `superscript', `table-cell', `target', `time-stamp'
;; and `verbatim'.
;;
;; Some elements also have special properties whose value can hold
;; objects themselves (i.e. an item tag or an headline name). Such
;; values are called "secondary strings". Any object belongs to
;; either an element or a secondary string.
;;
;; Notwithstanding affiliated keywords, each greater element, element
;; and object has a fixed set of properties attached to it. Among
;; them, three are shared by all types: `:begin' and `:end', which
;; refer to the beginning and ending buffer positions of the
;; considered element or object, and `:post-blank', which holds the
;; number of blank lines, or white spaces, at its end.
;; Some elements also have special properties whose value can hold
;; objects themselves (i.e. an item tag, an headline name, a table
;; cell). Such values are called "secondary strings".
;; number of blank lines, or white spaces, at its end. Greater
;; elements and elements containing objects will also have
;; `:contents-begin' and `:contents-end' properties to delimit
;; contents.
;; Lisp-wise, an element or an object can be represented as a list.
;; It follows the pattern (TYPE PROPERTIES CONTENTS), where:
@ -81,7 +87,7 @@
;; for each type of Org syntax.
;; The next two parts introduce four accessors and a function
;; retrieving the smallest element starting at point (respectively
;; retrieving the element starting at point (respectively
;; `org-element-type', `org-element-property', `org-element-contents',
;; `org-element-restriction' and `org-element-current-element').
@ -1584,56 +1590,40 @@ CONTENTS is the contents of the table row."
;;;; Verse Block
(defun org-element-verse-block-parser (&optional raw-secondary-p)
(defun org-element-verse-block-parser ()
"Parse a verse block.
Return a list whose car is `verse-block' and cdr is a plist
containing `:begin', `:end', `:hiddenp', `:value' and
`:post-blank' keywords.
Return a list whose CAR is `verse-block' and CDR is a plist
containing `:begin', `:end', `:contents-begin', `:contents-end',
`:hiddenp' and `:post-blank' keywords.
When optional argument RAW-SECONDARY-P is non-nil, verse-block's
value will not be parsed as a secondary string, but as a plain
string instead.
Assume point is at beginning or end of the block."
Assume point is at beginning of the block."
(save-excursion
(let* ((case-fold-search t)
(keywords (progn
(end-of-line)
(re-search-backward
(concat "^[ \t]*#\\+BEGIN_VERSE") nil t)
(org-element-collect-affiliated-keywords)))
(keywords (org-element-collect-affiliated-keywords))
(begin (car keywords))
(hidden (progn (forward-line) (org-truely-invisible-p)))
(value-begin (point))
(value-end
(contents-begin (point))
(contents-end
(progn
(re-search-forward (concat "^[ \t]*#\\+END_VERSE") nil t)
(point-at-bol)))
(pos-before-blank (progn (forward-line) (point)))
(end (progn (org-skip-whitespace)
(if (eobp) (point) (point-at-bol))))
(value
(if raw-secondary-p
(buffer-substring-no-properties value-begin value-end)
(org-element-parse-secondary-string
(buffer-substring-no-properties value-begin value-end)
(org-element-restriction 'verse-block)))))
(if (eobp) (point) (point-at-bol)))))
`(verse-block
(:begin ,begin
:end ,end
:contents-begin ,contents-begin
:contents-end ,contents-end
:hiddenp ,hidden
:value ,value
:post-blank ,(count-lines pos-before-blank end)
,@(cadr keywords))))))
(defun org-element-verse-block-interpreter (verse-block contents)
"Interpret VERSE-BLOCK element as Org syntax.
CONTENTS is nil."
(format "#+BEGIN_VERSE\n%s#+END_VERSE"
(org-remove-indentation
(org-element-interpret-secondary
(org-element-property :value verse-block)))))
CONTENTS is verse block contents."
(format "#+BEGIN_VERSE\n%s#+END_VERSE" contents))
@ -2767,8 +2757,7 @@ still has an entry since one of its properties (`:title') does.")
'((headline . :title)
(inlinetask . :title)
(item . :tag)
(footnote-reference . :inline-definition)
(verse-block . :value))
(footnote-reference . :inline-definition))
"Alist between element types and location of secondary value.")
@ -2884,17 +2873,11 @@ it is quicker than its counterpart, albeit more restrictive."
(if (save-excursion
(re-search-forward
(format "[ \t]*#\\+END_%s\\(?: \\|$\\)" type) nil t))
;; Build appropriate parser. `verse-block' type
;; elements require an additional argument, so they
;; must be treated separately.
(if (string= "VERSE" type)
(org-element-verse-block-parser raw-secondary-p)
(funcall
(intern
(format
"org-element-%s-parser"
(cdr (assoc type
org-element-non-recursive-block-alist))))))
(funcall
(intern
(format
"org-element-%s-parser"
(cdr (assoc type org-element-non-recursive-block-alist)))))
(org-element-paragraph-parser)))))
;; Inlinetask.
((org-at-heading-p) (org-element-inlinetask-parser raw-secondary-p))

View File

@ -260,6 +260,44 @@
(org-element-parse-buffer) 'footnote-reference 'identity))))
;;;; Verse blocks
(ert-deftest test-org-element/verse-block ()
"Test verse block parsing."
;; Standard test.
(org-test-with-temp-text "#+BEGIN_VERSE\nVerse block\n#+END_VERSE"
(should
(equal
(org-element-map (org-element-parse-buffer) 'verse-block 'identity nil t)
'(verse-block
(:begin 1 :end 38 :contents-begin 15 :contents-end 27 :hiddenp nil
:post-blank 0)
"Verse block\n"))))
;; Ignore case.
(org-test-with-temp-text "#+begin_verse\nVerse block\n#+end_verse"
(should
(equal
(org-element-map (org-element-parse-buffer) 'verse-block 'identity nil t)
'(verse-block
(:begin 1 :end 38 :contents-begin 15 :contents-end 27 :hiddenp nil
:post-blank 0)
"Verse block\n"))))
;; Parse folding.
(org-test-with-temp-text "#+BEGIN_VERSE\nVerse block\n#+END_VERSE"
(org-hide-block-all)
(should
(equal
(org-element-map (org-element-parse-buffer) 'verse-block 'identity nil t)
'(verse-block
(:begin 1 :end 38 :contents-begin 15 :contents-end 27
:hiddenp org-hide-block :post-blank 0)
"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))))
;;;; Granularity
@ -367,6 +405,21 @@ Paragraph \\alpha."
'(org-data nil (paragraph (:caption (("long") "short")) "Paragraph")))
"#+CAPTION[short]: long\nParagraph\n")))
(ert-deftest test-org-element/interpret-elements ()
"Test interpretation of elements and objects."
(let ((parse-and-interpret
(function
;; Parse TEXT string in an Org buffer and transcode it back
;; to Org syntax.
(lambda (text)
(with-temp-buffer
(org-mode)
(insert text)
(org-element-interpret-data (org-element-parse-buffer)))))))
;; Verse blocks.
(equal (funcall parse-and-interpret "#+BEGIN_VERSE\nTest\n#+END_VERSE")
"#+BEGIN_VERSE\nTest\n#+END_VERSE\n")))
;;;; Normalize contents