;;; muse-groff.el --- publish groff -mom -mwww files ;; Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 ;; Free Software Foundation, Inc. ;; Author: Andrew J. Korty (ajk AT iu DOT edu) ;; Date: Tue 5-Jul-2005 ;; This file is part of Emacs Muse. It is not part of GNU Emacs. ;; Emacs Muse is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published ;; by the Free Software Foundation; either version 3, or (at your ;; option) any later version. ;; Emacs Muse is distributed in the hope that it will be useful, but ;; WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ;; General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with Emacs Muse; see the file COPYING. If not, write to the ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, ;; Boston, MA 02110-1301, USA. ;;; Commentary: ;;; Contributors: ;;; Code: ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; Muse Publishing Using groff -mom -mwww ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (require 'muse-publish) (defgroup muse-groff nil "Rules for marking up a Muse file with groff -mom -mwww macros." :group 'muse-publish) (defcustom muse-groff-extension ".groff" "Default file extension for publishing groff -mom -mwww files." :type 'string :group 'muse-groff) (defcustom muse-groff-pdf-extension ".pdf" "Default file extension for publishing groff -mom -mwww files to PDF." :type 'string :group 'muse-groff) (defcustom muse-groff-header ".TITLE \"(muse-publishing-directive \"title\")\" .SUBTITLE \"(muse-publishing-directive \"date\")\" .AUTHOR \"(muse-publishing-directive \"author\")\" .PRINTSTYLE TYPESET .de list . LIST \\$1 . SHIFT_LIST \\$2 .. .PARA_INDENT 0 .START (and muse-publish-generate-contents \".TOC\n\")\n" "Header used for publishing groff -mom -mwww files." :type '(choice string file) :group 'muse-groff) (defcustom muse-groff-footer " " "Footer used for publishing groff -mom -mwww files." :type '(choice string file) :group 'muse-groff) (defcustom muse-groff-markup-regexps `((10400 ,(concat "\\(\n\\)?\n" "\\([" muse-regexp-blank "]*\n\\)+\\(<\\(blockquote\\|center\\)>\n\\)?") 0 muse-groff-markup-paragraph)) "List of markup regexps for identifying regions in a Muse page. For more on the structure of this list, see `muse-publish-markup-regexps'." :type '(repeat (choice (list :tag "Markup rule" integer (choice regexp symbol) integer (choice string function symbol)) function)) :group 'muse-groff) (defcustom muse-groff-markup-functions '((table . muse-groff-markup-table)) "An alist of style types to custom functions for that kind of text. For more on the structure of this list, see `muse-publish-markup-functions'." :type '(alist :key-type symbol :value-type function) :group 'muse-groff) (defcustom muse-groff-markup-tags '() "A list of tag specifications, for specially marking up GROFF." :type '(repeat (list (string :tag "Markup tag") (boolean :tag "Expect closing tag" :value t) (boolean :tag "Parse attributes" :value nil) (boolean :tag "Nestable" :value nil) function)) :group 'muse-groff) (defcustom muse-groff-markup-strings `((image-with-desc . "\n.MPIMG -R %s.%s\n") (image . "\n.MPIMG -R %s.%s\n") (image-link . "\n.\\\" %s\n.MPIMG -R %s.%s") (url . "\n.URL %s %s\n\\z") (link . "\n.URL %s %s\n\\z") (email-addr . "\f[C]%s\f[]") (emdash . "\\(em") (rule . "\n.RULE\n") (no-break-space . "\\h") (line-break . "\\p") (enddots . "....") (dots . "...") ;; (part . "\\part{") ;; (part-end . "}") ;; (chapter . "\\chapter{") ;; (chapter-end . "}") (section . ".HEAD \"") (section-end . "\"") (subsection . ".SUBHEAD \"") (subsection-end . "\"") (subsubsection . ".PARAHEAD \"") (subsubsection-end . "\"") ;; (footnote . "\\c\n.FOOTNOTE\n") ;; (footnote-end . "\n.FOOTNOTE OFF\n") ;; (footnotemark . "\\footnotemark[%d]") ;; (footnotetext . "\\footnotetext[%d]{") ;; (footnotetext-end . "}") (begin-underline . "\n.UNDERSCORE \"") (end-underline . "\"\n") (begin-literal . "\\fC") (end-literal . "\\fP") (begin-emph . "\\fI") (end-emph . "\\fP") (begin-more-emph . "\\fB") (end-more-emph . "\\fP") (begin-most-emph . "\\f(BI") (end-most-emph . "\\fP") (begin-verse . ".QUOTE") (end-verse . ".QUOTE OFF") (begin-center . "\n.CENTER\n") (end-center . "\n.QUAD L\n") (begin-example . ,(concat ".QUOTE_FONT CR\n.QUOTE_INDENT 1\n"".QUOTE_SIZE -2\n" ".UNDERLINE_QUOTES OFF\n.QUOTE")) (end-example . ".QUOTE OFF") (begin-quote . ".BLOCKQUOTE") (end-quote . ".BLOCKQUOTE OFF") (begin-cite . "") (begin-cite-author . "") (begin-cite-year . "") (end-cite . "") (begin-uli . ".list BULLET\n.SHIFT_LIST 2m\n.ITEM\n") (end-uli . "\n.LIST OFF") (begin-oli . ".list DIGIT\n.SHIFT_LIST 2m\n.ITEM\n") (end-oli . "\n.LIST OFF") (begin-ddt . "\\fB") (begin-dde . "\\fP\n.IR 4P\n") (end-ddt . ".IRX CLEAR")) "Strings used for marking up text. These cover the most basic kinds of markup, the handling of which differs little between the various styles." :type '(alist :key-type symbol :value-type string) :group 'muse-groff) (defcustom muse-groff-markup-specials '((?\\ . "\\e")) "A table of characters which must be represented specially." :type '(alist :key-type character :value-type string) :group 'muse-groff) (defun muse-groff-markup-paragraph () (let ((end (copy-marker (match-end 0) t))) (goto-char (1+ (match-beginning 0))) (delete-region (point) end) (unless (looking-at "\.\\(\\(\\(SUB\\|PARA\\)?HEAD \\)\\|RULE$\\)") (muse-insert-markup ".ALD .5v\n.PP\n.ne 2\n")))) (defun muse-groff-protect-leading-chars () "Protect leading periods and apostrophes from being interpreted as command characters." (while (re-search-forward "^[.']" nil t) (replace-match "\\\\&\\&" t))) (defun muse-groff-concat-lists () "Join like lists." (let ((type "") arg begin) (while (re-search-forward "^\.LIST[ \t]+\\(.*\\)\n" nil t) (setq arg (match-string 1)) (if (string= arg "OFF") (setq begin (match-beginning 0)) (if (and begin (string= type arg)) (delete-region begin (match-end 0)) (setq type arg begin 0)))))) (defun muse-groff-fixup-dquotes () "Fixup double quotes." (let ((open t)) (while (search-forward "\"" nil t) (unless (get-text-property (match-beginning 0) 'read-only) (if (and (bolp) (eq (char-before) ?\n)) (setq open t)) (if open (progn (replace-match "``") (setq open nil)) (replace-match "''") (setq open t)))))) (defun muse-groff-prepare-buffer () (goto-char (point-min)) (muse-groff-protect-leading-chars)) (defun muse-groff-munge-buffer () (goto-char (point-min)) (muse-groff-concat-lists)) (defun muse-groff-pdf-browse-file (file) (shell-command (concat "open " file))) (defun muse-groff-pdf-generate (file output-path final-target) (muse-publish-transform-output file output-path final-target "PDF" (function (lambda (file output-path) (let ((command (format (concat "file=%s; ext=%s; cd %s && cp $file$ext $file.ref && " "groff -mom -mwww -t $file$ext > $file.ps && " "pstopdf $file.ps") (file-name-sans-extension file) muse-groff-extension (file-name-directory output-path)))) (shell-command command)))) ".ps")) ;;; Register the Muse GROFF Publisher (muse-define-style "groff" :suffix 'muse-groff-extension :regexps 'muse-groff-markup-regexps ;;; :functions 'muse-groff-markup-functions :strings 'muse-groff-markup-strings :tags 'muse-groff-markup-tags :specials 'muse-groff-markup-specials :before 'muse-groff-prepare-buffer :before-end 'muse-groff-munge-buffer :header 'muse-groff-header :footer 'muse-groff-footer :browser 'find-file) (muse-derive-style "groff-pdf" "groff" :final 'muse-groff-pdf-generate :browser 'muse-groff-pdf-browse-file :osuffix 'muse-groff-pdf-extension) (provide 'muse-groff) ;;; muse-groff.el ends here ;; ;; Local Variables: ;; indent-tabs-mode: nil ;; End: