summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicolas Goaziou <mail@nicolasgoaziou.fr>2017-11-09 22:47:35 +0100
committerNicolas Goaziou <mail@nicolasgoaziou.fr>2017-11-10 00:38:31 +0100
commitd07ee7f7f2c591f170d55981c3acc0c402289749 (patch)
tree141e908944dd1e06c2c62f827222365c3016f850
parent8f3077d14afe91131d43c7ef6860b6e121538265 (diff)
downloadorg-mode-d07ee7f7f2c591f170d55981c3acc0c402289749.tar.gz
Implement :pre-blank property for items and footnotes definitions
* lisp/org-element.el (org-element-footnote-definition-parser): (org-element-item-parser): Add `:pre-blank' property. (org-element-footnote-definition-interpreter): (org-element-item-interpreter): (org-element-interpret-data): * lisp/ox.el (org-export-data): Use new property. * testing/lisp/test-org-element.el (test-org-element/footnote-definition-parser): (test-org-element/item-parser): Add tests.
-rw-r--r--lisp/org-element.el108
-rw-r--r--lisp/ox.el23
-rw-r--r--testing/lisp/test-org-element.el49
3 files changed, 123 insertions, 57 deletions
diff --git a/lisp/org-element.el b/lisp/org-element.el
index c21b2f9..3c8d7a7 100644
--- a/lisp/org-element.el
+++ b/lisp/org-element.el
@@ -812,7 +812,8 @@ their value.
Return a list whose CAR is `footnote-definition' and CDR is
a plist containing `:label', `:begin' `:end', `:contents-begin',
-`:contents-end', `:post-blank' and `:post-affiliated' keywords.
+`:contents-end', `:pre-blank',`:post-blank' and
+`:post-affiliated' keywords.
Assume point is at the beginning of the footnote definition."
(save-excursion
@@ -838,12 +839,16 @@ Assume point is at the beginning of the footnote definition."
((eq ?* (char-after (match-beginning 0))) (match-beginning 0))
(t (skip-chars-forward " \r\t\n" limit)
(if (= limit (point)) limit (line-beginning-position))))))
+ (pre-blank 0)
(contents-begin
(progn (search-forward "]")
(skip-chars-forward " \r\t\n" end)
(cond ((= (point) end) nil)
((= (line-beginning-position) post-affiliated) (point))
- (t (line-beginning-position)))))
+ (t
+ (setq pre-blank
+ (count-lines (line-beginning-position) begin))
+ (line-beginning-position)))))
(contents-end
(progn (goto-char end)
(skip-chars-backward " \r\t\n")
@@ -855,6 +860,7 @@ Assume point is at the beginning of the footnote definition."
:end end
:contents-begin contents-begin
:contents-end (and contents-begin contents-end)
+ :pre-blank pre-blank
:post-blank (count-lines contents-end end)
:post-affiliated post-affiliated)
(cdr affiliated))))))
@@ -862,9 +868,18 @@ Assume point is at the beginning of the footnote definition."
(defun org-element-footnote-definition-interpreter (footnote-definition contents)
"Interpret FOOTNOTE-DEFINITION element as Org syntax.
CONTENTS is the contents of the footnote-definition."
- (concat (format "[fn:%s]" (org-element-property :label footnote-definition))
- " "
- contents))
+ (let ((pre-blank
+ (min (or (org-element-property :pre-blank footnote-definition)
+ ;; 0 is specific to paragraphs at the beginning of
+ ;; the footnote definition, so we use 1 as
+ ;; a fall-back value, which is more universal.
+ 1)
+ ;; Footnote ends after more than two consecutive empty
+ ;; lines: limit ourselves to 2 newline characters.
+ 2)))
+ (concat (format "[fn:%s]" (org-element-property :label footnote-definition))
+ (if (= pre-blank 0) (concat " " (org-trim contents))
+ (concat (make-string pre-blank ?\n) contents)))))
;;;; Headline
@@ -1195,8 +1210,8 @@ STRUCT is the structure of the plain list.
Return a list whose CAR is `item' and CDR is a plist containing
`:bullet', `:begin', `:end', `:contents-begin', `:contents-end',
-`:checkbox', `:counter', `:tag', `:structure', `:post-blank' and
-`:post-affiliated' keywords.
+`:checkbox', `:counter', `:tag', `:structure', `:pre-blank',
+`:post-blank' and `:post-affiliated' keywords.
When optional argument RAW-SECONDARY-P is non-nil, item's tag, if
any, will not be parsed as a secondary string, but as a plain
@@ -1223,20 +1238,25 @@ Assume point is at the beginning of the item."
(string-to-number (match-string 0 c)))))))
(end (progn (goto-char (nth 6 (assq (point) struct)))
(if (bolp) (point) (line-beginning-position 2))))
+ (pre-blank 0)
(contents-begin
- (progn (goto-char
- ;; Ignore tags in un-ordered lists: they are just
- ;; a part of item's body.
- (if (and (match-beginning 4)
- (save-match-data (string-match "[.)]" bullet)))
- (match-beginning 4)
- (match-end 0)))
- (skip-chars-forward " \r\t\n" end)
- (cond ((= (point) end) nil)
- ;; If first line isn't empty, contents really
- ;; start at the text after item's meta-data.
- ((= (line-beginning-position) begin) (point))
- (t (line-beginning-position)))))
+ (progn
+ (goto-char
+ ;; Ignore tags in un-ordered lists: they are just
+ ;; a part of item's body.
+ (if (and (match-beginning 4)
+ (save-match-data (string-match "[.)]" bullet)))
+ (match-beginning 4)
+ (match-end 0)))
+ (skip-chars-forward " \r\t\n" end)
+ (cond ((= (point) end) nil)
+ ;; If first line isn't empty, contents really
+ ;; start at the text after item's meta-data.
+ ((= (line-beginning-position) begin) (point))
+ (t
+ (setq pre-blank
+ (count-lines (line-beginning-position) begin))
+ (line-beginning-position)))))
(contents-end (and contents-begin
(progn (goto-char end)
(skip-chars-backward " \r\t\n")
@@ -1251,6 +1271,7 @@ Assume point is at the beginning of the item."
:checkbox checkbox
:counter counter
:structure struct
+ :pre-blank pre-blank
:post-blank (count-lines (or contents-end begin) end)
:post-affiliated begin))))
(org-element-put-property
@@ -1275,26 +1296,30 @@ CONTENTS is the contents of the element."
(counter (org-element-property :counter item))
(tag (let ((tag (org-element-property :tag item)))
(and tag (org-element-interpret-data tag))))
- ;; Compute indentation.
- (ind (make-string (length bullet) 32))
- (item-starts-with-par-p
- (eq (org-element-type (car (org-element-contents item)))
- 'paragraph)))
+ (pre-blank
+ (min (or (org-element-property :pre-blank item)
+ ;; 0 is specific to paragraphs at the beginning of
+ ;; the item, so we use 1 as a fall-back value,
+ ;; which is more universal.
+ 1)
+ ;; Lists ends after more than two consecutive empty
+ ;; lines: limit ourselves to 2 newline characters.
+ 2))
+ (ind (make-string (length bullet) ?\s)))
;; Indent contents.
- (concat
- bullet
- (and counter (format "[@%d] " counter))
- (pcase checkbox
- (`on "[X] ")
- (`off "[ ] ")
- (`trans "[-] ")
- (_ nil))
- (and tag (format "%s :: " tag))
- (when contents
- (let ((contents (replace-regexp-in-string
- "\\(^\\)[ \t]*\\S-" ind contents nil nil 1)))
- (if item-starts-with-par-p (org-trim contents)
- (concat "\n" contents)))))))
+ (concat bullet
+ (and counter (format "[@%d] " counter))
+ (pcase checkbox
+ (`on "[X] ")
+ (`off "[ ] ")
+ (`trans "[-] ")
+ (_ nil))
+ (and tag (format "%s :: " tag))
+ (when contents
+ (let ((contents (replace-regexp-in-string
+ "\\(^\\)[ \t]*\\S-" ind contents nil nil 1)))
+ (if (= pre-blank 0) (org-trim contents)
+ (concat (make-string pre-blank ?\n) contents)))))))
;;;; Plain List
@@ -4532,8 +4557,9 @@ to interpret. Return Org syntax as a string."
(and (eq type 'paragraph)
(memq (org-element-type parent)
'(footnote-definition item))
- (eq data
- (car (org-element-contents parent)))))))
+ (eq data (car (org-element-contents parent)))
+ (eq (org-element-property :pre-blank parent)
+ 0)))))
""))))))
(if (memq type '(org-data plain-text nil)) results
;; Build white spaces. If no `:post-blank' property
diff --git a/lisp/ox.el b/lisp/ox.el
index 953a723..afce3e2 100644
--- a/lisp/ox.el
+++ b/lisp/ox.el
@@ -2001,17 +2001,18 @@ Return a string."
;; normalized first.
(org-element-normalize-contents
data
- ;; When normalizing contents of the
- ;; first paragraph in an item or
- ;; a footnote definition, ignore
- ;; first line's indentation: there is
- ;; none and it might be misleading.
- (when (eq type 'paragraph)
- (and
- (eq (car (org-element-contents parent))
- data)
- (memq (org-element-type parent)
- '(footnote-definition item)))))))
+ ;; When normalizing first paragraph
+ ;; of an item or
+ ;; a footnote-definition, ignore
+ ;; first line's indentation.
+ (and
+ (eq type 'paragraph)
+ (memq (org-element-type parent)
+ '(footnote-definition item))
+ (eq (car (org-element-contents parent))
+ data)
+ (eq (org-element-property :pre-blank parent)
+ 0)))))
"")))
(broken-link-handler
(funcall transcoder data
diff --git a/testing/lisp/test-org-element.el b/testing/lisp/test-org-element.el
index 7c359aa..b17e86b 100644
--- a/testing/lisp/test-org-element.el
+++ b/testing/lisp/test-org-element.el
@@ -969,7 +969,20 @@ Some other text
(org-test-with-temp-text "[fn:1]\n\n"
(let ((footnote (org-element-at-point)))
(or (org-element-property :contents-begin footnote)
- (org-element-property :contents-end footnote))))))
+ (org-element-property :contents-end footnote)))))
+ ;; Parse `:pre-blank'.
+ (should
+ (= 0
+ (org-test-with-temp-text "[fn:1] A"
+ (org-element-property :pre-blank (org-element-at-point)))))
+ (should
+ (= 1
+ (org-test-with-temp-text "[fn:1]\nA"
+ (org-element-property :pre-blank (org-element-at-point)))))
+ (should
+ (= 2
+ (org-test-with-temp-text "[fn:1]\n\nA"
+ (org-element-property :pre-blank (org-element-at-point))))))
;;;; Footnotes Reference.
@@ -1433,9 +1446,8 @@ DEADLINE: <2012-03-29 thu.>"
- [-] item 1
- [X] item 1.1
- [ ] item 1.2"
- (org-element-map
- (org-element-parse-buffer) 'item
- (lambda (item) (org-element-property :checkbox item))))))
+ (org-element-map (org-element-parse-buffer) 'item
+ (lambda (item) (org-element-property :checkbox item))))))
;; Item starting with special syntax.
(should
(equal '(("- item"))
@@ -1447,6 +1459,19 @@ DEADLINE: <2012-03-29 thu.>"
(org-test-with-temp-text
"-<point> item\n #+begin_src emacs-lisp\n(+ 1 1)\n #+end_src"
(= (org-element-property :end (org-element-at-point)) (point-max))))
+ ;; Parse `:pre-blank'.
+ (should
+ (= 0
+ (org-test-with-temp-text "-<point> A"
+ (org-element-property :pre-blank (org-element-at-point)))))
+ (should
+ (= 1
+ (org-test-with-temp-text "-<point>\n A"
+ (org-element-property :pre-blank (org-element-at-point)))))
+ (should
+ (= 2
+ (org-test-with-temp-text "-<point>\n\n A"
+ (org-element-property :pre-blank (org-element-at-point)))))
;; Last item in a list or sub-list has no `:post-blank' lines, since
;; those belong to the plain-list.
(should
@@ -2562,7 +2587,14 @@ Outside list"
(ert-deftest test-org-element/footnote-definition-interpreter ()
"Test footnote definition interpreter."
- (should (equal (org-test-parse-and-interpret "[fn:1] Test") "[fn:1] Test\n")))
+ (should (equal (org-test-parse-and-interpret "[fn:1] Test") "[fn:1] Test\n"))
+ ;; Handle `:pre-blank' in definitions.
+ (should
+ (equal (org-test-parse-and-interpret "[fn:1]\nparagraph")
+ "[fn:1]\nparagraph\n"))
+ (should
+ (equal (org-test-parse-and-interpret "[fn:1]\n\nparagraph")
+ "[fn:1]\n\nparagraph\n")))
(ert-deftest test-org-element/headline-interpreter ()
"Test headline and section interpreters."
@@ -2683,6 +2715,13 @@ Outside list"
(should
(equal (org-test-parse-and-interpret "-\n | a | b |")
"- \n | a | b |\n"))
+ ;; Handle `:pre-blank' in items.
+ (should
+ (equal (org-test-parse-and-interpret "-\n paragraph")
+ "- \n paragraph\n"))
+ (should
+ (equal (org-test-parse-and-interpret "-\n\n paragraph")
+ "- \n\n paragraph\n"))
;; Special case: correctly handle "*" bullets.
(should (org-test-parse-and-interpret " * item"))
;; Special case: correctly handle empty items.