1 #LyX 2.1 created this file. For more info see http://www.lyx.org/
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
20 \maintain_unincluded_children false
22 \language_package default
23 \inputencoding default
27 \font_typewriter default
29 \font_default_family default
30 \use_non_tex_fonts false
36 \default_output_format default
38 \bibtex_command default
39 \index_command default
40 \paperfontsize default
45 \use_package amsmath 0
46 \use_package amssymb 0
48 \use_package mathdots 1
49 \use_package mathtools 0
51 \use_package undertilde 0
53 \cite_engine_type numerical
57 \paperorientation portrait
67 \paragraph_separation indent
68 \paragraph_indentation default
69 \quotes_language english
72 \paperpagestyle default
73 \tracking_changes false
90 Sylvan <kayvan@sylvan.com>
97 \begin_layout Abstract
98 This document describes and implements a perl script for importing noweb
102 \begin_layout Standard
103 \begin_inset CommandInset toc
104 LatexCommand tableofcontents
111 \begin_layout Standard
112 \begin_inset Newpage newpage
118 \begin_layout Section
122 \begin_layout Standard
123 Since version 1.0.1, LyX now supports Literate Programming using
128 This addition to LyX made it very pleasant to write programs in the literate
129 style (like this one).
130 In addition to being able to write new literate programs, it would be quite
135 code could be imported into LyX in some fashion.
136 That's where this program comes in.
139 \begin_layout Standard
168 # Copyright (C) 1999 Kayvan A.
169 Sylvan <kayvan@sylvan.com>
174 # You are free to use and modify this code under the terms of
179 # the GNU General Public Licence version 2 or later.
189 # Written with assistance from:
194 # Edmar Wienskoski Jr.
195 <edmar-w-jr@technologist.com>
200 # Amir Karger <karger@post.harvard.edu>
210 # $Id: noweb2lyx.lyx,v 1.5 2005/07/18 09:42:27 jamatos Exp $
220 # NOTE: This file was automatically generated from noweb2lyx.lyx using noweb.
230 <<Setup variables from user supplied args>>
240 <<Convert noweb to LyX>>
248 \begin_layout Section
249 The Noweb file defined
252 \begin_layout Standard
257 file is a collection of documentation and code chunks.
258 Documentation chunks simply start with an ``@'' and have no name:
261 \begin_layout LyX-Code
262 @ Here is some documentation.
271 We can do arbitrary LaTeX code here.
272 \begin_inset Newline newline
279 \begin_layout Standard
280 Code chunks look like this:
283 \begin_layout LyX-Code
288 \begin_layout Plain Layout
299 \begin_layout Plain Layout
307 \begin_inset Newline newline
311 code for the chunk goes here ...}
312 \begin_inset Newline newline
318 \begin_layout Standard
319 The ``@'' is a necessary delimiter to end the code chunk.
320 The other form that the ``@'' line takes is as follows:
323 \begin_layout LyX-Code
328 \begin_layout Plain Layout
339 \begin_layout Plain Layout
347 \begin_inset Newline newline
351 code for the chunk ...}
352 \begin_inset Newline newline
355 @ %def identifier1 identifier2
358 \begin_layout Standard
359 In the latter form, we are declaring to
363 that this code chunk defines identifier1, identifier2, etc.
366 \begin_layout Standard
367 When first tackling this problem, I spoke with members of the LyX team that
368 knew about the literate programming extensions and reLyX (the LaTeX importing
372 \begin_layout Standard
373 One of the first ideas was to extend the reLyX code to understand the
378 This proved to be too hard and presents other problems
382 \begin_layout Plain Layout
383 Not the least of these problems is the fact that << is a quote in French.
389 On the other hand, it turns out that reLyX contains a very useful literal
391 If the input file contains the construct
394 \begin_layout LyX-Code
398 \begin_inset Newline newline
403 \begin_inset Newline newline
411 \begin_layout Standard
412 then reLyX will copy the surrounded code to the output file verbatim.
413 Given this, the first part of the translation is easy; we simply have to
414 copy the code chunks into an intermediate file that surrounds them with
430 \begin_layout Standard
431 Once reLyX is done with the input file, the problem is reduced to changing
432 the code chunks from LyX's LaTeX layout to the Chunk layout.
435 \begin_layout Standard
436 There is one final constraint on
441 We want to be able to run it as a simple pre-processor and post-processor
443 We can accomplish this by setting the flags
456 \begin_layout Plain Layout
487 \begin_layout Plain Layout
504 before we reach the main conversion code.
507 \begin_layout Standard
508 With all that preamble out of the way, we now have the basic high-level
509 outline for our code:
514 <<Convert noweb to LyX>>=
524 <<Transform noweb for reLyX>>
534 if ((!$pre_only) && (!$post_only)) {
539 <<Run reLyX on intermediate file>>
572 \begin_layout Section
573 Making a file that reLyX can process
576 \begin_layout Standard
577 In this section, we present the code that performs the task of creating
578 the intermediate file that reLyX can process, using the algorithm that
580 This algorithm is outlined in the code that follows:
589 <<Transform noweb for reLyX>>=
594 <<Setup INPUT and OUTPUT>>
599 inputline: while(<INPUT>)
619 >=/) { # Beginning of a noweb chunk
624 <<Read in and output the noweb code chunk>>
631 s+(.*)/) { # Beginning of a documentation chunk
636 print OUTPUT $1; # We do not need the ``@'' part
649 ]/) { # noweb quoted code
654 <<Perform special input quoting of [[var]]>>
664 print OUTPUT; # Just let the line pass through
679 <<Close INPUT and OUTPUT>>
687 \begin_layout Standard
688 In the code above, we do some pre-processing of the noweb ``[[...]]'' construct.
689 This avoids some problems with reLyX confusing lists composed of ``[[...]]''
695 <<Perform special input quoting of [[var]]>>=
707 \begin_inset Newline newline
711 \begin_inset Newline newline
717 \begin_layout Standard
731 \begin_layout Plain Layout
748 file, once we have identified a
752 code chunk, we transform it into a form that is usable by reLyX.
757 <<Read in and output the noweb code chunk>>=
762 <<Save the beginning of the chunk to savedchunk>>
767 <<Concatenate the rest of the chunk>>
772 <<print out the chunk in a reLyXskip block>>
780 \begin_layout Subsection
781 File input and output for the pre-processing step
784 \begin_layout Standard
802 \begin_layout Plain Layout
833 \begin_layout Plain Layout
850 to read and write files.
851 In the code fragment above, we need to read from the input file and write
852 to a file that will be later transformed by reLyX.
853 If we are being called only to pre-process the input file, then there is
854 no need to create a temporary file.
859 <<Setup INPUT and OUTPUT>>=
869 &setup_files($input_file, $output_file);
879 $relyx_file = "temp$$";
884 &setup_files($input_file, $relyx_file);
897 \begin_layout Standard
898 This code uses a small perl subroutine,
911 \begin_layout Plain Layout
927 , which we define below:
947 open(INPUT, "<$in") || die "Cannot read $in: $!
954 open(OUTPUT, ">$out") || die "Cannot write $out: $!
969 \begin_layout Subsection
977 \begin_layout Standard
978 After we see the beginning of the chunk, we need to read in and save the
979 rest of the chunk for output.
984 <<Save the beginning of the chunk to savedchunk>>=
1004 <<Concatenate the rest of the chunk>>=
1005 \begin_inset Newline newline
1008 chunkline: while (<INPUT>) {
1009 \begin_inset Newline newline
1012 last chunkline if /^@
1015 \begin_inset Newline newline
1019 \begin_inset Newline newline
1023 \begin_inset Newline newline
1027 \begin_inset Newline newline
1032 s+$/) {$savedchunk .= $_; last switch; }
1033 \begin_inset Newline newline
1038 s+%def.*$/) {$savedchunk .= $_; last switch; }
1039 \begin_inset Newline newline
1044 s+(.*)$/) {$savedchunk .= "@
1049 \begin_inset Newline newline
1053 \begin_inset Newline newline
1059 \begin_layout Subsection
1060 Printing out the chunk
1063 \begin_layout Standard
1064 The final piece of the first pass of the conversion is done by this code.
1069 <<print out the chunk in a reLyXskip block>>=
1085 print OUTPUT $savedchunk;
1103 print OUTPUT "$endLine";
1111 \begin_layout Standard
1112 Finally, we need to close the
1125 \begin_layout Plain Layout
1156 \begin_layout Plain Layout
1178 <<Close INPUT and OUTPUT>>=
1196 \begin_layout Section
1200 \begin_layout Standard
1201 In this section, we describe and implement the code that runs reLyX on the
1215 \begin_layout Plain Layout
1235 \begin_layout Subsection
1236 Selecting the document class
1239 \begin_layout Standard
1240 In order to run reLyX, we need to know the article class of the input document
1241 (to choose the corresponding literate document layout).
1242 For this, we need to parse the intermediate file.
1247 <<Run reLyX on intermediate file>>=
1252 <<Parse for document class>>
1257 <<Run reLyX with document class>>
1265 \begin_layout Standard
1266 In the code below, you'll see a strange regular expression to search for
1268 The reason for this kludge is that without it, we can't run
1276 file that is generated by LyX
1280 \begin_layout Plain Layout
1298 \begin_layout Plain Layout
1327 \begin_layout Plain Layout
1343 class and gets confused, so we have to obfuscate it slightly.
1349 With the regular expression as it is, we can actually run
1353 on itself and a produce a quite reasonable LyX file.
1358 <<Parse for document class>>=
1363 open(INPUT, "<$relyx_file") ||
1368 die "Cannot read $relyx_file: $!
1375 $class = "article"; # default if none found
1380 parse: while(<INPUT>) {
1389 docu[m]entclass{(.*)}/) {
1422 \begin_layout Subsection
1423 Running reLyX with the corresponding literate document layout
1426 \begin_layout Standard
1427 Now that we know what the document class ought to be, we do:
1432 <<Run reLyX with document class>>=
1433 \begin_inset Newline newline
1436 $doc_class = "literate-" .
1438 \begin_inset Newline newline
1441 die "reLyX returned non-zero: $!
1444 \begin_inset Newline newline
1447 if (system("reLyX -c $doc_class $relyx_file"));
1448 \begin_inset Newline newline
1454 \begin_layout Standard
1455 reLyX performs the main bulk of the translation work.
1456 Note that if the ``literate-
1460 '' document layout is not found, then reLyX will fail with an error.
1461 In that case, you may need to modify your
1465 input file to a supported document type.
1468 \begin_layout Section
1469 Fixing the reLyX output
1472 \begin_layout Standard
1473 We need to perform some post-processing of what reLyX produces in order
1474 to have the best output for our literate document.
1475 The outline of the post-processing steps are:
1480 <<Fix up LyX file>>=
1485 <<Setup INPUT and OUTPUT for the final output>>
1490 line: while(<INPUT>)
1500 <<Fix code chunks in latex layout>>
1505 <<Fix [[var]] noweb construct>>
1510 print OUTPUT; # default
1520 <<Close INPUT and OUTPUT>>
1528 \begin_layout Standard
1529 Note that in the perl code that is contained in the
1542 \begin_layout Plain Layout
1559 loop above, the perl construct
1573 \begin_layout Plain Layout
1590 is sufficient to restart the loop.
1591 We can use this construct to do some relatively complex parsing of the
1592 reLyX generated file.
1595 \begin_layout Subsection
1596 File input and output for the post-processing
1599 \begin_layout Standard
1613 \begin_layout Plain Layout
1644 \begin_layout Plain Layout
1661 is taken care of by this code:
1666 <<Setup INPUT and OUTPUT for the final output>>=
1676 &setup_files("$input_file", "$output_file");
1686 &setup_files("$relyx_file.lyx", "$output_file");
1699 \begin_layout Subsection
1700 Making sure the code chunks are in the Chunk layout
1703 \begin_layout Standard
1704 Now, as we outlined before, the final step is transforming the code-chunks
1705 which have been put into a LaTeX layout by LyX into the Chunk layout.
1710 <<Fix code chunks in latex layout>>=
1719 latex latex/) { # Beginning of some latex code
1724 if (($line = <INPUT>) =~ /^
1726 s*<</) { # code chunk
1731 <<Transform this chunk into layout chunk>>
1743 latex latex line + next line
1748 print OUTPUT "$_$line";
1771 \begin_layout Standard
1772 When we are sure that we are in a code chunk, we must read in the rest of
1773 the code chunk and output a chunk layout for it:
1778 <<Transform this chunk into layout chunk>>=
1796 \begin_inset Newline newline
1799 codeline: while (<INPUT>) {
1800 \begin_inset Newline newline
1804 \begin_inset Newline newline
1807 last codeline if /^@
1810 \begin_inset Newline newline
1814 \begin_inset Newline newline
1817 print OUTPUT $savedchunk;
1818 \begin_inset Newline newline
1821 <<Slurp up to the end of the latex layout>>
1822 \begin_inset Newline newline
1828 \begin_layout Standard
1829 Okay, now we just need to eat the rest of the latex layout.
1830 There should only be a few different types of lines for us to match:
1835 <<Slurp up to the end of the latex layout>>=
1840 slurp: while (<INPUT>) {
1870 warn "confused by line: $_";
1883 \begin_layout Subsection
1895 \begin_layout Standard
1900 allows the user to use a special code quoting mechanism in documentation
1902 Fixing this ``[[quoted-code]]''
1906 syntax means putting the ``[[quoted-code]]'' in a LaTeX layout in the LyX
1908 Otherwise, LyX will backslash-quote the brackets, creating ugly output.
1909 The quoted-code is transformed by
1913 when it generates the final LaTeX code.
1918 <<Fix [[var]] noweb construct>>=
1931 ]/) { # special code for [[var]]
1981 \begin_layout Section
1982 Cleaning up intermediate files
1985 \begin_layout Standard
1986 The cleanup code is very simple:
1996 system("rm -f $relyx_file*") unless ($post_only || $pre_only);
2004 \begin_layout Section
2005 User supplied arguments
2008 \begin_layout Standard
2013 script understands two arguments, input-file and output-file.
2014 It is also set up to be used internally by reLyX to pre-process or postprocess
2015 files in the import pipeline.
2020 <<Setup variables from user supplied args>>=
2025 &usage() if ($#ARGV < 1); # zero or one argument
2030 if ($ARGV[0] eq "-pre") {
2035 &usage unless ($#ARGV == 2);
2040 $input_file = $ARGV[1]; $output_file = $ARGV[2]; $pre_only = 1;
2045 } elsif ($ARGV[0] eq "-post") {
2050 &usage unless ($#ARGV == 2);
2055 $input_file = $ARGV[1]; $output_file = $ARGV[2]; $post_only = 1;
2065 &usage unless ($#ARGV == 1);
2070 $input_file = $ARGV[0]; $output_file = $ARGV[1];
2075 $pre_only = 0; $post_only = 0;
2085 @ %def input_file output_file pre_only post_only
2100 print "Usage: noweb2lyx [-pre | -post] input-file output-file
2105 \begin_inset Newline newline
2108 If -pre is specified, only pre-processes the input-file for reLyX.
2109 \begin_inset Newline newline
2112 Similarly, in the case of -post, post-processes reLyX output.
2113 \begin_inset Newline newline
2116 In case of bugs, Email Kayvan Sylvan <kayvan
2121 \begin_inset Newline newline
2125 \begin_inset Newline newline
2129 \begin_inset Newline newline
2135 \begin_layout Section
2143 \begin_layout Standard
2144 The noweb2lyx script can be tangled from LyX if you set
2150 to call a generic script that always extracts a chunk named
2155 Here is an example of such a script:
2158 \begin_layout LyX-Code
2160 \begin_inset Newline newline
2163 notangle -Rbuild-script $1 | env NOWEB_SOURCE=$1 NOWEB_OUTPUT_DIR=$2 sh
2178 notangle -Rnoweb2lyx.in noweb2lyx.nw > noweb2lyx.in
2183 sed -e "s=@PERL@=$PREFIX/bin/perl=" noweb2lyx.in > noweb2lyx
2196 \begin_layout Standard
2197 \begin_inset Newpage newpage
2203 \begin_layout Section*
2207 \begin_layout Standard
2220 \begin_layout Plain Layout
2232 \begin_layout Section*
2236 \begin_layout Standard
2249 \begin_layout Plain Layout