emacs-orgmode@gnu.org archives
 help / color / mirror / code / Atom feed
From: Roland Kaufmann <roland.kaufmann@gmail.com>
To: hniksic@xemacs.org
Cc: emacs-orgmode@gnu.org
Subject: [PATCH] Markup on same line as text
Date: Thu, 06 Jan 2011 23:12:11 +0100	[thread overview]
Message-ID: <4D263E3B.5030407@gmail.com> (raw)

[-- Attachment #1: Type: text/plain, Size: 1991 bytes --]

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.

[-- Attachment #2: 0001-Markup-on-same-line-as-text.patch --]
[-- Type: text/plain, Size: 7232 bytes --]

From 86f1508f58dd304471d768481944d34e220e24f1 Mon Sep 17 00:00:00 2001
From: Roland Kaufmann <rlndkfmn+orgmode@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 "")))
 \f
 ;; `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 "" ""))))
 \f
 ;;; `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)))
 \f
+(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--



[-- Attachment #3: Type: text/plain, Size: 201 bytes --]

_______________________________________________
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	other threads:[~2011-01-06 22:12 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-01-06 22:12 Roland Kaufmann [this message]
2011-02-16 20:04 ` [PATCH] Markup on same line as text Hrvoje Niksic
2011-02-16 21:53   ` Roland Kaufmann
2011-02-17 21:58 ` Hrvoje Niksic
2011-02-19 14:26   ` Roland Kaufmann
2011-02-19 23:49     ` Hrvoje Niksic
2011-02-26  9:39     ` Bastien
2011-02-27 21:09       ` Roland Kaufmann

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.orgmode.org/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4D263E3B.5030407@gmail.com \
    --to=roland.kaufmann@gmail.com \
    --cc=emacs-orgmode@gnu.org \
    --cc=hniksic@xemacs.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).