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 \paperfontsize default
27 \paperorientation portrait
30 \paragraph_separation indent
32 \quotes_language english
35 \paperpagestyle default
36 \tracking_changes false
52 Sylvan <kayvan@sylvan.com>
60 \begin_layout Abstract
62 This document describes and implements a perl script for importing noweb
66 \begin_layout Standard
69 \begin_inset LatexCommand \tableofcontents{}
76 \begin_layout Standard
89 \begin_layout Standard
91 Since version 1.0.1, LyX now supports Literate Programming using
96 This addition to LyX made it very pleasant to write programs in the literate
97 style (like this one).
98 In addition to being able to write new literate programs, it would be quite
103 code could be imported into LyX in some fashion.
104 That's where this program comes in.
107 \begin_layout Standard
128 # Copyright (C) 1999 Kayvan A.
129 Sylvan <kayvan@sylvan.com>
131 # You are free to use and modify this code under the terms of
133 # the GNU General Public Licence version 2 or later.
137 # Written with assistance from:
139 # Edmar Wienskoski Jr.
140 <edmar-w-jr@technologist.com>
142 # Amir Karger <karger@post.harvard.edu>
146 # $Id: noweb2lyx.lyx,v 1.5 2005/07/18 09:42:27 jamatos Exp $
150 # NOTE: This file was automatically generated from noweb2lyx.lyx using noweb.
154 <<Setup variables from user supplied args>>
158 <<Convert noweb to LyX>>
163 \begin_layout Section
165 The Noweb file defined
168 \begin_layout Standard
174 file is a collection of documentation and code chunks.
175 Documentation chunks simply start with an ``@'' and have no name:
178 \begin_layout LyX-Code
180 @ Here is some documentation.
182 We can do arbitrary LaTeX code here.
188 \begin_layout Standard
190 Code chunks look like this:
193 \begin_layout LyX-Code
199 \begin_layout Standard
209 \begin_layout Standard
218 code for the chunk goes here ...}
223 \begin_layout Standard
225 The ``@'' is a necessary delimiter to end the code chunk.
226 The other form that the ``@'' line takes is as follows:
229 \begin_layout LyX-Code
235 \begin_layout Standard
245 \begin_layout Standard
254 code for the chunk ...}
256 @ %def identifier1 identifier2
259 \begin_layout Standard
261 In the latter form, we are declaring to
265 that this code chunk defines identifier1, identifier2, etc.
268 \begin_layout Standard
270 When first tackling this problem, I spoke with members of the LyX team that
271 knew about the literate programming extensions and reLyX (the LaTeX importing
275 \begin_layout Standard
277 One of the first ideas was to extend the reLyX code to understand the
282 This proved to be too hard and presents other problems
286 \begin_layout Standard
288 Not the least of these problems is the fact that << is a quote in French.
294 On the other hand, it turns out that reLyX contains a very useful literal
296 If the input file contains the construct
299 \begin_layout LyX-Code
313 \begin_layout Standard
315 then reLyX will copy the surrounded code to the output file verbatim.
316 Given this, the first part of the translation is easy; we simply have to
317 copy the code chunks into an intermediate file that surrounds them with
333 \begin_layout Standard
335 Once reLyX is done with the input file, the problem is reduced to changing
336 the code chunks from LyX's LaTeX layout to the Scrap layout.
339 \begin_layout Standard
341 There is one final constraint on
346 We want to be able to run it as a simple pre-processor and post-processor
348 We can accomplish this by setting the flags
361 \begin_layout Standard
389 \begin_layout Standard
404 before we reach the main conversion code.
407 \begin_layout Standard
409 With all that preamble out of the way, we now have the basic high-level
410 outline for our code:
415 <<Convert noweb to LyX>>=
419 <<Transform noweb for reLyX>>
423 if ((!$pre_only) && (!$post_only)) {
425 <<Run reLyX on intermediate file>>
440 \begin_layout Section
442 Making a file that reLyX can process
445 \begin_layout Standard
447 In this section, we present the code that performs the task of creating
448 the intermediate file that reLyX can process, using the algorithm that
450 This algorithm is outlined in the code that follows:
455 <<Transform noweb for reLyX>>=
457 <<Setup INPUT and OUTPUT>>
459 inputline: while(<INPUT>)
473 >=/) { # Beginning of a noweb scrap
475 <<Read in and output the noweb code chunk>>
479 s+(.*)/) { # Beginning of a documentation chunk
481 print OUTPUT $1; # We do not need the ``@'' part
491 ]/) { # noweb quoted code
493 <<Perform special input quoting of [[var]]>>
497 print OUTPUT; # Just let the line pass through
503 <<Close INPUT and OUTPUT>>
508 \begin_layout Standard
510 In the code above, we do some pre-processing of the noweb ``[[...]]'' construct.
511 This avoids some problems with reLyX confusing lists composed of ``[[...]]''
517 <<Perform special input quoting of [[var]]>>=
532 \begin_layout Standard
547 \begin_layout Standard
562 file, once we have identified a
566 code chunk, we transform it into a form that is usable by reLyX.
571 <<Read in and output the noweb code chunk>>=
573 <<Save the beginning of the scrap to savedScrap>>
575 <<Concatenate the rest of the scrap>>
577 <<print out the scrap in a reLyXskip block>>
582 \begin_layout Subsection
584 File input and output for the pre-processing step
587 \begin_layout Standard
606 \begin_layout Standard
634 \begin_layout Standard
649 to read and write files.
650 In the code fragment above, we need to read from the input file and write
651 to a file that will be later transformed by reLyX.
652 If we are being called only to pre-process the input file, then there is
653 no need to create a temporary file.
658 <<Setup INPUT and OUTPUT>>=
662 &setup_files($input_file, $output_file);
666 $relyx_file = "temp$$";
668 &setup_files($input_file, $relyx_file);
675 \begin_layout Standard
677 This code uses a small perl subroutine,
690 \begin_layout Standard
705 , which we define below:
716 open(INPUT, "<$in") || die "Cannot read $in: $!
720 open(OUTPUT, ">$out") || die "Cannot write $out: $!
729 \begin_layout Subsection
738 \begin_layout Standard
740 After we see the beginning of the scrap, we need to read in and save the
741 rest of the scrap for output.
746 <<Save the beginning of the scrap to savedScrap>>=
757 <<Concatenate the rest of the scrap>>=
759 scrapline: while (<INPUT>) {
761 last scrapline if /^@
773 s+$/) {$savedScrap .= $_; last switch; }
777 s+%def.*$/) {$savedScrap .= $_; last switch; }
781 s+(.*)$/) {$savedScrap .= "@
792 \begin_layout Subsection
794 Printing out the scrap
797 \begin_layout Standard
799 The final piece of the first pass of the conversion is done by this code.
804 <<print out the scrap in a reLyXskip block>>=
814 print OUTPUT $savedScrap;
826 print OUTPUT "$endLine";
831 \begin_layout Standard
833 Finally, we need to close the
846 \begin_layout Standard
874 \begin_layout Standard
894 <<Close INPUT and OUTPUT>>=
903 \begin_layout Section
908 \begin_layout Standard
910 In this section, we describe and implement the code that runs reLyX on the
924 \begin_layout Standard
943 \begin_layout Subsection
945 Selecting the document class
948 \begin_layout Standard
950 In order to run reLyX, we need to know the article class of the input document
951 (to choose the corresponding literate document layout).
952 For this, we need to parse the intermediate file.
957 <<Run reLyX on intermediate file>>=
959 <<Parse for document class>>
961 <<Run reLyX with document class>>
966 \begin_layout Standard
968 In the code below, you'll see a strange regular expression to search for
970 The reason for this kludge is that without it, we can't run
978 file that is generated by LyX
982 \begin_layout Standard
1001 \begin_layout Standard
1029 \begin_layout Standard
1044 class and gets confused, so we have to obfuscate it slightly.
1050 With the regular expression as it is, we can actually run
1054 on itself and a produce a quite reasonable LyX file.
1059 <<Parse for document class>>=
1061 open(INPUT, "<$relyx_file") ||
1063 die "Cannot read $relyx_file: $!
1067 $class = "article"; # default if none found
1069 parse: while(<INPUT>) {
1075 docu[m]entclass{(.*)}/) {
1090 \begin_layout Subsection
1092 Running reLyX with the corresponding literate document layout
1095 \begin_layout Standard
1097 Now that we know what the document class ought to be, we do:
1102 <<Run reLyX with document class>>=
1104 $doc_class = "literate-" .
1107 die "reLyX returned non-zero: $!
1111 if (system("reLyX -c $doc_class $relyx_file"));
1116 \begin_layout Standard
1118 reLyX performs the main bulk of the translation work.
1119 Note that if the ``literate-
1123 '' document layout is not found, then reLyX will fail with an error.
1124 In that case, you may need to modify your
1128 input file to a supported document type.
1131 \begin_layout Section
1133 Fixing the reLyX output
1136 \begin_layout Standard
1138 We need to perform some post-processing of what reLyX produces in order
1139 to have the best output for our literate document.
1140 The outline of the post-processing steps are:
1145 <<Fix up LyX file>>=
1147 <<Setup INPUT and OUTPUT for the final output>>
1149 line: while(<INPUT>)
1153 <<Fix code chunks in latex layout>>
1155 <<Fix [[var]] noweb construct>>
1157 print OUTPUT; # default
1161 <<Close INPUT and OUTPUT>>
1166 \begin_layout Standard
1168 Note that in the perl code that is contained in the
1181 \begin_layout Standard
1196 loop above, the perl construct
1209 \begin_layout Standard
1224 is sufficient to restart the loop.
1225 We can use this construct to do some relatively complex parsing of the
1226 reLyX generated file.
1229 \begin_layout Subsection
1231 File input and output for the post-processing
1234 \begin_layout Standard
1249 \begin_layout Standard
1277 \begin_layout Standard
1292 is taken care of by this code:
1297 <<Setup INPUT and OUTPUT for the final output>>=
1301 &setup_files("$input_file", "$output_file");
1305 &setup_files("$relyx_file.lyx", "$output_file");
1312 \begin_layout Subsection
1314 Making sure the code chunks are in the Scrap layout
1317 \begin_layout Standard
1319 Now, as we outlined before, the final step is transforming the code-chunks
1320 which have been put into a LaTeX layout by LyX into the scrap layout.
1325 <<Fix code chunks in latex layout>>=
1331 latex latex/) { # Beginning of some latex code
1333 if (($line = <INPUT>) =~ /^
1335 s*<</) { # code scrap
1337 <<Transform this chunk into layout scrap>>
1343 latex latex line + next line
1345 print OUTPUT "$_$line";
1356 \begin_layout Standard
1358 When we are sure that we are in a code chunk, we must read in the rest of
1359 the code chunk and output a scrap layout for it:
1364 <<Transform this chunk into layout scrap>>=
1376 codeline: while (<INPUT>) {
1380 last codeline if /^@
1386 print OUTPUT $savedScrap;
1388 <<Slurp up to the end of the latex layout>>
1393 \begin_layout Standard
1395 Okay, now we just need to eat the rest of the latex layout.
1396 There should only be a few different types of lines for us to match:
1401 <<Slurp up to the end of the latex layout>>=
1403 slurp: while (<INPUT>) {
1421 warn "confused by line: $_";
1428 \begin_layout Subsection
1441 \begin_layout Standard
1447 allows the user to use a special code quoting mechanism in documentation
1449 Fixing this ``[[quoted-code]]''
1453 syntax means putting the ``[[quoted-code]]'' in a LaTeX layout in the LyX
1455 Otherwise, LyX will backslash-quote the brackets, creating ugly output.
1456 The quoted-code is transformed by
1460 when it generates the final LaTeX code.
1465 <<Fix [[var]] noweb construct>>=
1475 ]/) { # special code for [[var]]
1510 \begin_layout Section
1512 Cleaning up intermediate files
1515 \begin_layout Standard
1517 The cleanup code is very simple:
1524 system("rm -f $relyx_file*") unless ($post_only || $pre_only);
1529 \begin_layout Section
1531 User supplied arguments
1534 \begin_layout Standard
1540 script understands two arguments, input-file and output-file.
1541 It is also set up to be used internally by reLyX to pre-process or postprocess
1542 files in the import pipeline.
1547 <<Setup variables from user supplied args>>=
1549 &usage() if ($#ARGV < 1); # zero or one argument
1551 if ($ARGV[0] eq "-pre") {
1553 &usage unless ($#ARGV == 2);
1555 $input_file = $ARGV[1]; $output_file = $ARGV[2]; $pre_only = 1;
1557 } elsif ($ARGV[0] eq "-post") {
1559 &usage unless ($#ARGV == 2);
1561 $input_file = $ARGV[1]; $output_file = $ARGV[2]; $post_only = 1;
1565 &usage unless ($#ARGV == 1);
1567 $input_file = $ARGV[0]; $output_file = $ARGV[1];
1569 $pre_only = 0; $post_only = 0;
1573 @ %def input_file output_file pre_only post_only
1582 print "Usage: noweb2lyx [-pre | -post] input-file output-file
1586 If -pre is specified, only pre-processes the input-file for reLyX.
1588 Similarly, in the case of -post, post-processes reLyX output.
1590 In case of bugs, Email Kayvan Sylvan <kayvan
1603 \begin_layout Section
1612 \begin_layout Standard
1614 The noweb2lyx script can be tangled from LyX if you set
1620 to call a generic script that always extracts a scrap named
1625 Here is an example of such a script:
1628 \begin_layout LyX-Code
1632 notangle -Rbuild-script $1 | sh
1641 notangle -Rnoweb2lyx.in noweb2lyx.nw > noweb2lyx.in
1643 sed -e "s=@PERL@=$PREFIX/bin/perl=" noweb2lyx.in > noweb2lyx
1651 \begin_layout Standard
1658 \begin_layout Section*
1663 \begin_layout Standard
1678 \begin_layout Standard
1689 \begin_layout Section*
1694 \begin_layout Standard
1709 \begin_layout Standard