Say below org-mode block:

#+BEGIN_QUOTE
item 1
item 2
#+END_QUOTE

If export as html, the display is:

item 1 item 2

It should be two line but actually merged as one line! I wish to keep the line feed CRLF!

up vote 3 down vote accepted

If you want to preserve newlines for the whole org-file you can use

#+OPTIONS: \n:t

If you want to preserve newlines only in quote blocks you can copy the following Elisp code into your init file. It defines a new keyword HTML_QUOTE_KEEP_NEWLINES. If that keyword is set to t newlines are preserved in quote blocks only.

(require 'org)
(require 'org-element)
(require 'ox)
(require 'ox-html)

(defcustom org-html-quote-keep-newlines nil
  "Keep newlines in org quote blocks.
This is the default value.
You can set it buffer-specific with
,#+HTML_QUOTE_KEEP_NEWLINES: t"
  :group 'org-html
  :type 'boolean)

(setf (org-export-backend-options (org-export-get-backend 'html))
      (cons
       '(:html-quote-keep-newlines "HTML_QUOTE_KEEP_NEWLINES" nil org-html-quote-keep-newlines)
       (org-export-backend-options (org-export-get-backend 'html))))

(defun my-html-real-text-on-line-p ()
  "Return non-nil if there is more than whitespace and html tags on current line."
  (catch :found
    (while (null (eq (char-after) ?\n))
      (skip-syntax-forward " ") ;; skip whitespace
      (cond
       ((eq (char-after) ?<) ;; 1st case: beginning of tag
    ;; go behind the tag:
        (skip-chars-forward "^>") ;;< We even skip newlines here. It is actually an error if we fall off the edge of the world at this point.
    (forward-char)) ;;< Go behind the tag.
       ((eq (char-after) ?\n)) ;; 2nd case: Do nothing if we end up at an end of line.
       (t (throw :found t)))))) ;; 3rd case: No tag, no end of line, that is actually some real text.

(defun my-org-quote-preserve-linebreaks (quote_block_contents back_end info)
  "Keep linebreaks in QUOTE_BLOCK_CONTENTS when BACK_END is 'html."
  (when (and (eq back_end 'html)
             (plist-get info :html-quote-keep-newlines))
    (with-temp-buffer
      (insert quote_block_contents)
      (goto-char (point-min))
      (while (null (eobp))
    (when (my-html-real-text-on-line-p)
      (end-of-line)
      (insert "<br/>"))
    (forward-line))
      (buffer-string))))

(add-hook 'org-export-filter-quote-block-functions #'my-org-quote-preserve-linebreaks)
  • Many thanks, it works fine! Would you please help give more details about the cond statement? Is it two condition true then throw exception? what's the meaning of this statement? ((eq (char-after) ?\n)), I deleted it and works also! – lucky1928 Dec 2 at 19:30
  • @lucky1928 I have refactored and commented the code. That should solve your question what cond does. ((eq (char-after) ?\n)) checks whether the character at point is a newline. We do not want to interpret that as real text on that line and leave the cond form before throwing the :found t. Please use C-h f to read the documentation string of the function you want to know more about, e.g., <C-h f> cond <RET>. – Tobias Dec 3 at 9:09

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.