1 #LyX 1.5.0svn created this file. For more info see http://www.lyx.org/
5 \textclass literate-article
8 % This relaxes the noweb constraint that chunks are
9 % never broken across pages.
11 % This is from the noweb FAQ
13 \def\nwendcode{\endtrivlist \endgroup}
14 \let\nwdocspar=\smallbreak
17 \inputencoding default
20 \font_typewriter default
21 \font_default_family default
27 \paperfontsize default
35 \paperorientation portrait
38 \paragraph_separation indent
40 \quotes_language english
43 \paperpagestyle default
44 \tracking_changes false
60 Sylvan <kayvan@sylvan.com>
68 \begin_layout Abstract
70 This document describes and implements a perl script for importing noweb
74 \begin_layout Standard
77 \begin_inset LatexCommand tableofcontents
83 \begin_layout Standard
96 \begin_layout Standard
98 Since version 1.0.1, LyX now supports Literate Programming using
103 This addition to LyX made it very pleasant to write programs in the literate
104 style (like this one).
105 In addition to being able to write new literate programs, it would be quite
110 code could be imported into LyX in some fashion.
111 That's where this program comes in.
114 \begin_layout Standard
135 # Copyright (C) 1999 Kayvan A.
136 Sylvan <kayvan@sylvan.com>
138 # You are free to use and modify this code under the terms of
140 # the GNU General Public Licence version 2 or later.
144 # Written with assistance from:
146 # Edmar Wienskoski Jr.
147 <edmar-w-jr@technologist.com>
149 # Amir Karger <karger@post.harvard.edu>
153 # $Id: noweb2lyx.lyx,v 1.5 2005/07/18 09:42:27 jamatos Exp $
157 # NOTE: This file was automatically generated from noweb2lyx.lyx using noweb.
161 <<Setup variables from user supplied args>>
165 <<Convert noweb to LyX>>
170 \begin_layout Section
172 The Noweb file defined
175 \begin_layout Standard
181 file is a collection of documentation and code chunks.
182 Documentation chunks simply start with an ``@'' and have no name:
185 \begin_layout LyX-Code
187 @ Here is some documentation.
189 We can do arbitrary LaTeX code here.
195 \begin_layout Standard
197 Code chunks look like this:
200 \begin_layout LyX-Code
206 \begin_layout Standard
216 \begin_layout Standard
225 code for the chunk goes here ...}
230 \begin_layout Standard
232 The ``@'' is a necessary delimiter to end the code chunk.
233 The other form that the ``@'' line takes is as follows:
236 \begin_layout LyX-Code
242 \begin_layout Standard
252 \begin_layout Standard
261 code for the chunk ...}
263 @ %def identifier1 identifier2
266 \begin_layout Standard
268 In the latter form, we are declaring to
272 that this code chunk defines identifier1, identifier2, etc.
275 \begin_layout Standard
277 When first tackling this problem, I spoke with members of the LyX team that
278 knew about the literate programming extensions and reLyX (the LaTeX importing
282 \begin_layout Standard
284 One of the first ideas was to extend the reLyX code to understand the
289 This proved to be too hard and presents other problems
293 \begin_layout Standard
295 Not the least of these problems is the fact that << is a quote in French.
301 On the other hand, it turns out that reLyX contains a very useful literal
303 If the input file contains the construct
306 \begin_layout LyX-Code
320 \begin_layout Standard
322 then reLyX will copy the surrounded code to the output file verbatim.
323 Given this, the first part of the translation is easy; we simply have to
324 copy the code chunks into an intermediate file that surrounds them with
344 \begin_layout Standard
346 Once reLyX is done with the input file, the problem is reduced to changing
347 the code chunks from LyX's LaTeX layout to the Scrap layout.
350 \begin_layout Standard
352 There is one final constraint on
357 We want to be able to run it as a simple pre-processor and post-processor
359 We can accomplish this by setting the flags
374 \begin_layout Standard
408 \begin_layout Standard
425 before we reach the main conversion code.
428 \begin_layout Standard
430 With all that preamble out of the way, we now have the basic high-level
431 outline for our code:
436 <<Convert noweb to LyX>>=
440 <<Transform noweb for reLyX>>
444 if ((!$pre_only) && (!$post_only)) {
446 <<Run reLyX on intermediate file>>
461 \begin_layout Section
463 Making a file that reLyX can process
466 \begin_layout Standard
468 In this section, we present the code that performs the task of creating
469 the intermediate file that reLyX can process, using the algorithm that
471 This algorithm is outlined in the code that follows:
476 <<Transform noweb for reLyX>>=
478 <<Setup INPUT and OUTPUT>>
480 inputline: while(<INPUT>)
494 >=/) { # Beginning of a noweb scrap
496 <<Read in and output the noweb code chunk>>
500 s+(.*)/) { # Beginning of a documentation chunk
502 print OUTPUT $1; # We do not need the ``@'' part
512 ]/) { # noweb quoted code
514 <<Perform special input quoting of [[var]]>>
518 print OUTPUT; # Just let the line pass through
524 <<Close INPUT and OUTPUT>>
529 \begin_layout Standard
531 In the code above, we do some pre-processing of the noweb ``[[...]]'' construct.
532 This avoids some problems with reLyX confusing lists composed of ``[[...]]''
538 <<Perform special input quoting of [[var]]>>=
553 \begin_layout Standard
570 \begin_layout Standard
587 file, once we have identified a
591 code chunk, we transform it into a form that is usable by reLyX.
596 <<Read in and output the noweb code chunk>>=
598 <<Save the beginning of the scrap to savedScrap>>
600 <<Concatenate the rest of the scrap>>
602 <<print out the scrap in a reLyXskip block>>
607 \begin_layout Subsection
609 File input and output for the pre-processing step
612 \begin_layout Standard
633 \begin_layout Standard
667 \begin_layout Standard
684 to read and write files.
685 In the code fragment above, we need to read from the input file and write
686 to a file that will be later transformed by reLyX.
687 If we are being called only to pre-process the input file, then there is
688 no need to create a temporary file.
693 <<Setup INPUT and OUTPUT>>=
697 &setup_files($input_file, $output_file);
701 $relyx_file = "temp$$";
703 &setup_files($input_file, $relyx_file);
710 \begin_layout Standard
712 This code uses a small perl subroutine,
727 \begin_layout Standard
742 , which we define below:
753 open(INPUT, "<$in") || die "Cannot read $in: $!
757 open(OUTPUT, ">$out") || die "Cannot write $out: $!
766 \begin_layout Subsection
775 \begin_layout Standard
777 After we see the beginning of the scrap, we need to read in and save the
778 rest of the scrap for output.
783 <<Save the beginning of the scrap to savedScrap>>=
794 <<Concatenate the rest of the scrap>>=
796 scrapline: while (<INPUT>) {
798 last scrapline if /^@
810 s+$/) {$savedScrap .= $_; last switch; }
814 s+%def.*$/) {$savedScrap .= $_; last switch; }
818 s+(.*)$/) {$savedScrap .= "@
829 \begin_layout Subsection
831 Printing out the scrap
834 \begin_layout Standard
836 The final piece of the first pass of the conversion is done by this code.
841 <<print out the scrap in a reLyXskip block>>=
851 print OUTPUT $savedScrap;
863 print OUTPUT "$endLine";
868 \begin_layout Standard
870 Finally, we need to close the
885 \begin_layout Standard
919 \begin_layout Standard
941 <<Close INPUT and OUTPUT>>=
950 \begin_layout Section
955 \begin_layout Standard
957 In this section, we describe and implement the code that runs reLyX on the
973 \begin_layout Standard
992 \begin_layout Subsection
994 Selecting the document class
997 \begin_layout Standard
999 In order to run reLyX, we need to know the article class of the input document
1000 (to choose the corresponding literate document layout).
1001 For this, we need to parse the intermediate file.
1006 <<Run reLyX on intermediate file>>=
1008 <<Parse for document class>>
1010 <<Run reLyX with document class>>
1015 \begin_layout Standard
1017 In the code below, you'll see a strange regular expression to search for
1019 The reason for this kludge is that without it, we can't run
1029 file that is generated by LyX
1033 \begin_layout Standard
1052 \begin_layout Standard
1080 \begin_layout Standard
1095 class and gets confused, so we have to obfuscate it slightly.
1101 With the regular expression as it is, we can actually run
1105 on itself and a produce a quite reasonable LyX file.
1110 <<Parse for document class>>=
1112 open(INPUT, "<$relyx_file") ||
1114 die "Cannot read $relyx_file: $!
1118 $class = "article"; # default if none found
1120 parse: while(<INPUT>) {
1126 docu[m]entclass{(.*)}/) {
1141 \begin_layout Subsection
1143 Running reLyX with the corresponding literate document layout
1146 \begin_layout Standard
1148 Now that we know what the document class ought to be, we do:
1153 <<Run reLyX with document class>>=
1155 $doc_class = "literate-" .
1158 die "reLyX returned non-zero: $!
1162 if (system("reLyX -c $doc_class $relyx_file"));
1167 \begin_layout Standard
1169 reLyX performs the main bulk of the translation work.
1170 Note that if the ``literate-
1174 '' document layout is not found, then reLyX will fail with an error.
1175 In that case, you may need to modify your
1179 input file to a supported document type.
1182 \begin_layout Section
1184 Fixing the reLyX output
1187 \begin_layout Standard
1189 We need to perform some post-processing of what reLyX produces in order
1190 to have the best output for our literate document.
1191 The outline of the post-processing steps are:
1196 <<Fix up LyX file>>=
1198 <<Setup INPUT and OUTPUT for the final output>>
1200 line: while(<INPUT>)
1204 <<Fix code chunks in latex layout>>
1206 <<Fix [[var]] noweb construct>>
1208 print OUTPUT; # default
1212 <<Close INPUT and OUTPUT>>
1217 \begin_layout Standard
1219 Note that in the perl code that is contained in the
1234 \begin_layout Standard
1251 loop above, the perl construct
1268 \begin_layout Standard
1285 is sufficient to restart the loop.
1286 We can use this construct to do some relatively complex parsing of the
1287 reLyX generated file.
1290 \begin_layout Subsection
1292 File input and output for the post-processing
1295 \begin_layout Standard
1312 \begin_layout Standard
1346 \begin_layout Standard
1363 is taken care of by this code:
1368 <<Setup INPUT and OUTPUT for the final output>>=
1372 &setup_files("$input_file", "$output_file");
1376 &setup_files("$relyx_file.lyx", "$output_file");
1383 \begin_layout Subsection
1385 Making sure the code chunks are in the Scrap layout
1388 \begin_layout Standard
1390 Now, as we outlined before, the final step is transforming the code-chunks
1391 which have been put into a LaTeX layout by LyX into the scrap layout.
1396 <<Fix code chunks in latex layout>>=
1402 latex latex/) { # Beginning of some latex code
1404 if (($line = <INPUT>) =~ /^
1406 s*<</) { # code scrap
1408 <<Transform this chunk into layout scrap>>
1414 latex latex line + next line
1416 print OUTPUT "$_$line";
1427 \begin_layout Standard
1429 When we are sure that we are in a code chunk, we must read in the rest of
1430 the code chunk and output a scrap layout for it:
1435 <<Transform this chunk into layout scrap>>=
1447 codeline: while (<INPUT>) {
1451 last codeline if /^@
1457 print OUTPUT $savedScrap;
1459 <<Slurp up to the end of the latex layout>>
1464 \begin_layout Standard
1466 Okay, now we just need to eat the rest of the latex layout.
1467 There should only be a few different types of lines for us to match:
1472 <<Slurp up to the end of the latex layout>>=
1474 slurp: while (<INPUT>) {
1492 warn "confused by line: $_";
1499 \begin_layout Subsection
1514 \begin_layout Standard
1520 allows the user to use a special code quoting mechanism in documentation
1522 Fixing this ``[[quoted-code]]''
1526 syntax means putting the ``[[quoted-code]]'' in a LaTeX layout in the LyX
1528 Otherwise, LyX will backslash-quote the brackets, creating ugly output.
1529 The quoted-code is transformed by
1533 when it generates the final LaTeX code.
1538 <<Fix [[var]] noweb construct>>=
1548 ]/) { # special code for [[var]]
1583 \begin_layout Section
1585 Cleaning up intermediate files
1588 \begin_layout Standard
1590 The cleanup code is very simple:
1597 system("rm -f $relyx_file*") unless ($post_only || $pre_only);
1602 \begin_layout Section
1604 User supplied arguments
1607 \begin_layout Standard
1613 script understands two arguments, input-file and output-file.
1614 It is also set up to be used internally by reLyX to pre-process or postprocess
1615 files in the import pipeline.
1620 <<Setup variables from user supplied args>>=
1622 &usage() if ($#ARGV < 1); # zero or one argument
1624 if ($ARGV[0] eq "-pre") {
1626 &usage unless ($#ARGV == 2);
1628 $input_file = $ARGV[1]; $output_file = $ARGV[2]; $pre_only = 1;
1630 } elsif ($ARGV[0] eq "-post") {
1632 &usage unless ($#ARGV == 2);
1634 $input_file = $ARGV[1]; $output_file = $ARGV[2]; $post_only = 1;
1638 &usage unless ($#ARGV == 1);
1640 $input_file = $ARGV[0]; $output_file = $ARGV[1];
1642 $pre_only = 0; $post_only = 0;
1646 @ %def input_file output_file pre_only post_only
1655 print "Usage: noweb2lyx [-pre | -post] input-file output-file
1659 If -pre is specified, only pre-processes the input-file for reLyX.
1661 Similarly, in the case of -post, post-processes reLyX output.
1663 In case of bugs, Email Kayvan Sylvan <kayvan
1676 \begin_layout Section
1685 \begin_layout Standard
1687 The noweb2lyx script can be tangled from LyX if you set
1695 to call a generic script that always extracts a scrap named
1702 Here is an example of such a script:
1705 \begin_layout LyX-Code
1709 notangle -Rbuild-script $1 | sh
1718 notangle -Rnoweb2lyx.in noweb2lyx.nw > noweb2lyx.in
1720 sed -e "s=@PERL@=$PREFIX/bin/perl=" noweb2lyx.in > noweb2lyx
1728 \begin_layout Standard
1735 \begin_layout Section*
1740 \begin_layout Standard
1755 \begin_layout Standard
1766 \begin_layout Section*
1771 \begin_layout Standard
1786 \begin_layout Standard