org-element: Add a function to fill an element

* contrib/lisp/org-element.el (org-element-fill-paragraph): New function.
* testing/lisp/test-org-element.el: Add tests.
This commit is contained in:
Nicolas Goaziou 2012-05-05 17:13:32 +02:00
parent 88032eed64
commit e4c2540b68
2 changed files with 121 additions and 0 deletions

View file

@ -4135,6 +4135,83 @@ modified."
(reverse contents))))))
(funcall unindent-tree (org-element-contents parse-tree))))
(defun org-element-fill-paragraph (&optional justify)
"Fill element at point, when applicable.
This function only applies to paragraph, comment blocks, example
blocks and fixed-width areas. Also, as a special case, re-align
table when point is at one.
If JUSTIFY is non-nil (interactively, with prefix argument),
justify as well. If `sentence-end-double-space' is non-nil, then
period followed by one space does not end a sentence, so don't
break a line there. The variable `fill-column' controls the
width for filling."
(let ((element (org-element-at-point)))
(case (org-element-type element)
;; Align Org tables, leave table.el tables as-is.
(table-row (org-table-align) t)
(table
(when (eq (org-element-property :type element) 'org) (org-table-align))
t)
;; Elements that may contain `line-break' type objects.
((paragraph verse-block)
(let ((beg (org-element-property :contents-begin element))
(end (org-element-property :contents-end element)))
;; Do nothing if point is at an affiliated keyword or at
;; verse block markers.
(if (or (< (point) beg) (>= (point) end)) t
;; At a verse block, first narrow to current "paragraph"
;; and set current element to that paragraph.
(save-restriction
(when (eq (org-element-type element) 'verse-block)
(narrow-to-region beg end)
(save-excursion
(end-of-line)
(let ((bol-pos (point-at-bol)))
(re-search-backward org-element-paragraph-separate nil 'move)
(unless (or (bobp) (= (point-at-bol) bol-pos))
(forward-line))
(setq element (org-element-paragraph-parser)
beg (org-element-property :contents-begin element)
end (org-element-property :contents-end element)))))
;; Fill paragraph, taking line breaks into consideration.
;; For that, slice the paragraph using line breaks as
;; separators, and fill the parts in reverse order to
;; avoid messing with markers.
(save-excursion
(goto-char end)
(mapc
(lambda (pos)
(fill-region-as-paragraph pos (point) justify)
(goto-char pos))
;; Find the list of ending positions for line breaks
;; in the current paragraph. Add paragraph beginning
;; to include first slice.
(nreverse
(cons beg
(org-element-map
(org-element-parse-objects
beg end nil org-element-all-objects)
'line-break
(lambda (lb) (org-element-property :end lb)))))))) t)))
;; Elements whose contents should be filled as plain text.
((comment-block example-block)
(save-restriction
(narrow-to-region
(save-excursion
(goto-char (org-element-property :begin element))
(while (looking-at org-element--affiliated-re) (forward-line))
(forward-line)
(point))
(save-excursion
(goto-char (org-element-property :end element))
(if (bolp) (forward-line -1) (beginning-of-line))
(point)))
(fill-paragraph justify) t))
;; Ignore every other element.
(otherwise t))))
(provide 'org-element)
;;; org-element.el ends here

View file

@ -1999,6 +1999,50 @@ Outside."
(should (equal (buffer-string) "Para2\n\n\nParagraph 1\n\nPara3"))
(should (looking-at " 1"))))
(ert-deftest test-org-element/fill-paragraph ()
"Test `org-element-fill-paragraph' specifications."
;; At an Org table, align it.
(org-test-with-temp-text "|a|"
(org-element-fill-paragraph)
(should (equal (buffer-string) "| a |\n")))
;; At a paragraph, preserve line breaks.
(org-test-with-temp-text "some \\\\\nlong\ntext"
(let ((fill-column 20))
(org-element-fill-paragraph)
(should (equal (buffer-string) "some \\\\\nlong text"))))
;; At a verse block, fill paragraph at point, also preserving line
;; breaks. Though, do nothing when point is at the block
;; boundaries.
(org-test-with-temp-text "#+BEGIN_VERSE\nSome \\\\\nlong\ntext\n#+END_VERSE"
(forward-line)
(let ((fill-column 20))
(org-element-fill-paragraph)
(should (equal (buffer-string)
"#+BEGIN_VERSE\nSome \\\\\nlong text\n#+END_VERSE"))))
(org-test-with-temp-text "#+BEGIN_VERSE\nSome \\\\\nlong\ntext\n#+END_VERSE"
(let ((fill-column 20))
(org-element-fill-paragraph)
(should (equal (buffer-string)
"#+BEGIN_VERSE\nSome \\\\\nlong\ntext\n#+END_VERSE"))))
;; Fill contents of `comment-block' and `example-block' elements.
(org-test-with-temp-text "#+BEGIN_COMMENT\nSome\ntext\n#+END_COMMENT"
(let ((fill-column 20))
(forward-line)
(org-element-fill-paragraph)
(should (equal (buffer-string)
"#+BEGIN_COMMENT\nSome text\n#+END_COMMENT"))))
(org-test-with-temp-text "#+BEGIN_EXAMPLE\nSome\ntext\n#+END_EXAMPLE"
(let ((fill-column 20))
(forward-line)
(org-element-fill-paragraph)
(should (equal (buffer-string)
"#+BEGIN_EXAMPLE\nSome text\n#+END_EXAMPLE"))))
;; Do nothing at affiliated keywords.
(org-test-with-temp-text "#+NAME: para\nSome\ntext."
(let ((fill-column 20))
(org-element-fill-paragraph)
(should (equal (buffer-string) "#+NAME: para\nSome\ntext.")))))
(provide 'test-org-element)
;;; test-org-element.el ends here