]> git.lyx.org Git - lyx.git/blob - lib/examples/noweb2lyx.lyx
example files: fileformat and partly other updates second part
[lyx.git] / lib / examples / noweb2lyx.lyx
1 #LyX 1.6.0svn created this file. For more info see http://www.lyx.org/
2 \lyxformat 341
3 \begin_document
4 \begin_header
5 \textclass literate-article
6 \begin_preamble
7 %
8 % This relaxes the noweb constraint that chunks are
9 % never broken across pages.
10 %
11 % This is from the noweb FAQ
12 %
13 \def\nwendcode{\endtrivlist \endgroup}
14 \let\nwdocspar=\smallbreak
15 \end_preamble
16 \language english
17 \inputencoding default
18 \font_roman default
19 \font_sans default
20 \font_typewriter default
21 \font_default_family default
22 \font_sc false
23 \font_osf false
24 \font_sf_scale 100
25 \font_tt_scale 100
26
27 \graphics default
28 \paperfontsize default
29 \spacing single
30 \use_hyperref false
31 \papersize default
32 \use_geometry false
33 \use_amsmath 0
34 \use_esint 0
35 \cite_engine basic
36 \use_bibtopic false
37 \paperorientation portrait
38 \secnumdepth 3
39 \tocdepth 3
40 \paragraph_separation indent
41 \defskip medskip
42 \quotes_language english
43 \papercolumns 1
44 \papersides 1
45 \paperpagestyle default
46 \tracking_changes false
47 \output_changes false
48 \author "" 
49 \end_header
50
51 \begin_body
52
53 \begin_layout Title
54
55 \noun on
56 noweb2lyx
57 \end_layout
58
59 \begin_layout Author
60 Kayvan A.
61  Sylvan <kayvan@sylvan.com>
62 \end_layout
63
64 \begin_layout Date
65 May 6, 1999
66 \end_layout
67
68 \begin_layout Abstract
69 This document describes and implements a perl script for importing noweb
70  files into LyX
71 \end_layout
72
73 \begin_layout Standard
74 \begin_inset CommandInset toc
75 LatexCommand tableofcontents
76
77 \end_inset
78
79
80 \end_layout
81
82 \begin_layout Standard
83 \begin_inset Newpage newpage
84 \end_inset
85
86
87 \end_layout
88
89 \begin_layout Section
90 Introduction
91 \end_layout
92
93 \begin_layout Standard
94 Since version 1.0.1, LyX now supports Literate Programming using 
95 \noun on
96 noweb
97 \noun default
98 .
99  This addition to LyX made it very pleasant to write programs in the literate
100  style (like this one).
101  In addition to being able to write new literate programs, it would be quite
102  useful if old 
103 \noun on
104 noweb
105 \noun default
106  code could be imported into LyX in some fashion.
107  That's where this program comes in.
108 \end_layout
109
110 \begin_layout Standard
111 The purpose of 
112 \noun on
113 noweb2lyx
114 \noun default
115  is to convert a 
116 \noun on
117 noweb
118 \noun default
119  file to LyX.
120 \end_layout
121
122 \begin_layout Scrap
123 <<noweb2lyx.in>>=
124 \begin_inset Newline newline
125 \end_inset
126
127 #!@PERL@
128 \begin_inset Newline newline
129 \end_inset
130
131
132 \begin_inset Newline newline
133 \end_inset
134
135 # Copyright (C) 1999 Kayvan A.
136  Sylvan <kayvan@sylvan.com>
137 \begin_inset Newline newline
138 \end_inset
139
140 # You are free to use and modify this code under the terms of
141 \begin_inset Newline newline
142 \end_inset
143
144 # the GNU General Public Licence version 2 or later.
145 \begin_inset Newline newline
146 \end_inset
147
148 #
149 \begin_inset Newline newline
150 \end_inset
151
152 # Written with assistance from:
153 \begin_inset Newline newline
154 \end_inset
155
156 #   Edmar Wienskoski Jr.
157  <edmar-w-jr@technologist.com>
158 \begin_inset Newline newline
159 \end_inset
160
161 #   Amir Karger <karger@post.harvard.edu>
162 \begin_inset Newline newline
163 \end_inset
164
165 #
166 \begin_inset Newline newline
167 \end_inset
168
169 # $Id: noweb2lyx.lyx,v 1.5 2005/07/18 09:42:27 jamatos Exp $
170 \begin_inset Newline newline
171 \end_inset
172
173 #
174 \begin_inset Newline newline
175 \end_inset
176
177 # NOTE: This file was automatically generated from noweb2lyx.lyx using noweb.
178 \begin_inset Newline newline
179 \end_inset
180
181 #
182 \begin_inset Newline newline
183 \end_inset
184
185 <<Setup variables from user supplied args>>
186 \begin_inset Newline newline
187 \end_inset
188
189 <<Subroutines>>
190 \begin_inset Newline newline
191 \end_inset
192
193 <<Convert noweb to LyX>>
194 \begin_inset Newline newline
195 \end_inset
196
197 @
198 \end_layout
199
200 \begin_layout Section
201 The Noweb file defined
202 \end_layout
203
204 \begin_layout Standard
205
206 \noun on
207 noweb
208 \noun default
209  file is a collection of documentation and code chunks.
210  Documentation chunks simply start with an ``@'' and have no name:
211 \end_layout
212
213 \begin_layout LyX-Code
214 @ Here is some documentation.
215 \begin_inset Newline newline
216 \end_inset
217
218 We can do arbitrary LaTeX code here.
219 \begin_inset Newline newline
220 \end_inset
221
222 [...
223  blah blah blah ...]
224 \end_layout
225
226 \begin_layout Standard
227 Code chunks look like this:
228 \end_layout
229
230 \begin_layout LyX-Code
231 <
232 \begin_inset ERT
233 status collapsed
234
235 \begin_layout Plain Layout
236
237 {}
238 \end_layout
239
240 \end_inset
241
242 <Name of chunk here>
243 \begin_inset ERT
244 status collapsed
245
246 \begin_layout Plain Layout
247
248 {}
249 \end_layout
250
251 \end_inset
252
253 >=
254 \begin_inset Newline newline
255 \end_inset
256
257 {...
258  code for the chunk goes here ...}
259 \begin_inset Newline newline
260 \end_inset
261
262
263 \end_layout
264
265 \begin_layout Standard
266 The ``@'' is a necessary delimiter to end the code chunk.
267  The other form that the ``@'' line takes is as follows:
268 \end_layout
269
270 \begin_layout LyX-Code
271 <
272 \begin_inset ERT
273 status collapsed
274
275 \begin_layout Plain Layout
276
277 {}
278 \end_layout
279
280 \end_inset
281
282 <Name of chunk here>
283 \begin_inset ERT
284 status collapsed
285
286 \begin_layout Plain Layout
287
288 {}
289 \end_layout
290
291 \end_inset
292
293 >=
294 \begin_inset Newline newline
295 \end_inset
296
297 {...
298  code for the chunk ...}
299 \begin_inset Newline newline
300 \end_inset
301
302 @ %def identifier1 identifier2
303 \end_layout
304
305 \begin_layout Standard
306 In the latter form, we are declaring to 
307 \noun on
308 noweb
309 \noun default
310  that this code chunk defines identifier1, identifier2, etc.
311 \end_layout
312
313 \begin_layout Standard
314 When first tackling this problem, I spoke with members of the LyX team that
315  knew about the literate programming extensions and reLyX (the LaTeX importing
316  code).
317 \end_layout
318
319 \begin_layout Standard
320 One of the first ideas was to extend the reLyX code to understand the 
321 \noun on
322 noweb
323 \noun default
324  code chunks.
325  This proved to be too hard and presents other problems
326 \begin_inset Foot
327 status collapsed
328
329 \begin_layout Plain Layout
330 Not the least of these problems is the fact that << is a quote in French.
331 \end_layout
332
333 \end_inset
334
335 .
336  On the other hand, it turns out that reLyX contains a very useful literal
337  quoting mechanism.
338  If the input file contains the construct
339 \end_layout
340
341 \begin_layout LyX-Code
342
343 \backslash
344 begin{reLyXskip}
345 \begin_inset Newline newline
346 \end_inset
347
348 {...
349  LaTeX stuff ...}
350 \begin_inset Newline newline
351 \end_inset
352
353
354 \backslash
355 end{reLyXskip}
356 \end_layout
357
358 \begin_layout Standard
359 then reLyX will copy the surrounded code to the output file verbatim.
360  Given this, the first part of the translation is easy; we simply have to
361  copy the code chunks into an intermediate file that surrounds them with
362  
363 \family typewriter
364
365 \backslash
366 begin{reLyXskip}
367 \family default
368  and 
369 \family typewriter
370
371 \backslash
372 end{reLyXskip}
373 \family default
374 .
375 \end_layout
376
377 \begin_layout Standard
378 Once reLyX is done with the input file, the problem is reduced to changing
379  the code chunks from LyX's LaTeX layout to the Scrap layout.
380 \end_layout
381
382 \begin_layout Standard
383 There is one final constraint on 
384 \noun on
385 noweb2lyx
386 \noun default
387 .
388  We want to be able to run it as a simple pre-processor and post-processor
389  from within reLyX.
390  We can accomplish this by setting the flags 
391 \family roman
392 \series medium
393 \shape up
394 \size normal
395 \emph off
396 \bar no
397 \noun off
398 \color none
399
400 \begin_inset ERT
401 status collapsed
402
403 \begin_layout Plain Layout
404
405 [[pre_only]]
406 \end_layout
407
408 \end_inset
409
410
411 \family default
412 \series default
413 \shape default
414 \size default
415 \emph default
416 \bar default
417 \noun default
418  
419 \color inherit
420 and
421 \color none
422  
423 \family roman
424 \series medium
425 \shape up
426 \size normal
427 \emph off
428 \bar no
429 \noun off
430
431 \begin_inset ERT
432 status collapsed
433
434 \begin_layout Plain Layout
435
436 [[post_only]]
437 \end_layout
438
439 \end_inset
440
441
442 \family default
443 \series default
444 \shape default
445 \size default
446 \emph default
447 \bar default
448 \noun default
449  
450 \color inherit
451 before we reach the main conversion code.
452 \end_layout
453
454 \begin_layout Standard
455 With all that preamble out of the way, we now have the basic high-level
456  outline for our code:
457 \end_layout
458
459 \begin_layout Scrap
460 <<Convert noweb to LyX>>=
461 \begin_inset Newline newline
462 \end_inset
463
464 if (!$post_only) {
465 \begin_inset Newline newline
466 \end_inset
467
468   <<Transform noweb for reLyX>>
469 \begin_inset Newline newline
470 \end_inset
471
472 }
473 \begin_inset Newline newline
474 \end_inset
475
476 if ((!$pre_only) && (!$post_only)) {
477 \begin_inset Newline newline
478 \end_inset
479
480   <<Run reLyX on intermediate file>>
481 \begin_inset Newline newline
482 \end_inset
483
484 }
485 \begin_inset Newline newline
486 \end_inset
487
488 if (!$pre_only) {
489 \begin_inset Newline newline
490 \end_inset
491
492   <<Fix up LyX file>>
493 \begin_inset Newline newline
494 \end_inset
495
496 }
497 \begin_inset Newline newline
498 \end_inset
499
500 <<Clean up>>
501 \begin_inset Newline newline
502 \end_inset
503
504 @
505 \end_layout
506
507 \begin_layout Section
508 Making a file that reLyX can process
509 \end_layout
510
511 \begin_layout Standard
512 In this section, we present the code that performs the task of creating
513  the intermediate file that reLyX can process, using the algorithm that
514  we just outlined.
515  This algorithm is outlined in the code that follows:
516 \end_layout
517
518 \begin_layout Scrap
519 <<Transform noweb for reLyX>>=
520 \begin_inset Newline newline
521 \end_inset
522
523 <<Setup INPUT and OUTPUT>>
524 \begin_inset Newline newline
525 \end_inset
526
527 inputline: while(<INPUT>)
528 \begin_inset Newline newline
529 \end_inset
530
531 {
532 \begin_inset Newline newline
533 \end_inset
534
535   if (/^
536 \backslash
537 s*
538 \backslash
539 <
540 \backslash
541 <.*
542 \backslash
543 >
544 \backslash
545 >=/) { # Beginning of a noweb scrap
546 \begin_inset Newline newline
547 \end_inset
548
549     <<Read in and output the noweb code chunk>>
550 \begin_inset Newline newline
551 \end_inset
552
553   } elsif (/^@
554 \backslash
555 s+(.*)/) { # Beginning of a documentation chunk
556 \begin_inset Newline newline
557 \end_inset
558
559     print OUTPUT $1; # We do not need the ``@'' part
560 \begin_inset Newline newline
561 \end_inset
562
563   } elsif (/
564 \backslash
565 [
566 \backslash
567 [.+
568 \backslash
569 ]
570 \backslash
571 ]/) { # noweb quoted code
572 \begin_inset Newline newline
573 \end_inset
574
575     <<Perform special input quoting of [[var]]>>
576 \begin_inset Newline newline
577 \end_inset
578
579   } else {
580 \begin_inset Newline newline
581 \end_inset
582
583     print OUTPUT; # Just let the line pass through
584 \begin_inset Newline newline
585 \end_inset
586
587   }
588 \begin_inset Newline newline
589 \end_inset
590
591 }
592 \begin_inset Newline newline
593 \end_inset
594
595 <<Close INPUT and OUTPUT>>
596 \begin_inset Newline newline
597 \end_inset
598
599 @
600 \end_layout
601
602 \begin_layout Standard
603 In the code above, we do some pre-processing of the noweb ``[[...]]'' construct.
604  This avoids some problems with reLyX confusing lists composed of ``[[...]]''
605  constructs.
606 \end_layout
607
608 \begin_layout Scrap
609 <<Perform special input quoting of [[var]]>>=
610 \begin_inset Newline newline
611 \end_inset
612
613 s/
614 \backslash
615 [
616 \backslash
617 [.+?
618 \backslash
619 ]{2,}/{$&}/g;
620 \begin_inset Newline newline
621 \end_inset
622
623 print OUTPUT;
624 \begin_inset Newline newline
625 \end_inset
626
627 @
628 \end_layout
629
630 \begin_layout Standard
631 While reading in the 
632 \family roman
633 \series medium
634 \shape up
635 \size normal
636 \emph off
637 \bar no
638 \noun off
639 \color none
640
641 \begin_inset ERT
642 status collapsed
643
644 \begin_layout Plain Layout
645
646 [[INPUT]]
647 \end_layout
648
649 \end_inset
650
651
652 \family default
653 \series default
654 \shape default
655 \size default
656 \emph default
657 \bar default
658 \noun default
659  
660 \color inherit
661 file, once we have identified a 
662 \noun on
663 noweb
664 \noun default
665  code chunk, we transform it into a form that is usable by reLyX.
666 \end_layout
667
668 \begin_layout Scrap
669 <<Read in and output the noweb code chunk>>= 
670 \begin_inset Newline newline
671 \end_inset
672
673 <<Save the beginning of the scrap to savedScrap>>
674 \begin_inset Newline newline
675 \end_inset
676
677 <<Concatenate the rest of the scrap>>
678 \begin_inset Newline newline
679 \end_inset
680
681 <<print out the scrap in a reLyXskip block>>
682 \begin_inset Newline newline
683 \end_inset
684
685 @
686 \end_layout
687
688 \begin_layout Subsection
689 File input and output for the pre-processing step
690 \end_layout
691
692 \begin_layout Standard
693 In 
694 \noun on
695 noweb2lyx
696 \noun default
697 , we will use 
698 \family roman
699 \series medium
700 \shape up
701 \size normal
702 \emph off
703 \bar no
704 \noun off
705 \color none
706
707 \begin_inset ERT
708 status collapsed
709
710 \begin_layout Plain Layout
711
712 [[INPUT]]
713 \end_layout
714
715 \end_inset
716
717
718 \family default
719 \series default
720 \shape default
721 \size default
722 \emph default
723 \bar default
724 \noun default
725  
726 \color inherit
727 and
728 \color none
729  
730 \family roman
731 \series medium
732 \shape up
733 \size normal
734 \emph off
735 \bar no
736 \noun off
737
738 \begin_inset ERT
739 status collapsed
740
741 \begin_layout Plain Layout
742
743 [[OUTPUT]]
744 \end_layout
745
746 \end_inset
747
748
749 \family default
750 \series default
751 \shape default
752 \size default
753 \emph default
754 \bar default
755 \noun default
756  
757 \color inherit
758 to read and write files.
759  In the code fragment above, we need to read from the input file and write
760  to a file that will be later transformed by reLyX.
761  If we are being called only to pre-process the input file, then there is
762  no need to create a temporary file.
763 \end_layout
764
765 \begin_layout Scrap
766 <<Setup INPUT and OUTPUT>>=
767 \begin_inset Newline newline
768 \end_inset
769
770 if ($pre_only) {
771 \begin_inset Newline newline
772 \end_inset
773
774   &setup_files($input_file, $output_file);
775 \begin_inset Newline newline
776 \end_inset
777
778 } else {
779 \begin_inset Newline newline
780 \end_inset
781
782   $relyx_file = "temp$$";
783 \begin_inset Newline newline
784 \end_inset
785
786   &setup_files($input_file, $relyx_file);
787 \begin_inset Newline newline
788 \end_inset
789
790 }
791 \begin_inset Newline newline
792 \end_inset
793
794 @
795 \end_layout
796
797 \begin_layout Standard
798 This code uses a small perl subroutine, 
799 \family roman
800 \series medium
801 \shape up
802 \size normal
803 \emph off
804 \bar no
805 \noun off
806 \color none
807
808 \begin_inset ERT
809 status collapsed
810
811 \begin_layout Plain Layout
812
813 [[setup_files]]
814 \end_layout
815
816 \end_inset
817
818
819 \family default
820 \series default
821 \shape default
822 \size default
823 \emph default
824 \bar default
825 \noun default
826 \color inherit
827 , which we define below:
828 \end_layout
829
830 \begin_layout Scrap
831 <<Subroutines>>=
832 \begin_inset Newline newline
833 \end_inset
834
835 sub setup_files {
836 \begin_inset Newline newline
837 \end_inset
838
839   my($in, $out) = @_;
840 \begin_inset Newline newline
841 \end_inset
842
843   open(INPUT, "<$in") || die "Cannot read $in: $!
844 \backslash
845 n";
846 \begin_inset Newline newline
847 \end_inset
848
849   open(OUTPUT, ">$out") || die "Cannot write $out: $!
850 \backslash
851 n";
852 \begin_inset Newline newline
853 \end_inset
854
855 }
856 \begin_inset Newline newline
857 \end_inset
858
859 @ %def setup_files   
860 \end_layout
861
862 \begin_layout Subsection
863 Reading in the 
864 \noun on
865 noweb
866 \noun default
867  scrap
868 \end_layout
869
870 \begin_layout Standard
871 After we see the beginning of the scrap, we need to read in and save the
872  rest of the scrap for output.
873 \end_layout
874
875 \begin_layout Scrap
876 <<Save the beginning of the scrap to savedScrap>>=
877 \begin_inset Newline newline
878 \end_inset
879
880 $savedScrap = $_;
881 \begin_inset Newline newline
882 \end_inset
883
884 $endLine = "";
885 \begin_inset Newline newline
886 \end_inset
887
888 @
889 \end_layout
890
891 \begin_layout Scrap
892 <<Concatenate the rest of the scrap>>=
893 \begin_inset Newline newline
894 \end_inset
895
896 scrapline: while (<INPUT>) {
897 \begin_inset Newline newline
898 \end_inset
899
900   last scrapline if /^@
901 \backslash
902 s+/;
903 \begin_inset Newline newline
904 \end_inset
905
906   $savedScrap .= $_;
907 \begin_inset Newline newline
908 \end_inset
909
910 };
911 \begin_inset Newline newline
912 \end_inset
913
914 switch: {
915 \begin_inset Newline newline
916 \end_inset
917
918   if (/^@
919 \backslash
920 s+$/) {$savedScrap .= $_; last switch; }
921 \begin_inset Newline newline
922 \end_inset
923
924   if (/^@
925 \backslash
926 s+%def.*$/) {$savedScrap .= $_; last switch; }
927 \begin_inset Newline newline
928 \end_inset
929
930   if (/^@
931 \backslash
932 s+(.*)$/) {$savedScrap .= "@
933 \backslash
934 n"; $endLine = "$1
935 \backslash
936 n"; }
937 \begin_inset Newline newline
938 \end_inset
939
940 }
941 \begin_inset Newline newline
942 \end_inset
943
944 @
945 \end_layout
946
947 \begin_layout Subsection
948 Printing out the scrap
949 \end_layout
950
951 \begin_layout Standard
952 The final piece of the first pass of the conversion is done by this code.
953 \end_layout
954
955 \begin_layout Scrap
956 <<print out the scrap in a reLyXskip block>>=
957 \begin_inset Newline newline
958 \end_inset
959
960 print OUTPUT "
961 \backslash
962
963 \backslash
964 begin{reLyXskip}
965 \backslash
966 n";
967 \begin_inset Newline newline
968 \end_inset
969
970 print OUTPUT $savedScrap;
971 \begin_inset Newline newline
972 \end_inset
973
974 print OUTPUT "
975 \backslash
976
977 \backslash
978 end{reLyXskip}
979 \backslash
980 n
981 \backslash
982 n";
983 \begin_inset Newline newline
984 \end_inset
985
986 print OUTPUT "$endLine";
987 \begin_inset Newline newline
988 \end_inset
989
990 @
991 \end_layout
992
993 \begin_layout Standard
994 Finally, we need to close the 
995 \family roman
996 \series medium
997 \shape up
998 \size normal
999 \emph off
1000 \bar no
1001 \noun off
1002 \color none
1003
1004 \begin_inset ERT
1005 status collapsed
1006
1007 \begin_layout Plain Layout
1008
1009 [[INPUT]]
1010 \end_layout
1011
1012 \end_inset
1013
1014
1015 \family default
1016 \series default
1017 \shape default
1018 \size default
1019 \emph default
1020 \bar default
1021 \noun default
1022  
1023 \color inherit
1024 and
1025 \color none
1026  
1027 \family roman
1028 \series medium
1029 \shape up
1030 \size normal
1031 \emph off
1032 \bar no
1033 \noun off
1034
1035 \begin_inset ERT
1036 status collapsed
1037
1038 \begin_layout Plain Layout
1039
1040 [[OUTPUT]]
1041 \end_layout
1042
1043 \end_inset
1044
1045
1046 \family default
1047 \series default
1048 \shape default
1049 \size default
1050 \emph default
1051 \bar default
1052 \noun default
1053  
1054 \color inherit
1055 files.
1056 \end_layout
1057
1058 \begin_layout Scrap
1059 <<Close INPUT and OUTPUT>>=
1060 \begin_inset Newline newline
1061 \end_inset
1062
1063 close(INPUT);
1064 \begin_inset Newline newline
1065 \end_inset
1066
1067 close(OUTPUT);
1068 \begin_inset Newline newline
1069 \end_inset
1070
1071 @
1072 \end_layout
1073
1074 \begin_layout Section
1075 Running reLyX
1076 \end_layout
1077
1078 \begin_layout Standard
1079 In this section, we describe and implement the code that runs reLyX on the
1080  intermediate file 
1081 \family roman
1082 \series medium
1083 \shape up
1084 \size normal
1085 \emph off
1086 \bar no
1087 \noun off
1088 \color none
1089
1090 \begin_inset ERT
1091 status collapsed
1092
1093 \begin_layout Plain Layout
1094
1095 [[relyx_file]]
1096 \end_layout
1097
1098 \end_inset
1099
1100
1101 \family default
1102 \series default
1103 \shape default
1104 \size default
1105 \emph default
1106 \bar default
1107 \noun default
1108 \color inherit
1109 .
1110  
1111 \end_layout
1112
1113 \begin_layout Subsection
1114 Selecting the document class
1115 \end_layout
1116
1117 \begin_layout Standard
1118 In order to run reLyX, we need to know the article class of the input document
1119  (to choose the corresponding literate document layout).
1120  For this, we need to parse the intermediate file.
1121 \end_layout
1122
1123 \begin_layout Scrap
1124 <<Run reLyX on intermediate file>>=
1125 \begin_inset Newline newline
1126 \end_inset
1127
1128 <<Parse for document class>>
1129 \begin_inset Newline newline
1130 \end_inset
1131
1132 <<Run reLyX with document class>>
1133 \begin_inset Newline newline
1134 \end_inset
1135
1136 @
1137 \end_layout
1138
1139 \begin_layout Standard
1140 In the code below, you'll see a strange regular expression to search for
1141  the document class.
1142  The reason for this kludge is that without it, we can't run 
1143 \noun on
1144 noweb2lyx
1145 \noun default
1146  on the 
1147 \emph on
1148 noweb2lyx.nw
1149 \emph default
1150  file that is generated by LyX
1151 \begin_inset Foot
1152 status collapsed
1153
1154 \begin_layout Plain Layout
1155 reLyX searches for 
1156 \backslash
1157
1158 \backslash
1159 doc
1160 \family roman
1161 \series medium
1162 \shape up
1163 \size normal
1164 \emph off
1165 \bar no
1166 \noun off
1167 \color none
1168
1169 \begin_inset ERT
1170 status collapsed
1171
1172 \begin_layout Plain Layout
1173
1174 {}
1175 \end_layout
1176
1177 \end_inset
1178
1179
1180 \family default
1181 \series default
1182 \shape default
1183 \size default
1184 \emph default
1185 \bar default
1186 \noun default
1187 \color inherit
1188 ument
1189 \family roman
1190 \series medium
1191 \shape up
1192 \size normal
1193 \emph off
1194 \bar no
1195 \noun off
1196 \color none
1197
1198 \begin_inset ERT
1199 status collapsed
1200
1201 \begin_layout Plain Layout
1202
1203 {}
1204 \end_layout
1205
1206 \end_inset
1207
1208
1209 \family default
1210 \series default
1211 \shape default
1212 \size default
1213 \emph default
1214 \bar default
1215 \noun default
1216 \color inherit
1217 class and gets confused, so we have to obfuscate it slightly.
1218 \end_layout
1219
1220 \end_inset
1221
1222 .
1223  With the regular expression as it is, we can actually run 
1224 \noun on
1225 noweb2lyx
1226 \noun default
1227  on itself and a produce a quite reasonable LyX file.
1228 \end_layout
1229
1230 \begin_layout Scrap
1231 <<Parse for document class>>=
1232 \begin_inset Newline newline
1233 \end_inset
1234
1235 open(INPUT, "<$relyx_file") ||
1236 \begin_inset Newline newline
1237 \end_inset
1238
1239   die "Cannot read $relyx_file: $!
1240 \backslash
1241 n";
1242 \begin_inset Newline newline
1243 \end_inset
1244
1245 $class = "article"; # default if none found
1246 \begin_inset Newline newline
1247 \end_inset
1248
1249 parse: while(<INPUT>) {
1250 \begin_inset Newline newline
1251 \end_inset
1252
1253   if (/
1254 \backslash
1255
1256 \backslash
1257 docu[m]entclass{(.*)}/) {
1258 \begin_inset Newline newline
1259 \end_inset
1260
1261     $class = $1;
1262 \begin_inset Newline newline
1263 \end_inset
1264
1265     last parse;
1266 \begin_inset Newline newline
1267 \end_inset
1268
1269   }
1270 \begin_inset Newline newline
1271 \end_inset
1272
1273 }
1274 \begin_inset Newline newline
1275 \end_inset
1276
1277 close(INPUT);
1278 \begin_inset Newline newline
1279 \end_inset
1280
1281 @
1282 \end_layout
1283
1284 \begin_layout Subsection
1285 Running reLyX with the corresponding literate document layout
1286 \end_layout
1287
1288 \begin_layout Standard
1289 Now that we know what the document class ought to be, we do:
1290 \end_layout
1291
1292 \begin_layout Scrap
1293 <<Run reLyX with document class>>= 
1294 \begin_inset Newline newline
1295 \end_inset
1296
1297 $doc_class = "literate-" .
1298  $class;
1299 \begin_inset Newline newline
1300 \end_inset
1301
1302 die "reLyX returned non-zero: $!
1303 \backslash
1304 n"
1305 \begin_inset Newline newline
1306 \end_inset
1307
1308   if (system("reLyX -c $doc_class $relyx_file"));
1309 \begin_inset Newline newline
1310 \end_inset
1311
1312 @
1313 \end_layout
1314
1315 \begin_layout Standard
1316 reLyX performs the main bulk of the translation work.
1317  Note that if the ``literate-
1318 \emph on
1319 class
1320 \emph default
1321 '' document layout is not found, then reLyX will fail with an error.
1322  In that case, you may need to modify your 
1323 \noun on
1324 noweb
1325 \noun default
1326  input file to a supported document type.
1327 \end_layout
1328
1329 \begin_layout Section
1330 Fixing the reLyX output
1331 \end_layout
1332
1333 \begin_layout Standard
1334 We need to perform some post-processing of what reLyX produces in order
1335  to have the best output for our literate document.
1336  The outline of the post-processing steps are:
1337 \end_layout
1338
1339 \begin_layout Scrap
1340 <<Fix up LyX file>>=
1341 \begin_inset Newline newline
1342 \end_inset
1343
1344 <<Setup INPUT and OUTPUT for the final output>>
1345 \begin_inset Newline newline
1346 \end_inset
1347
1348 line: while(<INPUT>)
1349 \begin_inset Newline newline
1350 \end_inset
1351
1352 {
1353 \begin_inset Newline newline
1354 \end_inset
1355
1356   <<Fix code chunks in latex layout>>
1357 \begin_inset Newline newline
1358 \end_inset
1359
1360   <<Fix [[var]] noweb construct>>
1361 \begin_inset Newline newline
1362 \end_inset
1363
1364   print OUTPUT; # default
1365 \begin_inset Newline newline
1366 \end_inset
1367
1368
1369 \begin_inset Newline newline
1370 \end_inset
1371
1372 <<Close INPUT and OUTPUT>>
1373 \begin_inset Newline newline
1374 \end_inset
1375
1376 @
1377 \end_layout
1378
1379 \begin_layout Standard
1380 Note that in the perl code that is contained in the 
1381 \family roman
1382 \series medium
1383 \shape up
1384 \size normal
1385 \emph off
1386 \bar no
1387 \noun off
1388 \color none
1389
1390 \begin_inset ERT
1391 status collapsed
1392
1393 \begin_layout Plain Layout
1394
1395 [[while(<INPUT>)]]
1396 \end_layout
1397
1398 \end_inset
1399
1400
1401 \family default
1402 \series default
1403 \shape default
1404 \size default
1405 \emph default
1406 \bar default
1407 \noun default
1408  
1409 \color inherit
1410 loop above, the perl construct
1411 \color none
1412  
1413 \family roman
1414 \series medium
1415 \shape up
1416 \size normal
1417 \emph off
1418 \bar no
1419 \noun off
1420
1421 \begin_inset ERT
1422 status collapsed
1423
1424 \begin_layout Plain Layout
1425
1426 [[next line]]
1427 \end_layout
1428
1429 \end_inset
1430
1431
1432 \family default
1433 \series default
1434 \shape default
1435 \size default
1436 \emph default
1437 \bar default
1438 \noun default
1439  
1440 \color inherit
1441 is sufficient to restart the loop.
1442  We can use this construct to do some relatively complex parsing of the
1443  reLyX generated file.
1444 \end_layout
1445
1446 \begin_layout Subsection
1447 File input and output for the post-processing
1448 \end_layout
1449
1450 \begin_layout Standard
1451 Setting up the 
1452 \family roman
1453 \series medium
1454 \shape up
1455 \size normal
1456 \emph off
1457 \bar no
1458 \noun off
1459 \color none
1460
1461 \begin_inset ERT
1462 status collapsed
1463
1464 \begin_layout Plain Layout
1465
1466 [[INPUT]]
1467 \end_layout
1468
1469 \end_inset
1470
1471
1472 \family default
1473 \series default
1474 \shape default
1475 \size default
1476 \emph default
1477 \bar default
1478 \noun default
1479  
1480 \color inherit
1481 and
1482 \color none
1483  
1484 \family roman
1485 \series medium
1486 \shape up
1487 \size normal
1488 \emph off
1489 \bar no
1490 \noun off
1491
1492 \begin_inset ERT
1493 status collapsed
1494
1495 \begin_layout Plain Layout
1496
1497 [[OUTPUT]]
1498 \end_layout
1499
1500 \end_inset
1501
1502
1503 \family default
1504 \series default
1505 \shape default
1506 \size default
1507 \emph default
1508 \bar default
1509 \noun default
1510  
1511 \color inherit
1512 is taken care of by this code:
1513 \end_layout
1514
1515 \begin_layout Scrap
1516 <<Setup INPUT and OUTPUT for the final output>>=
1517 \begin_inset Newline newline
1518 \end_inset
1519
1520 if ($post_only) {
1521 \begin_inset Newline newline
1522 \end_inset
1523
1524   &setup_files("$input_file", "$output_file");
1525 \begin_inset Newline newline
1526 \end_inset
1527
1528 } else {
1529 \begin_inset Newline newline
1530 \end_inset
1531
1532   &setup_files("$relyx_file.lyx", "$output_file");
1533 \begin_inset Newline newline
1534 \end_inset
1535
1536 }
1537 \begin_inset Newline newline
1538 \end_inset
1539
1540 @
1541 \end_layout
1542
1543 \begin_layout Subsection
1544 Making sure the code chunks are in the Scrap layout
1545 \end_layout
1546
1547 \begin_layout Standard
1548 Now, as we outlined before, the final step is transforming the code-chunks
1549  which have been put into a LaTeX layout by LyX into the scrap layout.
1550 \end_layout
1551
1552 \begin_layout Scrap
1553 <<Fix code chunks in latex layout>>=
1554 \begin_inset Newline newline
1555 \end_inset
1556
1557 if (/
1558 \backslash
1559
1560 \backslash
1561 latex latex/) { # Beginning of some latex code
1562 \begin_inset Newline newline
1563 \end_inset
1564
1565   if (($line = <INPUT>) =~ /^
1566 \backslash
1567 s*<</) { # code scrap
1568 \begin_inset Newline newline
1569 \end_inset
1570
1571     <<Transform this chunk into layout scrap>>
1572 \begin_inset Newline newline
1573 \end_inset
1574
1575   } else {
1576 \begin_inset Newline newline
1577 \end_inset
1578
1579     # print the 
1580 \backslash
1581 latex latex line + next line
1582 \begin_inset Newline newline
1583 \end_inset
1584
1585     print OUTPUT "$_$line";
1586 \begin_inset Newline newline
1587 \end_inset
1588
1589   }
1590 \begin_inset Newline newline
1591 \end_inset
1592
1593   next line;
1594 \begin_inset Newline newline
1595 \end_inset
1596
1597 }
1598 \begin_inset Newline newline
1599 \end_inset
1600
1601 @
1602 \end_layout
1603
1604 \begin_layout Standard
1605 When we are sure that we are in a code chunk, we must read in the rest of
1606  the code chunk and output a scrap layout for it:
1607 \end_layout
1608
1609 \begin_layout Scrap
1610 <<Transform this chunk into layout scrap>>=
1611 \begin_inset Newline newline
1612 \end_inset
1613
1614 $savedScrap = "
1615 \backslash
1616
1617 \backslash
1618 layout Scrap
1619 \backslash
1620 n
1621 \backslash
1622 n$line";
1623 \begin_inset Newline newline
1624 \end_inset
1625
1626 codeline: while (<INPUT>) {
1627 \begin_inset Newline newline
1628 \end_inset
1629
1630   $savedScrap .= $_;
1631 \begin_inset Newline newline
1632 \end_inset
1633
1634   last codeline if /^@
1635 \backslash
1636 s+/;
1637 \begin_inset Newline newline
1638 \end_inset
1639
1640 };
1641 \begin_inset Newline newline
1642 \end_inset
1643
1644 print OUTPUT $savedScrap;
1645 \begin_inset Newline newline
1646 \end_inset
1647
1648 <<Slurp up to the end of the latex layout>>
1649 \begin_inset Newline newline
1650 \end_inset
1651
1652 @
1653 \end_layout
1654
1655 \begin_layout Standard
1656 Okay, now we just need to eat the rest of the latex layout.
1657  There should only be a few different types of lines for us to match:
1658 \end_layout
1659
1660 \begin_layout Scrap
1661 <<Slurp up to the end of the latex layout>>=
1662 \begin_inset Newline newline
1663 \end_inset
1664
1665 slurp: while (<INPUT>) {
1666 \begin_inset Newline newline
1667 \end_inset
1668
1669   last slurp if /
1670 \backslash
1671
1672 \backslash
1673 latex /;
1674 \begin_inset Newline newline
1675 \end_inset
1676
1677   next slurp if /
1678 \backslash
1679
1680 \backslash
1681 newline/;
1682 \begin_inset Newline newline
1683 \end_inset
1684
1685   next slurp if /^
1686 \backslash
1687 s*$/;
1688 \begin_inset Newline newline
1689 \end_inset
1690
1691   warn "confused by line: $_";
1692 \begin_inset Newline newline
1693 \end_inset
1694
1695 }
1696 \begin_inset Newline newline
1697 \end_inset
1698
1699 @
1700 \end_layout
1701
1702 \begin_layout Subsection
1703 Taking care of the 
1704 \noun on
1705 noweb
1706 \noun default
1707  
1708 \emph on
1709 [[quoted code]]
1710 \emph default
1711  construct
1712 \end_layout
1713
1714 \begin_layout Standard
1715
1716 \noun on
1717 noweb
1718 \noun default
1719  allows the user to use a special code quoting mechanism in documentation
1720  chunks.
1721  Fixing this ``[[quoted-code]]'' 
1722 \noun on
1723 noweb
1724 \noun default
1725  syntax means putting the ``[[quoted-code]]'' in a LaTeX layout in the LyX
1726  file.
1727  Otherwise, LyX will backslash-quote the brackets, creating ugly output.
1728  The quoted-code is transformed by 
1729 \noun on
1730 noweb
1731 \noun default
1732  when it generates the final LaTeX code.
1733 \end_layout
1734
1735 \begin_layout Scrap
1736 <<Fix [[var]] noweb construct>>=
1737 \begin_inset Newline newline
1738 \end_inset
1739
1740 if (/
1741 \backslash
1742 [
1743 \backslash
1744 [.+
1745 \backslash
1746 ]
1747 \backslash
1748 ]/) { # special code for [[var]]
1749 \begin_inset Newline newline
1750 \end_inset
1751
1752   s/
1753 \backslash
1754 [
1755 \backslash
1756 [.+?
1757 \backslash
1758 ]{2,}/
1759 \backslash
1760 n
1761 \backslash
1762
1763 \backslash
1764 latex latex
1765 \backslash
1766 n$&
1767 \backslash
1768 n
1769 \backslash
1770
1771 \backslash
1772 latex default
1773 \backslash
1774 n/g;
1775 \begin_inset Newline newline
1776 \end_inset
1777
1778   print OUTPUT;
1779 \begin_inset Newline newline
1780 \end_inset
1781
1782   next line;
1783 \begin_inset Newline newline
1784 \end_inset
1785
1786 }
1787 \begin_inset Newline newline
1788 \end_inset
1789
1790 @
1791 \end_layout
1792
1793 \begin_layout Section
1794 Cleaning up intermediate files
1795 \end_layout
1796
1797 \begin_layout Standard
1798 The cleanup code is very simple:
1799 \end_layout
1800
1801 \begin_layout Scrap
1802 <<Clean up>>=
1803 \begin_inset Newline newline
1804 \end_inset
1805
1806 system("rm -f $relyx_file*") unless ($post_only || $pre_only);
1807 \begin_inset Newline newline
1808 \end_inset
1809
1810 @
1811 \end_layout
1812
1813 \begin_layout Section
1814 User supplied arguments
1815 \end_layout
1816
1817 \begin_layout Standard
1818 The 
1819 \noun on
1820 noweb2lyx
1821 \noun default
1822  script understands two arguments, input-file and output-file.
1823  It is also set up to be used internally by reLyX to pre-process or postprocess
1824  files in the import pipeline.
1825 \end_layout
1826
1827 \begin_layout Scrap
1828 <<Setup variables from user supplied args>>=
1829 \begin_inset Newline newline
1830 \end_inset
1831
1832 &usage() if ($#ARGV < 1); # zero or one argument 
1833 \begin_inset Newline newline
1834 \end_inset
1835
1836 if ($ARGV[0] eq "-pre") {
1837 \begin_inset Newline newline
1838 \end_inset
1839
1840   &usage unless ($#ARGV == 2);
1841 \begin_inset Newline newline
1842 \end_inset
1843
1844   $input_file = $ARGV[1]; $output_file = $ARGV[2]; $pre_only = 1;
1845 \begin_inset Newline newline
1846 \end_inset
1847
1848 } elsif ($ARGV[0] eq "-post") {
1849 \begin_inset Newline newline
1850 \end_inset
1851
1852   &usage unless ($#ARGV == 2);
1853 \begin_inset Newline newline
1854 \end_inset
1855
1856   $input_file = $ARGV[1]; $output_file = $ARGV[2]; $post_only = 1;
1857 \begin_inset Newline newline
1858 \end_inset
1859
1860 } else {
1861 \begin_inset Newline newline
1862 \end_inset
1863
1864   &usage unless ($#ARGV == 1);
1865 \begin_inset Newline newline
1866 \end_inset
1867
1868   $input_file = $ARGV[0]; $output_file = $ARGV[1];
1869 \begin_inset Newline newline
1870 \end_inset
1871
1872   $pre_only = 0; $post_only = 0;
1873 \begin_inset Newline newline
1874 \end_inset
1875
1876 }
1877 \begin_inset Newline newline
1878 \end_inset
1879
1880 @ %def input_file output_file pre_only post_only
1881 \end_layout
1882
1883 \begin_layout Scrap
1884 <<Subroutines>>=
1885 \begin_inset Newline newline
1886 \end_inset
1887
1888 sub usage() {
1889 \begin_inset Newline newline
1890 \end_inset
1891
1892   print "Usage: noweb2lyx [-pre | -post] input-file output-file
1893 \begin_inset Newline newline
1894 \end_inset
1895
1896
1897 \begin_inset Newline newline
1898 \end_inset
1899
1900 If -pre is specified, only pre-processes the input-file for reLyX.
1901 \begin_inset Newline newline
1902 \end_inset
1903
1904 Similarly, in the case of -post, post-processes reLyX output.
1905 \begin_inset Newline newline
1906 \end_inset
1907
1908 In case of bugs, Email Kayvan Sylvan <kayvan
1909 \backslash
1910 @sylvan.com>.
1911 \backslash
1912 n";
1913 \begin_inset Newline newline
1914 \end_inset
1915
1916   exit;
1917 \begin_inset Newline newline
1918 \end_inset
1919
1920 }
1921 \begin_inset Newline newline
1922 \end_inset
1923
1924 @ %def usage
1925 \end_layout
1926
1927 \begin_layout Section
1928 Generating the 
1929 \noun on
1930 noweb2lyx
1931 \noun default
1932  script
1933 \end_layout
1934
1935 \begin_layout Standard
1936 The noweb2lyx script can be tangled from LyX if you set 
1937 \family typewriter
1938
1939 \backslash
1940 build_command
1941 \family default
1942  to call a generic script that always extracts a scrap named 
1943 \family typewriter
1944 build-script
1945 \family default
1946  and executes it.
1947  Here is an example of such a script:
1948 \end_layout
1949
1950 \begin_layout LyX-Code
1951 #!/bin/sh
1952 \begin_inset Newline newline
1953 \end_inset
1954
1955 notangle -Rbuild-script $1 | sh
1956 \end_layout
1957
1958 \begin_layout Scrap
1959 <<build-script>>=
1960 \begin_inset Newline newline
1961 \end_inset
1962
1963 PREFIX=/usr
1964 \begin_inset Newline newline
1965 \end_inset
1966
1967 notangle -Rnoweb2lyx.in noweb2lyx.nw > noweb2lyx.in
1968 \begin_inset Newline newline
1969 \end_inset
1970
1971 sed -e "s=@PERL@=$PREFIX/bin/perl=" noweb2lyx.in > noweb2lyx
1972 \begin_inset Newline newline
1973 \end_inset
1974
1975 chmod +x noweb2lyx
1976 \begin_inset Newline newline
1977 \end_inset
1978
1979 @
1980 \end_layout
1981
1982 \begin_layout Standard
1983 \begin_inset Newpage newpage
1984 \end_inset
1985
1986
1987 \end_layout
1988
1989 \begin_layout Section*
1990 Macros
1991 \end_layout
1992
1993 \begin_layout Standard
1994
1995 \family roman
1996 \series medium
1997 \shape up
1998 \size normal
1999 \emph off
2000 \bar no
2001 \noun off
2002 \color none
2003 \begin_inset ERT
2004 status collapsed
2005
2006 \begin_layout Plain Layout
2007
2008
2009 \backslash
2010 nowebchunks
2011 \end_layout
2012
2013 \end_inset
2014
2015
2016 \end_layout
2017
2018 \begin_layout Section*
2019 Identifiers
2020 \end_layout
2021
2022 \begin_layout Standard
2023
2024 \family roman
2025 \series medium
2026 \shape up
2027 \size normal
2028 \emph off
2029 \bar no
2030 \noun off
2031 \color none
2032 \begin_inset ERT
2033 status collapsed
2034
2035 \begin_layout Plain Layout
2036
2037
2038 \backslash
2039 nowebindex
2040 \end_layout
2041
2042 \end_inset
2043
2044
2045 \end_layout
2046
2047 \end_body
2048 \end_document