%%% lp-elisp.tex --- Literate Programmin in Emacs Lisp

%% Copyright (C) 1997 -- 2002 Edward O'Connor <ted@oconnor.cx>

%% Author: Edward O'Connor <ted@oconnor.cx>

%% Permission is granted to copy, distribute and/or modify this
%% document under the terms of the GNU Free Documentation License,
%% Version 1.1 or any later version published by the Free Software
%% Foundation, with no Invariant Sections, with the Front-Cover
%% Texts being ``The Art of Configuring GNU Emacs, by Edward
%% O'Connor,'' and no Back-Cover Texts.

%% You may obtain a copy of the GNU Free Documentation License
%% from the Free Software Foundation by visiting
%% <URL:http://www.fsf.org/licenses/fdl.txt> or by writing to:

%% The Free Software Foundation, Inc.
%% 59 Temple Place - Suite 330
%% Boston, MA 02111-1307
%% USA

\chapter{Producing This Document}
\label{chap:meta}

\begin{elispEmacsLisponly}
;; Copyright (C) 1997 -- 2002 Edward O'Connor <ted@oconnor.cx>

;; Author: Edward O'Connor <ted@oconnor.cx>

;; This file 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 2 or,
;; at your option, any later version.

;; This file 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.

;; I'm sure you already have many copies of the GPL on your machine.
;; If you're using GNU Emacs, try typing  `C-h C-c' to bring it up.
;; If you're using XEmacs,  `C-h C-l' does this.
\end{elispEmacsLisponly}

\begin{elispEmacsLisponly}
;;; Commentary:
\end{elispEmacsLisponly}

\begin{elcomment}{0}
At one time, my \dotemacs\ file was a literate program made with this
poor-man's literate programming system for Emacs Lisp. It uses
\davidw's \elfile{two-mode-mode.el} to allow us to edit the files
using both \LaTeX\ and \elmode{emacs-lisp} major modes.

I've since switched to using \texttt{noweb}, and I recommend that you do
the same.

If you have the elisp but don't have the LaTeX source, you can find it
here:

        \selfhref{http://edward.oconnor.cx/elisp/lp-elisp.tex}
\end{elcomment}

Here's how to generate this elisp file:

\begin{elispTeXonly}
(lel-generate-elisp-file "lp-elisp" "Literate Programming in Emacs Lisp")
\end{elispTeXonly}

\begin{elispEmacsLisponly}
;;; History:
\end{elispEmacsLisponly}

\begin{elispEmacsLisponly}
;;; Code:
\end{elispEmacsLisponly}

\begin{elisp}
(require 'two-mode-mode)

(defun literate-emacs-lisp-mode ()
  "Treat the current buffer as a literate Emacs Lisp program."
  (interactive)
  (setq default-mode    '("LaTeX" latex-mode)
        second-modes     '(("Emacs-Lisp"
                            ;; We break up the values so as to not have strange
                            ;; behavior when editing this function.
                            (concat "\\begin{" "elisp") ; }
                            (concat "\\end{" "elisp")  ; }
                            emacs-lisp-mode)))
  (two-mode-mode))
\end{elisp}

(You may have noticed that every line of Elisp that has a dollar
sign has a matching dollar sign in a comment; this is so
font-locking doesn't go crazy when the buffer is in
\elmode{latex-mode}.)

For \LaTeX\ processing, we define several \TeX\ macros to make our
lives easier.

An elcomment is a section of text that should also be included in
the generated elisp file as a comment. The argument is an integer
specifying how many spaces to indent the generated comments.

\begin{tabular}{|l|}
\hline
\verb|\newenvironment{elcomment}[1]{}{}| \\
\hline
\end{tabular}

Elisp environments contain code that should appear both in the
book and in the generated elisp file.

\begin{tabular}{|l|}
\hline
\verb|\newenvironment{elisp}%| \\
\verb|  {\endgraf\noindent\verbatim}%| \\
\verb|  {\endverbatim}| \\
\hline
\end{tabular}

ElispTeXonly environments contain code that should appear only in
the book.

\begin{tabular}{|l|}
\hline
\verb|\newenvironment{elispTeXonly}%| \\
\verb|  {\endgraf\noindent\verbatim}%| \\
\verb|  {\endverbatim}| \\
\hline
\end{tabular}

ElispEmacsLisponly environments contain code that should appear
only in the generated .emacs file.

