diff options
| -rw-r--r-- | lisp/ChangeLog | 22 | ||||
| -rw-r--r-- | lisp/htmlfontify.el | 159 |
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 @@ | |||
| 1 | 2012-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 | |||
| 1 | 2012-03-17 Eli Zaretskii <eliz@gnu.org> | 23 | 2012-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. |
| 1113 | and return a CSS style specification.\n | 1120 | See also `hfy-face-to-css'." |
| 1114 | See 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. | ||
| 1136 | The signature of the handler is of the form \(lambda (FN) ...\). | ||
| 1137 | FN is a font or `defface' specification (cf | ||
| 1138 | `face-attr-construct'). The handler should return a cons cell of | ||
| 1139 | the form (STYLE-NAME . STYLE-SPEC). | ||
| 1140 | |||
| 1141 | The default handler is `hfy-face-to-css-default'. | ||
| 1142 | |||
| 1143 | See 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'. |
| 1332 | If `hfy-user-sheet-assoc' is currently bound then use it to | ||
| 1333 | collect new styles discovered during this run. Otherwise create | ||
| 1334 | a 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. | ||
| 1576 | Insert \"<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. | ||
| 1589 | Insert \"</span>\". See `hfy-end-span-handler' for more | ||
| 1590 | information." | ||
| 1591 | (insert "</span>")) | ||
| 1592 | |||
| 1593 | (defvar hfy-begin-span-handler 'hfy-begin-span | ||
| 1594 | "Handler to begin a span of text. | ||
| 1595 | The signature of the handler is \(lambda (STYLE TEXT-BLOCK | ||
| 1596 | TEXT-ID TEXT-BEGINS-BLOCK-P) ...\). The handler must insert | ||
| 1597 | appropriate tags to begin a span of text. | ||
| 1598 | |||
| 1599 | STYLE is the name of the style that begins at point. It is | ||
| 1600 | derived from the face attributes as part of `hfy-face-to-css' | ||
| 1601 | callback. The other arguments TEXT-BLOCK, TEXT-ID, | ||
| 1602 | TEXT-BEGINS-BLOCK-P are non-nil only if the buffer contains | ||
| 1603 | invisible text. | ||
| 1604 | |||
| 1605 | TEXT-BLOCK is a string that identifies a single chunk of visible | ||
| 1606 | or invisible text of which the current position is a part. For | ||
| 1607 | visible portions, it's value is \"nil\". For invisible portions, | ||
| 1608 | it's value is computed as part of `hfy-invisible-name'. | ||
| 1609 | |||
| 1610 | TEXT-ID marks a unique position within a block. It is set to | ||
| 1611 | value of `point' at the current buffer position. | ||
| 1612 | |||
| 1613 | TEXT-BEGINS-BLOCK-P is a boolean and is non-nil if the current | ||
| 1614 | span also begins a invisible portion of text. | ||
| 1615 | |||
| 1616 | An implementation can use TEXT-BLOCK, TEXT-ID, | ||
| 1617 | TEXT-BEGINS-BLOCK-P to implement fold/unfold-on-mouse-click like | ||
| 1618 | behaviour. | ||
| 1619 | |||
| 1620 | The default handler is `hfy-begin-span'.") | ||
| 1621 | |||
| 1622 | (defvar hfy-end-span-handler 'hfy-end-span | ||
| 1623 | "Handler to end a span of text. | ||
| 1624 | The signature of the handler is \(lambda () ...\). The handler | ||
| 1625 | must insert appropriate tags to end a span of text. | ||
| 1626 | |||
| 1627 | The 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'. |
| 1552 | SRCDIR, if set, is the directory being htmlfontified. | 1631 | SRCDIR, 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. | ||
| 1798 | It is assumed that STRING has text properties that allow it to be | ||
| 1799 | fontified. 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) |