1 #LyX 2.0 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
16 \use_default_options false
17 \maintain_unincluded_children false
19 \language_package default
20 \inputencoding default
24 \font_typewriter default
25 \font_default_family default
26 \use_non_tex_fonts false
33 \default_output_format default
35 \bibtex_command default
36 \index_command default
37 \paperfontsize default
49 \paperorientation portrait
58 \paragraph_separation indent
59 \paragraph_indentation default
60 \quotes_language english
63 \paperpagestyle default
64 \tracking_changes false
81 Sylvan <kayvan@sylvan.com>
88 \begin_layout Abstract
89 This document describes and implements a perl script for importing noweb
93 \begin_layout Standard
94 \begin_inset CommandInset toc
95 LatexCommand tableofcontents
102 \begin_layout Standard
103 \begin_inset Newpage newpage
109 \begin_layout Section
113 \begin_layout Standard
114 Since version 1.0.1, LyX now supports Literate Programming using
119 This addition to LyX made it very pleasant to write programs in the literate
120 style (like this one).
121 In addition to being able to write new literate programs, it would be quite
126 code could be imported into LyX in some fashion.
127 That's where this program comes in.
130 \begin_layout Standard
155 # Copyright (C) 1999 Kayvan A.
156 Sylvan <kayvan@sylvan.com>
160 # You are free to use and modify this code under the terms of
164 # the GNU General Public Licence version 2 or later.
172 # Written with assistance from:
176 # Edmar Wienskoski Jr.
177 <edmar-w-jr@technologist.com>
181 # Amir Karger <karger@post.harvard.edu>
189 # $Id: noweb2lyx.lyx,v 1.5 2005/07/18 09:42:27 jamatos Exp $
197 # NOTE: This file was automatically generated from noweb2lyx.lyx using noweb.
205 <<Setup variables from user supplied args>>
213 <<Convert noweb to LyX>>
220 \begin_layout Section
221 The Noweb file defined
224 \begin_layout Standard
229 file is a collection of documentation and code chunks.
230 Documentation chunks simply start with an ``@'' and have no name:
233 \begin_layout LyX-Code
234 @ Here is some documentation.
242 We can do arbitrary LaTeX code here.
243 \begin_inset Newline newline
250 \begin_layout Standard
251 Code chunks look like this:
254 \begin_layout LyX-Code
259 \begin_layout Plain Layout
270 \begin_layout Plain Layout
278 \begin_inset Newline newline
282 code for the chunk goes here ...}
283 \begin_inset Newline newline
289 \begin_layout Standard
290 The ``@'' is a necessary delimiter to end the code chunk.
291 The other form that the ``@'' line takes is as follows:
294 \begin_layout LyX-Code
299 \begin_layout Plain Layout
310 \begin_layout Plain Layout
318 \begin_inset Newline newline
322 code for the chunk ...}
323 \begin_inset Newline newline
326 @ %def identifier1 identifier2
329 \begin_layout Standard
330 In the latter form, we are declaring to
334 that this code chunk defines identifier1, identifier2, etc.
337 \begin_layout Standard
338 When first tackling this problem, I spoke with members of the LyX team that
339 knew about the literate programming extensions and reLyX (the LaTeX importing
343 \begin_layout Standard
344 One of the first ideas was to extend the reLyX code to understand the
349 This proved to be too hard and presents other problems
353 \begin_layout Plain Layout
354 Not the least of these problems is the fact that << is a quote in French.
360 On the other hand, it turns out that reLyX contains a very useful literal
362 If the input file contains the construct
365 \begin_layout LyX-Code
369 \begin_inset Newline newline
374 \begin_inset Newline newline
382 \begin_layout Standard
383 then reLyX will copy the surrounded code to the output file verbatim.
384 Given this, the first part of the translation is easy; we simply have to
385 copy the code chunks into an intermediate file that surrounds them with
401 \begin_layout Standard
402 Once reLyX is done with the input file, the problem is reduced to changing
403 the code chunks from LyX's LaTeX layout to the Scrap layout.
406 \begin_layout Standard
407 There is one final constraint on
412 We want to be able to run it as a simple pre-processor and post-processor
414 We can accomplish this by setting the flags
427 \begin_layout Plain Layout
458 \begin_layout Plain Layout
475 before we reach the main conversion code.
478 \begin_layout Standard
479 With all that preamble out of the way, we now have the basic high-level
480 outline for our code:
484 <<Convert noweb to LyX>>=
492 <<Transform noweb for reLyX>>
500 if ((!$pre_only) && (!$post_only)) {
504 <<Run reLyX on intermediate file>>
531 \begin_layout Section
532 Making a file that reLyX can process
535 \begin_layout Standard
536 In this section, we present the code that performs the task of creating
537 the intermediate file that reLyX can process, using the algorithm that
539 This algorithm is outlined in the code that follows:
547 <<Transform noweb for reLyX>>=
551 <<Setup INPUT and OUTPUT>>
555 inputline: while(<INPUT>)
573 >=/) { # Beginning of a noweb scrap
577 <<Read in and output the noweb code chunk>>
583 s+(.*)/) { # Beginning of a documentation chunk
587 print OUTPUT $1; # We do not need the ``@'' part
599 ]/) { # noweb quoted code
603 <<Perform special input quoting of [[var]]>>
611 print OUTPUT; # Just let the line pass through
623 <<Close INPUT and OUTPUT>>
630 \begin_layout Standard
631 In the code above, we do some pre-processing of the noweb ``[[...]]'' construct.
632 This avoids some problems with reLyX confusing lists composed of ``[[...]]''
637 <<Perform special input quoting of [[var]]>>=
648 \begin_inset Newline newline
652 \begin_inset Newline newline
658 \begin_layout Standard
672 \begin_layout Plain Layout
689 file, once we have identified a
693 code chunk, we transform it into a form that is usable by reLyX.
697 <<Read in and output the noweb code chunk>>=
701 <<Save the beginning of the scrap to savedScrap>>
705 <<Concatenate the rest of the scrap>>
709 <<print out the scrap in a reLyXskip block>>
716 \begin_layout Subsection
717 File input and output for the pre-processing step
720 \begin_layout Standard
738 \begin_layout Plain Layout
769 \begin_layout Plain Layout
786 to read and write files.
787 In the code fragment above, we need to read from the input file and write
788 to a file that will be later transformed by reLyX.
789 If we are being called only to pre-process the input file, then there is
790 no need to create a temporary file.
794 <<Setup INPUT and OUTPUT>>=
802 &setup_files($input_file, $output_file);
810 $relyx_file = "temp$$";
814 &setup_files($input_file, $relyx_file);
825 \begin_layout Standard
826 This code uses a small perl subroutine,
839 \begin_layout Plain Layout
855 , which we define below:
871 open(INPUT, "<$in") || die "Cannot read $in: $!
877 open(OUTPUT, ">$out") || die "Cannot write $out: $!
890 \begin_layout Subsection
898 \begin_layout Standard
899 After we see the beginning of the scrap, we need to read in and save the
900 rest of the scrap for output.
904 <<Save the beginning of the scrap to savedScrap>>=
920 <<Concatenate the rest of the scrap>>=
921 \begin_inset Newline newline
924 scrapline: while (<INPUT>) {
925 \begin_inset Newline newline
928 last scrapline if /^@
931 \begin_inset Newline newline
935 \begin_inset Newline newline
939 \begin_inset Newline newline
943 \begin_inset Newline newline
948 s+$/) {$savedScrap .= $_; last switch; }
949 \begin_inset Newline newline
954 s+%def.*$/) {$savedScrap .= $_; last switch; }
955 \begin_inset Newline newline
960 s+(.*)$/) {$savedScrap .= "@
965 \begin_inset Newline newline
969 \begin_inset Newline newline
975 \begin_layout Subsection
976 Printing out the scrap
979 \begin_layout Standard
980 The final piece of the first pass of the conversion is done by this code.
984 <<print out the scrap in a reLyXskip block>>=
998 print OUTPUT $savedScrap;
1014 print OUTPUT "$endLine";
1021 \begin_layout Standard
1022 Finally, we need to close the
1035 \begin_layout Plain Layout
1066 \begin_layout Plain Layout
1087 <<Close INPUT and OUTPUT>>=
1102 \begin_layout Section
1106 \begin_layout Standard
1107 In this section, we describe and implement the code that runs reLyX on the
1121 \begin_layout Plain Layout
1141 \begin_layout Subsection
1142 Selecting the document class
1145 \begin_layout Standard
1146 In order to run reLyX, we need to know the article class of the input document
1147 (to choose the corresponding literate document layout).
1148 For this, we need to parse the intermediate file.
1152 <<Run reLyX on intermediate file>>=
1156 <<Parse for document class>>
1160 <<Run reLyX with document class>>
1167 \begin_layout Standard
1168 In the code below, you'll see a strange regular expression to search for
1170 The reason for this kludge is that without it, we can't run
1178 file that is generated by LyX
1182 \begin_layout Plain Layout
1200 \begin_layout Plain Layout
1229 \begin_layout Plain Layout
1245 class and gets confused, so we have to obfuscate it slightly.
1251 With the regular expression as it is, we can actually run
1255 on itself and a produce a quite reasonable LyX file.
1259 <<Parse for document class>>=
1263 open(INPUT, "<$relyx_file") ||
1267 die "Cannot read $relyx_file: $!
1273 $class = "article"; # default if none found
1277 parse: while(<INPUT>) {
1285 docu[m]entclass{(.*)}/) {
1312 \begin_layout Subsection
1313 Running reLyX with the corresponding literate document layout
1316 \begin_layout Standard
1317 Now that we know what the document class ought to be, we do:
1321 <<Run reLyX with document class>>=
1322 \begin_inset Newline newline
1325 $doc_class = "literate-" .
1327 \begin_inset Newline newline
1330 die "reLyX returned non-zero: $!
1333 \begin_inset Newline newline
1336 if (system("reLyX -c $doc_class $relyx_file"));
1337 \begin_inset Newline newline
1343 \begin_layout Standard
1344 reLyX performs the main bulk of the translation work.
1345 Note that if the ``literate-
1349 '' document layout is not found, then reLyX will fail with an error.
1350 In that case, you may need to modify your
1354 input file to a supported document type.
1357 \begin_layout Section
1358 Fixing the reLyX output
1361 \begin_layout Standard
1362 We need to perform some post-processing of what reLyX produces in order
1363 to have the best output for our literate document.
1364 The outline of the post-processing steps are:
1368 <<Fix up LyX file>>=
1372 <<Setup INPUT and OUTPUT for the final output>>
1376 line: while(<INPUT>)
1384 <<Fix code chunks in latex layout>>
1388 <<Fix [[var]] noweb construct>>
1392 print OUTPUT; # default
1400 <<Close INPUT and OUTPUT>>
1407 \begin_layout Standard
1408 Note that in the perl code that is contained in the
1421 \begin_layout Plain Layout
1438 loop above, the perl construct
1452 \begin_layout Plain Layout
1469 is sufficient to restart the loop.
1470 We can use this construct to do some relatively complex parsing of the
1471 reLyX generated file.
1474 \begin_layout Subsection
1475 File input and output for the post-processing
1478 \begin_layout Standard
1492 \begin_layout Plain Layout
1523 \begin_layout Plain Layout
1540 is taken care of by this code:
1544 <<Setup INPUT and OUTPUT for the final output>>=
1552 &setup_files("$input_file", "$output_file");
1560 &setup_files("$relyx_file.lyx", "$output_file");
1571 \begin_layout Subsection
1572 Making sure the code chunks are in the Scrap layout
1575 \begin_layout Standard
1576 Now, as we outlined before, the final step is transforming the code-chunks
1577 which have been put into a LaTeX layout by LyX into the scrap layout.
1581 <<Fix code chunks in latex layout>>=
1589 latex latex/) { # Beginning of some latex code
1593 if (($line = <INPUT>) =~ /^
1595 s*<</) { # code scrap
1599 <<Transform this chunk into layout scrap>>
1609 latex latex line + next line
1613 print OUTPUT "$_$line";
1632 \begin_layout Standard
1633 When we are sure that we are in a code chunk, we must read in the rest of
1634 the code chunk and output a scrap layout for it:
1638 <<Transform this chunk into layout scrap>>=
1655 \begin_inset Newline newline
1658 codeline: while (<INPUT>) {
1659 \begin_inset Newline newline
1663 \begin_inset Newline newline
1666 last codeline if /^@
1669 \begin_inset Newline newline
1673 \begin_inset Newline newline
1676 print OUTPUT $savedScrap;
1677 \begin_inset Newline newline
1680 <<Slurp up to the end of the latex layout>>
1681 \begin_inset Newline newline
1687 \begin_layout Standard
1688 Okay, now we just need to eat the rest of the latex layout.
1689 There should only be a few different types of lines for us to match:
1693 <<Slurp up to the end of the latex layout>>=
1697 slurp: while (<INPUT>) {
1723 warn "confused by line: $_";
1734 \begin_layout Subsection
1746 \begin_layout Standard
1751 allows the user to use a special code quoting mechanism in documentation
1753 Fixing this ``[[quoted-code]]''
1757 syntax means putting the ``[[quoted-code]]'' in a LaTeX layout in the LyX
1759 Otherwise, LyX will backslash-quote the brackets, creating ugly output.
1760 The quoted-code is transformed by
1764 when it generates the final LaTeX code.
1768 <<Fix [[var]] noweb construct>>=
1780 ]/) { # special code for [[var]]
1825 \begin_layout Section
1826 Cleaning up intermediate files
1829 \begin_layout Standard
1830 The cleanup code is very simple:
1838 system("rm -f $relyx_file*") unless ($post_only || $pre_only);
1845 \begin_layout Section
1846 User supplied arguments
1849 \begin_layout Standard
1854 script understands two arguments, input-file and output-file.
1855 It is also set up to be used internally by reLyX to pre-process or postprocess
1856 files in the import pipeline.
1860 <<Setup variables from user supplied args>>=
1864 &usage() if ($#ARGV < 1); # zero or one argument
1868 if ($ARGV[0] eq "-pre") {
1872 &usage unless ($#ARGV == 2);
1876 $input_file = $ARGV[1]; $output_file = $ARGV[2]; $pre_only = 1;
1880 } elsif ($ARGV[0] eq "-post") {
1884 &usage unless ($#ARGV == 2);
1888 $input_file = $ARGV[1]; $output_file = $ARGV[2]; $post_only = 1;
1896 &usage unless ($#ARGV == 1);
1900 $input_file = $ARGV[0]; $output_file = $ARGV[1];
1904 $pre_only = 0; $post_only = 0;
1912 @ %def input_file output_file pre_only post_only
1924 print "Usage: noweb2lyx [-pre | -post] input-file output-file
1928 \begin_inset Newline newline
1931 If -pre is specified, only pre-processes the input-file for reLyX.
1932 \begin_inset Newline newline
1935 Similarly, in the case of -post, post-processes reLyX output.
1936 \begin_inset Newline newline
1939 In case of bugs, Email Kayvan Sylvan <kayvan
1944 \begin_inset Newline newline
1948 \begin_inset Newline newline
1952 \begin_inset Newline newline
1958 \begin_layout Section
1966 \begin_layout Standard
1967 The noweb2lyx script can be tangled from LyX if you set
1973 to call a generic script that always extracts a scrap named
1978 Here is an example of such a script:
1981 \begin_layout LyX-Code
1983 \begin_inset Newline newline
1986 notangle -Rbuild-script $1 | sh
1998 notangle -Rnoweb2lyx.in noweb2lyx.nw > noweb2lyx.in
2002 sed -e "s=@PERL@=$PREFIX/bin/perl=" noweb2lyx.in > noweb2lyx
2013 \begin_layout Standard
2014 \begin_inset Newpage newpage
2020 \begin_layout Section*
2024 \begin_layout Standard
2037 \begin_layout Plain Layout
2049 \begin_layout Section*
2053 \begin_layout Standard
2066 \begin_layout Plain Layout