\begin{tabular}{|l|}
\hline
\verb|\let\elispEmacsLisponly=\comment| \\
\verb|\let\endelispEmacsLisponly=\endcomment| \\
\hline
\end{tabular}

Here's the elisp that dumps out elisp files from \LaTeX\ source
files. The function \elfun{lel-generate-dot-files} is the main
entry point, while \elfun{lel-generate-elisp-file} is the main
workhorse.

\begin{elisp}
(defun lel-dotemacs-comment-filter (line)
  "Filter LINE for inclusion as a comment in an elisp file."
  (let ((newline line))
    (mapc (lambda (match)
            (while (string-match (car match) newline)
              (setq newline (replace-match (cdr match) t t newline))))
          '(("{19}\\(\\\\\\)?"                          . " 19")
            ("{20}\\(\\\\\\)?"                          . " 20")
            ("{21}\\(\\\\\\)?"                          . " 21")
            ("{21.3}\\(\\\\\\)?"                        . " 21.3")
            ("\\\\Emacs\\(\\\\\\)?"                     . "GNU Emacs")
            ("\\\\Meadow\\(\\\\\\)?"                    . "Meadow")
            ("\\\\dotemacs\\(\\\\\\)?"                  . ".emacs")
            ("\\\\verb"                                 . "")
            ("|"                                        . "")
            ("{"                                        . " `")
            ("}\\(\\\\\\)?"                             . "'")
            ("\\\\el\\(var\\|fun\\|package\\|buffer\\)" . "")
            ("\\\\el\\(key\\|prog\\|file\\|mode\\)"     . "")
            ("\\\\XEmacs\\(\\\\\\)?"                    . "XEmacs")))
    newline))

(defun lel-generate-elisp-file (prefix docstring &optional el-name)
  "Generate PREFIX.el (or EL-NAME) from TeX in PREFIX.tex."
  (save-window-excursion
    (save-excursion
      (let* ((tex-file-name (concat prefix ".tex"))
             (elisp-file-name (or el-name (concat prefix ".el")))
             (inbuf (or (get-file-buffer tex-file-name)
                        (find-file tex-file-name)))
             outbuf
             (elisp (concat (format ";;; %s --- %s "
                                    elisp-file-name docstring)
                            "-*- mode: emacs-lisp -*-\n"))
             (in-elisp nil)
             (in-comment nil)
             (comment-indent-amount 0))

        ;; Generate the new elisp file. Note that there are
        ;; probably many more efficient ways of doing this.
        (with-temp-file elisp-file-name
          (setq outbuf (current-buffer))
          (set-buffer inbuf)
          (goto-char (point-min))
          (message (concat (format "Extracting elisp from %s "
                                   tex-file-name)
                           "(this may take a while)..."))
          (while (not (>= (point) (point-max)))
            (let ((line (buffer-substring-no-properties
                         (line-beginning-position)
                         (line-end-position))))
              (cond ((and in-elisp
                          (string-match
                           (concat "^\\\\en" "d{elisp[}E]")
                           line))
                     (setq elisp (concat elisp "\n"))
                     (setq in-elisp nil))

                    ((and (not in-elisp)
                          (string-match
                           (concat "^\\\\begi" "n{elisp[}E]")
                           line))
                     (setq in-elisp t))

                    ((and in-comment
                          (string-match
                           "^\\\\end{elcomment}$" ; $
                           line))
                     (setq elisp (concat elisp "\n"))
                     (setq in-comment nil))

                    ((and (not in-comment)
                          (string-match
                           "^\\\\begin{elcomment}{\\([0-9]\\)+}$" ; $
                           line))
                     (setq in-comment t
                           comment-indent-amount
                           (string-to-number
                            (substring line
                                       (match-beginning 1)
                                       (match-end 1)))))

                    (in-comment
                     (setq elisp (concat elisp
                                         "\n"
                                         (make-string
                                          comment-indent-amount
                                          ?\ )
                                         ";; "
                                         (lel-dotemacs-comment-filter line))))

                    (in-elisp
                     (setq elisp (concat elisp "\n" line))))

              (forward-line 1)))
          (set-buffer outbuf)
          (insert elisp "\n")
          (delete-trailing-whitespace))))))

(provide 'lp-elisp)
\end{elisp}

\begin{elispEmacsLisponly}
;;; lp-elisp.el ends here
\end{elispEmacsLisponly}

%% Local Variables:
%% mode: literate-emacs-lisp
%% coding: iso-8859-1-unix
%% End:

%%% lp-elisp.tex ends here
