aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJambunathan K2012-03-17 22:03:54 +0800
committerChong Yidong2012-03-17 22:03:54 +0800
commitf02ff80d330e6dc19682bdf162ccdcee66e59216 (patch)
treee937bd36af287b8d8ada9e82987f7dfdb4433bf3
parent986bd52a31d3ef5a9cc35ecfb8463d758d1e5e6c (diff)
downloademacs-f02ff80d330e6dc19682bdf162ccdcee66e59216.tar.gz
emacs-f02ff80d330e6dc19682bdf162ccdcee66e59216.zip
* htmlfontify.el: Add support for code block fontification
for ODT export. (hfy-optimisations): Define new option `body-text-only' (hfy-fontify-buffer): Honor above setting. (hfy-begin-span, hfy-end-span): New routines factored out form `hfy-fontify-buffer'. (hfy-begin-span-handler, hfy-end-span-handler): New variables that permit insertion of custom tags. (hfy-fontify-buffer): Use above handlers. (hfy-face-to-css-default): Same as the earlier `hfy-face-to-css'. (hfy-face-to-css): Re-defined to be a variable. (hfy-compile-stylesheet): Modified. Allow stylesheet to be built over multiple runs. This is made possible by having the caller let bind a special variable `hfy-user-sheet-assoc'. (htmlfontify-string): New defun. (hfy-compile-face-map): Make sure that the last char in the buffer is correctly fontified. (hfy-face-resolve-face): Whitespace only change. Fixes: debbugs:9914
-rw-r--r--lisp/ChangeLog22
-rw-r--r--lisp/htmlfontify.el159
2 files changed, 147 insertions, 34 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog
index 3be8553dd69..094c5697379 100644
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -1,3 +1,25 @@
12012-03-13 Jambunathan K <kjambunathan@gmail.com>
2
3 * htmlfontify.el: Add support for code block fontification for ODT
4 export (Bug #9914).
5 (hfy-optimisations): Define new option
6 `body-text-only'
7 (hfy-fontify-buffer): Honor above setting.
8 (hfy-begin-span, hfy-end-span): New routines factored out form
9 `hfy-fontify-buffer'.
10 (hfy-begin-span-handler, hfy-end-span-handler): New variables
11 that permit insertion of custom tags.
12 (hfy-fontify-buffer): Use above handlers.
13 (hfy-face-to-css-default): Same as the earlier `hfy-face-to-css'.
14 (hfy-face-to-css): Re-defined to be a variable.
15 (hfy-compile-stylesheet): Modified. Allow stylesheet to be built
16 over multiple runs. This is made possible by having the caller let
17 bind a special variable `hfy-user-sheet-assoc'.
18 (htmlfontify-string): New defun.
19 (hfy-compile-face-map): Make sure that the last char in the
20 buffer is correctly fontified.
21 (hfy-face-resolve-face): Whitespace only change.
22
12012-03-17 Eli Zaretskii <eliz@gnu.org> 232012-03-17 Eli Zaretskii <eliz@gnu.org>
2 24
3 * textmodes/ispell.el (ispell-get-decoded-string): Make the error 25 * textmodes/ispell.el (ispell-get-decoded-string): Make the error
diff --git a/lisp/htmlfontify.el b/lisp/htmlfontify.el
index b94d4293fa7..fbf7a672ff6 100644
--- a/lisp/htmlfontify.el
+++ b/lisp/htmlfontify.el
@@ -450,6 +450,12 @@ and so on."
450 keep-overlays : More of a bell (or possibly whistle) than an 450 keep-overlays : More of a bell (or possibly whistle) than an
451 optimization - If on, preserve overlay highlighting 451 optimization - If on, preserve overlay highlighting
452 (cf ediff or goo-font-lock) as well as basic faces.\n 452 (cf ediff or goo-font-lock) as well as basic faces.\n
453 body-text-only : Emit only body-text. In concrete terms,
454 1. Suppress calls to `hfy-page-header'and
455 `hfy-page-footer'
456 2. Pretend that `div-wrapper' option above is
457 turned off
458 3. Don't enclose output in <pre> </pre> tags
453 And the following are planned but not yet available:\n 459 And the following are planned but not yet available:\n
454 kill-context-leak : Suppress hyperlinking between files highlighted by 460 kill-context-leak : Suppress hyperlinking between files highlighted by
455 different modes.\n 461 different modes.\n
@@ -463,7 +469,8 @@ which can never slow you down, but may result in incomplete fontification."
463 (const :tag "skip-refontification" skip-refontification) 469 (const :tag "skip-refontification" skip-refontification)
464 (const :tag "kill-context-leak" kill-context-leak ) 470 (const :tag "kill-context-leak" kill-context-leak )
465 (const :tag "div-wrapper" div-wrapper ) 471 (const :tag "div-wrapper" div-wrapper )
466 (const :tag "keep-overlays" keep-overlays )) 472 (const :tag "keep-overlays" keep-overlays )
473 (const :tag "body-text-only" body-text-only ))
467 :group 'htmlfontify 474 :group 'htmlfontify
468 :tag "optimizations") 475 :tag "optimizations")
469 476
@@ -1044,7 +1051,7 @@ haven't encountered them yet. Returns a `hfy-style-assoc'."
1044 ((facep fn) 1051 ((facep fn)
1045 (hfy-face-attr-for-class fn hfy-display-class)) 1052 (hfy-face-attr-for-class fn hfy-display-class))
1046 ((and (symbolp fn) 1053 ((and (symbolp fn)
1047 (facep (symbol-value fn))) 1054 (facep (symbol-value fn)))
1048 ;; Obsolete faces like `font-lock-reference-face' are defined as 1055 ;; Obsolete faces like `font-lock-reference-face' are defined as
1049 ;; aliases for another face. 1056 ;; aliases for another face.
1050 (hfy-face-attr-for-class (symbol-value fn) hfy-display-class)) 1057 (hfy-face-attr-for-class (symbol-value fn) hfy-display-class))
@@ -1108,10 +1115,9 @@ See also `hfy-face-to-style-i', `hfy-flatten-style'."
1108 1115
1109;; construct an assoc of (stripped-name . "{ css-stuff-here }") pairs 1116;; construct an assoc of (stripped-name . "{ css-stuff-here }") pairs
1110;; from a face: 1117;; from a face:
1111(defun hfy-face-to-css (fn) 1118(defun hfy-face-to-css-default (fn)
1112 "Take FN, a font or `defface' specification (cf `face-attr-construct') 1119 "Default handler for mapping faces to styles.
1113and return a CSS style specification.\n 1120See also `hfy-face-to-css'."
1114See also `hfy-face-to-style'."
1115 ;;(message "hfy-face-to-css");;DBUG 1121 ;;(message "hfy-face-to-css");;DBUG
1116 (let* ((css-list (hfy-face-to-style fn)) 1122 (let* ((css-list (hfy-face-to-style fn))
1117 (seen nil) 1123 (seen nil)
@@ -1125,6 +1131,17 @@ See also `hfy-face-to-style'."
1125 css-list))) 1131 css-list)))
1126 (cons (hfy-css-name fn) (format "{%s}" (apply 'concat css-text)))) ) 1132 (cons (hfy-css-name fn) (format "{%s}" (apply 'concat css-text)))) )
1127 1133
1134(defvar hfy-face-to-css 'hfy-face-to-css-default
1135 "Handler for mapping faces to styles.
1136The signature of the handler is of the form \(lambda (FN) ...\).
1137FN is a font or `defface' specification (cf
1138`face-attr-construct'). The handler should return a cons cell of
1139the form (STYLE-NAME . STYLE-SPEC).
1140
1141The default handler is `hfy-face-to-css-default'.
1142
1143See also `hfy-face-to-style'.")
1144
1128(defalias 'hfy-prop-invisible-p 1145(defalias 'hfy-prop-invisible-p
1129 (if (fboundp 'invisible-p) #'invisible-p 1146 (if (fboundp 'invisible-p) #'invisible-p
1130 (lambda (prop) 1147 (lambda (prop)
@@ -1311,20 +1328,27 @@ The plists are returned in descending priority order."
1311 1328
1312;; construct an assoc of (face-name . (css-name . "{ css-style }")) elements: 1329;; construct an assoc of (face-name . (css-name . "{ css-style }")) elements:
1313(defun hfy-compile-stylesheet () 1330(defun hfy-compile-stylesheet ()
1314 "Trawl the current buffer, construct and return a `hfy-sheet-assoc'." 1331 "Trawl the current buffer, construct and return a `hfy-sheet-assoc'.
1332If `hfy-user-sheet-assoc' is currently bound then use it to
1333collect new styles discovered during this run. Otherwise create
1334a new assoc."
1315 ;;(message "hfy-compile-stylesheet");;DBUG 1335 ;;(message "hfy-compile-stylesheet");;DBUG
1316 (let ((pt (point-min)) 1336 (let ((pt (point-min))
1317 ;; Make the font stack stay: 1337 ;; Make the font stack stay:
1318 ;;(hfy-tmpfont-stack nil) 1338 ;;(hfy-tmpfont-stack nil)
1319 (fn nil) 1339 (fn nil)
1320 (style nil)) 1340 (style (and (boundp 'hfy-user-sheet-assoc) hfy-user-sheet-assoc)))
1321 (save-excursion 1341 (save-excursion
1322 (goto-char pt) 1342 (goto-char pt)
1323 (while (< pt (point-max)) 1343 (while (< pt (point-max))
1324 (if (and (setq fn (hfy-face-at pt)) (not (assoc fn style))) 1344 (if (and (setq fn (hfy-face-at pt)) (not (assoc fn style)))
1325 (push (cons fn (hfy-face-to-css fn)) style)) 1345 (push (cons fn (funcall hfy-face-to-css fn)) style))
1326 (setq pt (next-char-property-change pt))) ) 1346 (setq pt (next-char-property-change pt))))
1327 (push (cons 'default (hfy-face-to-css 'default)) style))) 1347 (unless (assoc 'default style)
1348 (push (cons 'default (funcall hfy-face-to-css 'default)) style))
1349 (when (boundp 'hfy-user-sheet-assoc)
1350 (setq hfy-user-sheet-assoc style))
1351 style))
1328 1352
1329(defun hfy-fontified-p () 1353(defun hfy-fontified-p ()
1330 "`font-lock' doesn't like to say it's been fontified when in batch 1354 "`font-lock' doesn't like to say it's been fontified when in batch
@@ -1425,7 +1449,7 @@ Returns a modified copy of FACE-MAP."
1425 (setq pt (next-char-property-change pt)) 1449 (setq pt (next-char-property-change pt))
1426 (setq pt-narrow (+ offset pt))) 1450 (setq pt-narrow (+ offset pt)))
1427 (if (and map (not (eq 'end (cdar map)))) 1451 (if (and map (not (eq 'end (cdar map))))
1428 (push (cons (- (point-max) (point-min)) 'end) map))) 1452 (push (cons (1+ (- (point-max) (point-min))) 'end) map)))
1429 (if (hfy-opt 'merge-adjacent-tags) (hfy-merge-adjacent-spans map) map))) 1453 (if (hfy-opt 'merge-adjacent-tags) (hfy-merge-adjacent-spans map) map)))
1430 1454
1431(defun hfy-buffer () 1455(defun hfy-buffer ()
@@ -1547,6 +1571,61 @@ Do not record undo information during evaluation of BODY."
1547 (remove-text-properties (point-min) (point-max) 1571 (remove-text-properties (point-min) (point-max)
1548 '(hfy-show-trailing-whitespace))))) 1572 '(hfy-show-trailing-whitespace)))))
1549 1573
1574(defun hfy-begin-span (style text-block text-id text-begins-block-p)
1575 "Default handler to begin a span of text.
1576Insert \"<span class=\"STYLE\" ...>\". See
1577`hfy-begin-span-handler' for more information."
1578 (when text-begins-block-p
1579 (insert
1580 (format "<span onclick=\"toggle_invis('%s');\">…</span>" text-block)))
1581
1582 (insert
1583 (if text-block
1584 (format "<span class=\"%s\" id=\"%s-%d\">" style text-block text-id)
1585 (format "<span class=\"%s\">" style))))
1586
1587(defun hfy-end-span ()
1588 "Default handler to end a span of text.
1589Insert \"</span>\". See `hfy-end-span-handler' for more
1590information."
1591 (insert "</span>"))
1592
1593(defvar hfy-begin-span-handler 'hfy-begin-span
1594 "Handler to begin a span of text.
1595The signature of the handler is \(lambda (STYLE TEXT-BLOCK
1596TEXT-ID TEXT-BEGINS-BLOCK-P) ...\). The handler must insert
1597appropriate tags to begin a span of text.
1598
1599STYLE is the name of the style that begins at point. It is
1600derived from the face attributes as part of `hfy-face-to-css'
1601callback. The other arguments TEXT-BLOCK, TEXT-ID,
1602TEXT-BEGINS-BLOCK-P are non-nil only if the buffer contains
1603invisible text.
1604
1605TEXT-BLOCK is a string that identifies a single chunk of visible
1606or invisible text of which the current position is a part. For
1607visible portions, it's value is \"nil\". For invisible portions,
1608it's value is computed as part of `hfy-invisible-name'.
1609
1610TEXT-ID marks a unique position within a block. It is set to
1611value of `point' at the current buffer position.
1612
1613TEXT-BEGINS-BLOCK-P is a boolean and is non-nil if the current
1614span also begins a invisible portion of text.
1615
1616An implementation can use TEXT-BLOCK, TEXT-ID,
1617TEXT-BEGINS-BLOCK-P to implement fold/unfold-on-mouse-click like
1618behaviour.
1619
1620The default handler is `hfy-begin-span'.")
1621
1622(defvar hfy-end-span-handler 'hfy-end-span
1623 "Handler to end a span of text.
1624The signature of the handler is \(lambda () ...\). The handler
1625must insert appropriate tags to end a span of text.
1626
1627The default handler is `hfy-end-span'.")
1628
1550(defun hfy-fontify-buffer (&optional srcdir file) 1629(defun hfy-fontify-buffer (&optional srcdir file)
1551 "Implement the guts of `htmlfontify-buffer'. 1630 "Implement the guts of `htmlfontify-buffer'.
1552SRCDIR, if set, is the directory being htmlfontified. 1631SRCDIR, if set, is the directory being htmlfontified.
@@ -1634,23 +1713,19 @@ FILE, if set, is the file name."
1634 (or (get-text-property pt 'hfy-linkp) 1713 (or (get-text-property pt 'hfy-linkp)
1635 (get-text-property pt 'hfy-endl ))) 1714 (get-text-property pt 'hfy-endl )))
1636 (if (eq 'end fn) 1715 (if (eq 'end fn)
1637 (insert "</span>") 1716 (funcall hfy-end-span-handler)
1638 (if (not (and srcdir file)) 1717 (if (not (and srcdir file))
1639 nil 1718 nil
1640 (when move-link 1719 (when move-link
1641 (remove-text-properties (point) (1+ (point)) '(hfy-endl nil)) 1720 (remove-text-properties (point) (1+ (point)) '(hfy-endl nil))
1642 (put-text-property pt (1+ pt) 'hfy-endl t) )) 1721 (put-text-property pt (1+ pt) 'hfy-endl t) ))
1643 ;; if we have invisible blocks, we need to do some extra magic: 1722 ;; if we have invisible blocks, we need to do some extra magic:
1644 (if invis-ranges 1723 (funcall hfy-begin-span-handler
1645 (let ((iname (hfy-invisible-name pt invis-ranges)) 1724 (hfy-lookup fn css-sheet)
1646 (fname (hfy-lookup fn css-sheet ))) 1725 (and invis-ranges
1647 (when (assq pt invis-ranges) 1726 (format "%s" (hfy-invisible-name pt invis-ranges)))
1648 (insert 1727 (and invis-ranges pt)
1649 (format "<span onclick=\"toggle_invis('%s');\">" iname)) 1728 (and invis-ranges (assq pt invis-ranges)))
1650 (insert "…</span>"))
1651 (insert
1652 (format "<span class=\"%s\" id=\"%s-%d\">" fname iname pt)))
1653 (insert (format "<span class=\"%s\">" (hfy-lookup fn css-sheet))))
1654 (if (not move-link) nil 1729 (if (not move-link) nil
1655 ;;(message "removing prop2 @ %d" (point)) 1730 ;;(message "removing prop2 @ %d" (point))
1656 (if (remove-text-properties (point) (1+ (point)) '(hfy-endl nil)) 1731 (if (remove-text-properties (point) (1+ (point)) '(hfy-endl nil))
@@ -1698,23 +1773,39 @@ FILE, if set, is the file name."
1698 ;; so we have to do this after we use said properties: 1773 ;; so we have to do this after we use said properties:
1699 ;; (message "munging dangerous characters") 1774 ;; (message "munging dangerous characters")
1700 (hfy-html-dekludge-buffer) 1775 (hfy-html-dekludge-buffer)
1701 ;; insert the stylesheet at the top: 1776 (unless (hfy-opt 'body-text-only)
1702 (goto-char (point-min)) 1777 ;; insert the stylesheet at the top:
1703 ;;(message "inserting stylesheet") 1778 (goto-char (point-min))
1704 (insert (hfy-sprintf-stylesheet css-sheet file)) 1779
1705 (if (hfy-opt 'div-wrapper) (insert "<div class=\"default\">")) 1780 ;;(message "inserting stylesheet")
1706 (insert "\n<pre>") 1781 (insert (hfy-sprintf-stylesheet css-sheet file))
1707 (goto-char (point-max)) 1782
1708 (insert "</pre>\n") 1783 (if (hfy-opt 'div-wrapper) (insert "<div class=\"default\">"))
1709 (if (hfy-opt 'div-wrapper) (insert "</div>")) 1784 (insert "\n<pre>")
1710 ;;(message "inserting footer") 1785 (goto-char (point-max))
1711 (insert (funcall hfy-page-footer file)) 1786 (insert "</pre>\n")
1787 (if (hfy-opt 'div-wrapper) (insert "</div>"))
1788 ;;(message "inserting footer")
1789 (insert (funcall hfy-page-footer file)))
1712 ;; call any post html-generation hooks: 1790 ;; call any post html-generation hooks:
1713 (run-hooks 'hfy-post-html-hooks) 1791 (run-hooks 'hfy-post-html-hooks)
1714 ;; return the html buffer 1792 ;; return the html buffer
1715 (set-buffer-modified-p nil) 1793 (set-buffer-modified-p nil)
1716 html-buffer)) 1794 html-buffer))
1717 1795
1796(defun htmlfontify-string (string)
1797 "Take a STRING and return a fontified version of it.
1798It is assumed that STRING has text properties that allow it to be
1799fontified. This is a simple convenience wrapper around
1800`htmlfontify-buffer'."
1801 (let* ((hfy-optimisations-1 (copy-sequence hfy-optimisations))
1802 (hfy-optimisations (add-to-list 'hfy-optimisations-1
1803 'skip-refontification)))
1804 (with-temp-buffer
1805 (insert string)
1806 (htmlfontify-buffer)
1807 (buffer-string))))
1808
1718(defun hfy-force-fontification () 1809(defun hfy-force-fontification ()
1719 "Try to force font-locking even when it is optimized away." 1810 "Try to force font-locking even when it is optimized away."
1720 (run-hooks 'hfy-init-kludge-hook) 1811 (run-hooks 'hfy-init-kludge-hook)