I just discovered a problem with colorization and references in code snippets due to the way org-mode and htmlize interact. Consider the org-mode fragment:

#+BEGIN_SRC emacs-lisp
(let ((x 42)) ; meaning of l.u.e.
  (print x))  ; (ref:2)
#+END_SRC

Without the reference on line 2, doing an org-export-as-html would generate markup like this:

(let ((x 42)) <span style="comment">; meaning of l.u.e.
</span>  (print x))

Note that htmlize put the newline character on the end of the first line together with the text of the comment, both which is put inside the span. The closing tag of the span to colorize the comment thus ends up on the next line.

When a reference is put on the next line, org-mode will subsequently add markup to highlight each line, so the markup ends up like this:

(let ((x 42)) <span style="comment">; meaning of l.u.e.
<span id="ref-2"></span>  (print x))</span>
                 ^^^^^^^
The first closing tag is really the end of the comment which is spilled to the next line, but it erraneously closes the id span. The color of the comment then proceeds to the end of the second line, where the id span was to close.

To remedy this, I wrote a patch which postpone writing the newline to the html buffer until after the closing tag has been emitted. The patch is attached and should be applicable to the current Git repository.

It should be applicable to version 1.37 of htmlize.el as well, with the command `patch -p3 < 0001-Markup-on-same-line-as-text.patch`.

I refactored the insert-text functions so that they return the markup that should be applied instead of doing the insertion itself, and then let this go through a new function add-markup which puts the tags around the text, putting any trailing newline in the text at the very end, before the main htmlize-buffer-1 does the actual insertion in the buffer.

I have tested this with all three kinds of htmlize-output-type, and it seems to give the expected result.

--
 Roland.
>From 86f1508f58dd304471d768481944d34e220e24f1 Mon Sep 17 00:00:00 2001
From: Roland Kaufmann <rlndkfmn+orgm...@gmail.com>
Date: Thu, 6 Jan 2011 11:22:49 +0100
Subject: [PATCH] Markup on same line as text
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="------------1.7.3.1.msysgit.0"

This is a multi-part message in MIME format.
--------------1.7.3.1.msysgit.0
Content-Type: text/plain; charset=UTF-8; format=fixed
Content-Transfer-Encoding: 8bit


* contrib/lisp/htmlize.el: Markup on same line as text

Newline was considered to be a part of the text to be marked up; thus
the closing tag was put on the next line. Since org-mode does line
processing on the result, the line number span was closed prematurely
by this tag and the formatting erraneously extended through the next
line.

This fix replaces the insert-text functions with new get-markup variants
which return a pair (start-tag end-tag) for the appropriate formatting.
The newline is then removed from the text with `split-trailing-newline`
and appended again after the close tag in `add-markup`.

The text is sent to the buffer after this processing instead of in each
behavioral insert-text function. The names of the functions are changed
so reflect that the signatures are different.
---
 contrib/lisp/htmlize.el |   67 ++++++++++++++++++++++++++---------------------
 1 files changed, 37 insertions(+), 30 deletions(-)


--------------1.7.3.1.msysgit.0
Content-Type: text/x-patch; name="0001-Markup-on-same-line-as-text.patch"
Content-Transfer-Encoding: 8bit
Content-Disposition: attachment; 
filename="0001-Markup-on-same-line-as-text.patch"

diff --git a/contrib/lisp/htmlize.el b/contrib/lisp/htmlize.el
index 5f4cb5b..f952b80 100644
--- a/contrib/lisp/htmlize.el
+++ b/contrib/lisp/htmlize.el
@@ -1209,7 +1209,7 @@ property and by buffer overlays that specify `face'."
 ;; `htmlize-buffer-1' calls a number of "methods", which indirect to
 ;; the functions that depend on `htmlize-output-type'.  The currently
 ;; used methods are `doctype', `insert-head', `body-tag', and
-;; `insert-text'.  Not all output types define all methods.
+;; `get-markup'.  Not all output types define all methods.
 ;;
 ;; Methods are called either with (htmlize-method METHOD ARGS...) 
 ;; special form, or by accessing the function with
@@ -1347,18 +1347,18 @@ it's called with the same value of KEY.  All other 
times, the cached
   (insert htmlize-hyperlink-style
          "    -->\n    </style>\n"))
 
-(defun htmlize-css-insert-text (text fstruct-list buffer)
-  ;; Insert TEXT colored with FACES into BUFFER.  In CSS mode, this is
-  ;; easy: just nest the text in one <span class=...> tag for each
-  ;; face in FSTRUCT-LIST.
-  (dolist (fstruct fstruct-list)
-    (princ "<span class=\"" buffer)
-    (princ (htmlize-fstruct-css-name fstruct) buffer)
-    (princ "\">" buffer))
-  (princ text buffer)
-  (dolist (fstruct fstruct-list)
-    (ignore fstruct)                   ; shut up the byte-compiler
-    (princ "</span>" buffer)))
+(defun htmlize-css-get-markup (fstruct-list)
+  ;; Get markup for FACES. In CSS mode, this is easy; just create one
+  ;; <span class=...> tag for each face in FSTRUCT-LIST.
+  (cons
+   (mapconcat
+       (lambda (fs) (concat "<span class=\""
+                                                (htmlize-fstruct-css-name fs)
+                                                "\">"))
+       fstruct-list "")
+   (mapconcat
+       (lambda (fs) (ignore fs) "</span>")
+       fstruct-list "")))
 
 ;; `inline-css' output support.
 
@@ -1367,20 +1367,16 @@ it's called with the same value of KEY.  All other 
times, the cached
          (mapconcat #'identity (htmlize-css-specs (gethash 'default face-map))
                     " ")))
 
-(defun htmlize-inline-css-insert-text (text fstruct-list buffer)
+(defun htmlize-inline-css-get-markup (fstruct-list)
   (let* ((merged (htmlize-merge-faces fstruct-list))
         (style (htmlize-memoize
                 merged
                 (let ((specs (htmlize-css-specs merged)))
                   (and specs
                        (mapconcat #'identity (htmlize-css-specs merged) " 
"))))))
-    (when style
-      (princ "<span style=\"" buffer)
-      (princ style buffer)
-      (princ "\">" buffer))
-    (princ text buffer)
-    (when style
-      (princ "</span>" buffer))))
+       (if style
+               (cons (concat "<span style=\"" style "\">") "</span>")
+         (cons "" ""))))
 
 ;;; `font' tag based output support.
 
@@ -1390,12 +1386,12 @@ it's called with the same value of KEY.  All other 
times, the cached
            (htmlize-fstruct-foreground fstruct)
            (htmlize-fstruct-background fstruct))))
        
-(defun htmlize-font-insert-text (text fstruct-list buffer)
+(defun htmlize-font-get-markup (fstruct-list)
   ;; In `font' mode, we use the traditional HTML means of altering
   ;; presentation: <font> tag for colors, <b> for bold, <u> for
   ;; underline, and <strike> for strike-through.
-  (let* ((merged (htmlize-merge-faces fstruct-list))
-        (markup (htmlize-memoize
+  (let ((merged (htmlize-merge-faces fstruct-list)))
+        (htmlize-memoize
                  merged
                  (cons (concat
                         (and (htmlize-fstruct-foreground merged)
@@ -1410,10 +1406,19 @@ it's called with the same value of KEY.  All other 
times, the cached
                         (and (htmlize-fstruct-italicp merged)    "</i>")
                         (and (htmlize-fstruct-boldp merged)      "</b>")
                         (and (htmlize-fstruct-foreground merged) 
"</font>"))))))
-    (princ (car markup) buffer)
-    (princ text buffer)
-    (princ (cdr markup) buffer)))
 
+(defun split-trailing-newline (text)
+  "Split a trailing newline from the text"
+  (let ((length-minus-one (- (length text) 1)))
+       (if (and (>= length-minus-one 0) (char-equal (aref text 
length-minus-one) ?\n))
+               (cons (substring text 0 length-minus-one) "\n")
+         (cons text ""))))
+
+(defun add-markup (markup text)
+  "Interpose head and tail of markup on each side of text"
+  (let ((text-and-newline (split-trailing-newline text)))
+       (concat (car markup) (car text-and-newline) (cdr markup) (cdr 
text-and-newline))))
+
 (defun htmlize-buffer-1 ()
   ;; Internal function; don't call it from outside this file.  Htmlize
   ;; current buffer, writing the resulting HTML to a new buffer, and
@@ -1468,11 +1473,11 @@ it's called with the same value of KEY.  All other 
times, the cached
                "\n    ")
        (plist-put places 'content-start (point-marker))
        (insert "<pre>\n"))
-      (let ((insert-text-method
+      (let ((get-markup-method
             ;; Get the inserter method, so we can funcall it inside
             ;; the loop.  Not calling `htmlize-method' in the loop
             ;; body yields a measurable speed increase.
-            (htmlize-method-function 'insert-text))
+            (htmlize-method-function 'get-markup))
            ;; Declare variables used in loop body outside the loop
            ;; because it's faster to establish `let' bindings only
            ;; once.
@@ -1510,7 +1515,9 @@ it's called with the same value of KEY.  All other times, 
the cached
          (when (> (length text) 0)
            ;; Insert the text, along with the necessary markup to
            ;; represent faces in FSTRUCT-LIST.
-           (funcall insert-text-method text fstruct-list htmlbuf))
+               (let* ((markup (funcall get-markup-method fstruct-list))
+                          (markedup-text (add-markup markup text)))
+                 (princ markedup-text htmlbuf)))
          (goto-char next-change)))
 
       ;; Insert the epilog and post-process the buffer.

--------------1.7.3.1.msysgit.0--


_______________________________________________
Emacs-orgmode mailing list
Please use `Reply All' to send replies to the list.
Emacs-orgmode@gnu.org
http://lists.gnu.org/mailman/listinfo/emacs-orgmode

Reply via email to