wip
[newfangle.git] / fangle.tm
blob9d16310683d0d3209637a72a9de6ef4ea2e618e7
1 <TeXmacs|1.0.7.15>
3 <style|<tuple|book|fangle|header-book|tmdoc-keyboard>>
5 <\body>
6   <hide-preamble|<assign|LyX|<macro|L<space|-0.1667em><move|Y|0fn|-0.25em><space|-0.125em>X>><assign|par-first|0fn><assign|par-par-sep|0.5fn>>
8   <doc-data|<doc-title|fangle>|<doc-author-data|<author-name|Sam
9   Liddicott>|<\author-address>
10     sam@liddicott.com
11   </author-address>>|<doc-date|August 2009>>
13   <section*|Introduction>
15   <name|Fangle> is a tool for fangled literate programming. Newfangled is
16   defined as <em|New and often needlessly novel> by
17   <name|TheFreeDictionary.com>.
19   In this case, fangled means yet another not-so-new<footnote|but improved.>
20   method for literate programming.
22   <name|Literate Programming> has a long history starting with the great
23   <name|Donald Knuth> himself, whose literate programming tools seem to make
24   use of as many escape sequences for semantic markup as <TeX> (also by
25   <name|Donald Knuth>).
27   <name|Norman Ramsey> wrote the <name|Noweb> set of tools
28   (<verbatim|notangle>, <verbatim|noweave> and <verbatim|noroots>) and
29   helpfully reduced the amount of magic character sequences to pretty much
30   just <verbatim|\<less\>\<less\>>, <verbatim|\<gtr\>\<gtr\>> and
31   <verbatim|@>, and in doing so brought the wonders of literate programming
32   within my reach.
34   While using the <LyX> editor for <LaTeX> editing I had various troubles
35   with the noweb tools, some of which were my fault, some of which were
36   noweb's fault and some of which were <LyX>'s fault.
38   <name|Noweb> generally brought literate programming to the masses through
39   removing some of the complexity of the original literate programming, but
40   this would be of no advantage to me if the <LyX> / <LaTeX> combination
41   brought more complications in their place.
43   <name|Fangle> was thus born (originally called <name|Newfangle>) as an awk
44   replacement for notangle, adding some important features, like better
45   integration with <LyX> and <LaTeX> (and later <TeXmacs>), multiple output
46   format conversions, and fixing notangle bugs like indentation when using -L
47   for line numbers.
49   Significantly, fangle is just one program which replaces various programs
50   in <name|Noweb>. Noweave is done away with and implemented directly as
51   <LaTeX> macros, and noroots is implemented as a function of the untangler
52   fangle.
54   Fangle is written in awk for portability reasons, awk being available for
55   most platforms. A Python version<\footnote>
56     hasn't anyone implemented awk in python yet?
57   </footnote> was considered for the benefit of <LyX> but a scheme version
58   for <TeXmacs> will probably materialise first; as <TeXmacs> macro
59   capabilities help make edit-time and format-time rendering of fangle chunks
60   simple enough for my weak brain.
62   As an extension to many literate-programming styles, Fangle permits code
63   chunks to take parameters and thus operate somewhat like C pre-processor
64   macros, or like C++ templates. Name parameters (or even local
65   <em|variables> in the callers scope) are anticipated, as parameterized
66   chunks <emdash> useful though they are <emdash> are hard to comprehend in
67   the literate document.
69   <section*|License><new-page*><label|License>
71   Fangle is licensed under the GPL 3 (or later).
73   This doesn't mean that sources generated by fangle must be licensed under
74   the GPL 3.
76   This doesn't mean that you can't use or distribute fangle with sources of
77   an incompatible license, but it means you must make the source of fangle
78   available too.
80   As fangle is currently written in awk, an interpreted language, this should
81   not be too hard.
83   <\nf-chunk|gpl3-copyright>
84     <item>fangle - fully featured notangle replacement in awk
86     <item>
88     <item>Copyright (C) 2009-2010 Sam Liddicott
89     \<less\>sam@liddicott.com\<gtr\>
91     <item>
93     <item>This program is free software: you can redistribute it and/or
94     modify
96     <item>it under the terms of the GNU General Public License as published
97     by
99     <item>the Free Software Foundation, either version 3 of the License, or
101     <item>(at your option) any later version.
103     <item>
105     <item>This program is distributed in the hope that it will be useful,
107     <item>but WITHOUT ANY WARRANTY; without even the implied warranty of
109     <item>MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. \ See the
111     <item>GNU General Public License for more details.
113     <item>
115     <item>You should have received a copy of the GNU General Public License
117     <item>along with this program. \ If not, see
118     \<less\>http://www.gnu.org/licenses/\<gtr\>.
119   </nf-chunk|text|>
121   <\table-of-contents|toc>
122   </table-of-contents>
124   <part|Using Fangle>
126   <chapter|Introduction to Literate Programming>
128   Todo: Should really follow on from a part-0 explanation of what literate
129   programming is.
131   <chapter|Running Fangle>
133   Fangle is a replacement for <name|noweb>, which consists of
134   <verbatim|notangle>, <verbatim|noroots> and <verbatim|noweave>.
136   Like <verbatim|notangle> and <verbatim|noroots>, <verbatim|fangle> can read
137   multiple named files, or from stdin.
139   <section|Listing roots>
141   The -r option causes fangle to behave like noroots.
143   <code*|fangle -r filename.tex>
145   will print out the fangle roots of a tex file.\ 
147   Unlike the <verbatim|noroots> command, the printed roots are not enclosed
148   in angle brackets e.g. <verbatim|\<less\>\<less\>name\<gtr\>\<gtr\>>,
149   unless at least one of the roots is defined using the <verbatim|notangle>
150   notation <verbatim|\<less\>\<less\>name\<gtr\>\<gtr\>=>.
152   Also, unlike noroots, it prints out all roots --- not just those that are
153   not used elsewhere. I find that a root not being used doesn't make it
154   particularly top level <emdash> and so-called top level roots could also be
155   included in another root as well.\ 
157   My convention is that top level roots to be extracted begin with
158   <verbatim|./> and have the form of a filename.
160   Makefile.inc, discussed in <reference|makefile.inc>, can automatically
161   extract all such sources prefixed with <verbatim|./>
163   <section|Extracting roots>
165   notangle's <verbatim|-R> and <verbatim|-L> options are supported.
167   If you are using <LyX> or <LaTeX>, the standard way to extract a file would
168   be:
170   <verbatim|fangle -R./Makefile.inc fangle.tex \<gtr\> ./Makefile.inc>
172   If you are using <TeXmacs>, the standard way to extract a file would
173   similarly be:
175   <verbatim|fangle -R./Makefile.inc fangle.txt \<gtr\> ./Makefile.inc>
177   <TeXmacs> users would obtain the text file with a <em|verbatim> export from
178   <TeXmacs> which can be done on the command line with <verbatim|texmacs -s
179   -c fangle.tm fangle.txt -q>
181   Unlike the <verbatim|noroots> command, the <verbatim|<verbatim|-L>> option
182   to generate C pre-preocessor <verbatim|#file> style line-number
183   directives,does not break indenting of the generated file..
185   Also, thanks to mode tracking (described in <reference|modes>) the
186   <verbatim|-L> option does not interrupt (and break) multi-line C macros
187   either.
189   This does mean that sometimes the compiler might calculate the source line
190   wrongly when generating error messages in such cases, but there isn't any
191   other way around if multi-line macros include other chunks.
193   Future releases will include a mapping file so that line/character
194   references from the C compiler can be converted to the correct part of the
195   source document.
197   <section|Formatting the document>
199   The noweave replacement built into the editing and formatting environment
200   for <TeXmacs>, <LyX> (which uses <LaTeX>), and even for raw <LaTeX>.
202   Use of fangle with <TeXmacs>, <LyX> and <LaTeX> are explained the the next
203   few chapters.
205   <chapter|Using Fangle with <LaTeX>>
207   Because the noweave replacement is impemented in <LaTeX>, there is no
208   processing stage required before running the <LaTeX> command. Of course,
209   <LaTeX> may need running two or more times, so that the code chunk
210   references can be fully calculated.
212   The formatting is managed by a set of macros shown in
213   <reference|latex-source>, and can be included with:
215   <verbatim|\\usepackage{fangle.sty}>
217   Norman Ramsay's origial <filename|noweb.sty> package is currently required
218   as it is used for formatting the code chunk captions.
220   The <filename|listings.sty> package is required, and is used for formatting
221   the code chunks and syntax highlighting.
223   The <filename|xargs.sty> package is also required, and makes writing
224   <LaTeX> macro so much more pleasant.
226   <todo|Add examples of use of Macros>
228   <chapter|Using Fangle with <LyX>>
230   <LyX> uses the same <LaTeX> macros shown in <reference|latex-source> as
231   part of a <LyX> module file <filename|fangle.module>, which automatically
232   includes the macros in the document pre-amble provided that the fangle
233   <LyX> module is used in the document.
235   <section|Installing the <LyX> module>
237   Copy <filename|fangle.module> to your <LyX> layouts directory, which for
238   unix users will be <filename|~/.lyx/layouts>
240   In order to make the new literate styles availalble, you will need to
241   reconfigure <LyX> by clicking Tools-\<gtr\>Reconfigure, and then re-start
242   <LyX>.
244   <section|Obtaining a decent mono font>
246   The syntax high-lighting features of <name|lstlistings> makes use of bold;
247   however a mono-space tt font is used to typeset the listings. Obtaining a
248   <with|font-family|tt|<strong|bold> tt font> can be impossibly difficult and
249   amazingly easy. I spent many hours at it, following complicated
250   instructions from those who had spend many hours over it, and was finally
251   delivered the simple solution on the lyx mailing list.
253   <subsection|txfonts>
255   The simple way was to add this to my preamble:
257   <\verbatim>
258     \\usepackage{txfonts}
260     \\renewcommand{\\ttdefault}{txtt}
261   </verbatim>
263   \;
265   <subsection|ams pmb>
267   The next simplest way was to use ams poor-mans-bold, by adding this to the
268   pre-amble:
270   <\verbatim>
271     \\usepackage{amsbsy}
273     %\\renewcommand{\\ttdefault}{txtt}
275     %somehow make \\pmb be the command for bold, forgot how, sorry, above
276     line not work
277   </verbatim>
279   It works, but looks wretched on the dvi viewer.
281   <subsection|Luximono>
283   The lstlistings documention suggests using Luximono.
285   Luximono was installed according to the instructions in Ubuntu Forums
286   thread 1159181<\footnote>
287     http://ubuntuforums.org/showthread.php?t=1159181
288   </footnote> with tips from miknight<\footnote>
289     http://miknight.blogspot.com/2005/11/how-to-install-luxi-mono-font-in.html
290   </footnote> stating that <verbatim|sudo updmap --enable MixedMap ul9.map>
291   is required. It looks fine in PDF and PS view but still looks rotten in dvi
292   view.
294   <section|Formatting your Lyx document>
296   It is not necessary to base your literate document on any of the original
297   <LyX> literate classes; so select a regular class for your document type.
299   Add the new module <em|Fangle Literate Listings> and also <em|Logical
300   Markup> which is very useful.
302   In the drop-down style listbox you should notice a new style defined,
303   called <em|Chunk>.
305   When you wish to insert a literate chunk, you enter it's plain name in the
306   Chunk style, instead of the old <name|noweb> method that uses
307   <verbatim|\<less\>\<less\>name\<gtr\>\<gtr\>=> type tags. In the line (or
308   paragraph) following the chunk name, you insert a listing with:
309   Insert-\<gtr\>Program Listing.
311   Inside the white listing box you can type (or paste using
312   <kbd|shift+ctrl+V>) your listing. There is no need to use <kbd|ctrl+enter>
313   at the end of lines as with some older <LyX> literate techniques --- just
314   press enter as normal.
316   <subsection|Customising the listing appearance>
318   The code is formatted using the <name|lstlistings> package. The chunk style
319   doesn't just define the chunk name, but can also define any other chunk
320   options supported by the lstlistings package <verbatim|\\lstset> command.
321   In fact, what you type in the chunk style is raw latex. If you want to set
322   the chunk language without having to right-click the listing, just add
323   <verbatim|,lanuage=C> after the chunk name. (Currently the language will
324   affect all subsequent listings, so you may need to specify
325   <verbatim|,language=> quite a lot).
327   <todo|so fix the bug>
329   Of course you can do this by editing the listings box advanced properties
330   by right-clicking on the listings box, but that takes longer, and you can't
331   see at-a-glance what the advanced settings are while editing the document;
332   also advanced settings apply only to that box --- the chunk settings apply
333   through the rest of the document<\footnote>
334     It ought to apply only to subsequent chunks of the same name. I'll fix
335     that later
336   </footnote>.
338   <todo|So make sure they only apply to chunks of that name>
340   <subsection|Global customisations>
342   As lstlistings is used to set the code chunks, it's <verbatim|\\lstset>
343   command can be used in the pre-amble to set some document wide settings.
345   If your source has many words with long sequences of capital letters, then
346   <verbatim|columns=fullflexible> may be a good idea, or the capital letters
347   will get crowded. (I think lstlistings ought to use a slightly smaller font
348   for captial letters so that they still fit).
350   The font family <verbatim|\\ttfamily> looks more normal for code, but has
351   no bold (an alternate typewriter font is used).\ 
353   With <verbatim|\\ttfamily>, I must also specify
354   <verbatim|columns=fullflexible> or the wrong letter spacing is used.
356   In my <LaTeX> pre-amble I usually specialise my code format with:
358   <\nf-chunk|document-preamble>
359     <item>\\lstset{
361     <item>numbers=left, stepnumber=1, numbersep=5pt,
363     <item>breaklines=false,
365     <item>basicstyle=\\footnotesize\\ttfamily,
367     <item>numberstyle=\\tiny,
369     <item>language=C,
371     <item>columns=fullflexible,
373     <item>numberfirstline=true
375     <item>}
376   </nf-chunk|tex|>
378   \;
380   <section|Configuring the build script>
382   You can invoke code extraction and building from the <LyX> menu option
383   Document-\<gtr\>Build Program.
385   First, make sure you don't have a conversion defined for Lyx-\<gtr\>Program
387   From the menu Tools-\<gtr\>Preferences, add a conversion from
388   Latex(Plain)-\<gtr\>Program as:
390   <\verbatim>
391     set -x ; fangle -Rlyx-build $$i \|\ 
393     \ \ env LYX_b=$$b LYX_i=$$i LYX_o=$$o LYX_p=$$p LYX_r=$$r bash
394   </verbatim>
396   (But don't cut-n-paste it from this document or you may be be pasting a
397   multi-line string which will break your lyx preferences file).\ 
399   I hope that one day, <LyX> will set these into the environment when calling
400   the build script.
402   You may also want to consider adding options to this conversion...
404   <verbatim|parselog=/usr/share/lyx/scripts/listerrors>
406   ...but if you do you will lose your stderr<\footnote>
407     There is some bash plumbing to get a copy of stderr but this footnote is
408     too small
409   </footnote>.
411   Now, a shell script chunk called <filename|lyx-build> will be extracted and
412   run whenever you choose the Document-\<gtr\>Build Program menu item.
414   This document was originally managed using <LyX> and lyx-build script for
415   this document is shown here for historical reference.\ 
417   <\verbatim>
418     lyx -e latex fangle.lyx && \\
420     \ \ fangle fangle.lyx \<gtr\> ./autoboot
421   </verbatim>
423   This looks simple enough, but as mentioned, fangle has to be had from
424   somewhere before it can be extracted.
426   <subsection|...>
428   When the lyx-build chunk is executed, the current directory will be a
429   temporary directory, and <verbatim|LYX_SOURCE> will refer to the tex file
430   in this temporary directory. This is unfortunate as our makefile wants to
431   run from the project directory where the Lyx file is kept.
433   We can extract the project directory from <verbatim|$$r>, and derive the
434   probable Lyx filename from the noweb file that Lyx generated.
436   <\nf-chunk|lyx-build-helper>
437     <item>PROJECT_DIR="$LYX_r"
439     <item>LYX_SRC="$PROJECT_DIR/${LYX_i%.tex}.lyx"
441     <item>TEX_DIR="$LYX_p"
443     <item>TEX_SRC="$TEX_DIR/$LYX_i"
444   </nf-chunk|sh|>
446   And then we can define a lyx-build fragment similar to the autoboot
447   fragment
449   <\nf-chunk|lyx-build>
450     <item>#! /bin/sh
452     <item><nf-ref|lyx-build-helper|>
454     <item>cd $PROJECT_DIR \|\| exit 1
456     <item>
458     <item>#/usr/bin/fangle -filter ./notanglefix-filter \\
460     <item># \ -R./Makefile.inc "../../noweb-lyx/noweb-lyx3.lyx" \\
462     <item># \ \| sed '/NOWEB_SOURCE=/s/=.*/=samba4-dfs.lyx/' \\
464     <item># \ \<gtr\> ./Makefile.inc
466     <item>#
468     <item>#make -f ./Makefile.inc fangle_sources
469   </nf-chunk|sh|>
471   \;
473   <chapter|Using Fangle with <TeXmacs>>
475   <todo|Write this chapter>
477   <chapter|Fangle with Makefiles><label|makefile.inc>
479   Here we describe a <filename|Makefile.inc> that you can include in your own
480   Makefiles, or glue as a recursive make to other projects.
482   <filename|Makefile.inc> will cope with extracting all the other source
483   files from this or any specified literate document and keeping them up to
484   date.\ 
486   It may also be included by a <verbatim|Makefile> or <verbatim|Makefile.am>
487   defined in a literate document to automatically deal with the extraction of
488   source files and documents during normal builds.
490   Thus, if <verbatim|Makefile.inc> is included into a main project makefile
491   it add rules for the source files, capable of extracting the source files
492   from the literate document.
494   <section|A word about makefiles formats>
496   Whitespace formatting is very important in a Makefile. The first character
497   of each action line must be a TAB.\ 
499   <\verbatim>
500     target: pre-requisite
502     <nf-tab>action
504     <nf-tab>action
505   </verbatim>
507   This requires that the literate programming environment have the ability to
508   represent a TAB character in a way that fangle will generate an actual TAB
509   character.
511   We also adopt a convention that code chunks whose names beginning with
512   <verbatim|./> should always be automatically extracted from the document.
513   Code chunks whose names do not begin with <verbatim|./> are for internal
514   reference. Such chunks may be extracted directly, but will not be
515   automatically extracted by this Makefile.
517   <section|Extracting Sources>
519   Our makefile has two parts; variables must be defined before the targets
520   that use them.
522   As we progress through this chapter, explaining concepts, we will be adding
523   lines to <nf-ref|Makefile.inc-vars|> and <nf-ref|Makefile.inc-targets|>
524   which are included in <nf-ref|./Makefile.inc|> below.
526   <\nf-chunk|./Makefile.inc>
527     <item><nf-ref|Makefile.inc-vars|>
529     <item><nf-ref|Makefile.inc-default-targets|>
531     <item><nf-ref|Makefile.inc-targets|>
532   </nf-chunk|make|>
534   We first define a placeholder for the tool <verbatim|fangle> in case it
535   cannot be found in the path.
537   <\nf-chunk|Makefile.inc-vars>
538     <item>FANGLE=fangle
540     <item>AWK=awk
542     <item>RUN_FANGLE=$(AWK) -f $(FANGLE)
543   </nf-chunk|make|>
545   We also define a placeholder for <verbatim|LITERATE_SOURCE> to hold the
546   name of this document. This will normally be passed on the command line or
547   set by the including makefile.
549   <\nf-chunk|Makefile.inc-vars>
550     <item>#LITERATE_SOURCE=
551   </nf-chunk||>
553   Fangle cannot process <LyX> or <TeXmacs> documents directly, so the first
554   stage is to convert these to more suitable text based formats<\footnote>
555     <LyX> and <TeXmacs> formats are text-based, but not suitable for fangle
556   </footnote>.
558   <subsection|Converting from <LyX> to <LaTeX>><label|Converting-from-Lyx>
560   The first stage will always be to convert the <LyX> file to a <LaTeX> file.
561   Fangle must run on a <TeX> file because the <LyX> command
562   <verbatim|server-goto-file-line><\footnote>
563     The Lyx command <verbatim|server-goto-file-line> is used to position the
564     Lyx cursor at the compiler errors.
565   </footnote> requries that the line number provided be a line of the <TeX>
566   file and always maps this the line in the <LyX> docment. We use
567   <verbatim|server-goto-file-line> when moving the cursor to error lines
568   during compile failures.
570   The command <verbatim|lyx -e literate fangle.lyx> will produce
571   <verbatim|fangle.tex>, a <TeX> file; so we define a make target to be the
572   same as the <LyX> file but with the <verbatim|.tex> extension.
574   The <verbatim|EXTRA_DIST> is for automake support so that the <TeX> files
575   will automaticaly be distributed with the source, to help those who don't
576   have <LyX> installed.
578   <\nf-chunk|Makefile.inc-vars>
579     <item>LYX_SOURCE=$(LITERATE_SOURCE) # but only the .lyx files
581     <item>TEX_SOURCE=$(LYX_SOURCE:.lyx=.tex)
583     <item>EXTRA_DIST+=$(TEX_SOURCE)
584   </nf-chunk||>
586   We then specify that the <TeX> source is to be generated from the <LyX>
587   source.
589   <\nf-chunk|Makefile.inc-targets>
590     <item>.SUFFIXES: .tex .lyx
592     <item>.lyx.tex:
594     <item><nf-tab>lyx -e latex $\<less\>
596     <item>clean_tex:
598     <item><nf-tab>rm -f -- $(TEX_SOURCE)
600     <item>clean: clean_tex
601   </nf-chunk|make|>
603   <subsection|Converting from <TeXmacs>><label|Converting-from-Lyx>
605   Fangle cannot process <TeXmacs> files directly<\footnote>
606     but this is planned when <TeXmacs> uses xml as it's native format
607   </footnote>, but must first convert them to text files.
609   The command <verbatim|texmacs -c fangle.tm fangle.txt -q> will produce
610   <verbatim|fangle.txt>, a text file; so we define a make target to be the
611   same as the <TeXmacs> file but with the <verbatim|.txt> extension.
613   The <verbatim|EXTRA_DIST> is for automake support so that the <TeX> files
614   will automaticaly be distributed with the source, to help those who don't
615   have <LyX> installed.
617   <\nf-chunk|Makefile.inc-vars>
618     <item>TEXMACS_SOURCE=$(LITERATE_SOURCE) # but only the .tm files
620     <item>TXT_SOURCE=$(LITERATE_SOURCE:.tm=.txt)
622     <item>EXTRA_DIST+=$(TXT_SOURCE)
623   </nf-chunk||>
625   <todo|Add loop around each $\<less\> so multiple targets can be specified>
627   <\nf-chunk|Makefile.inc-targets>
628     <item>.SUFFIXES: .txt .tm
630     <item>.tm.txt:
632     <item><nf-tab>texmacs -s -c $\<less\> $@ -q
634     <item>.PHONEY: clean_txt
636     <item>clean_txt:
638     <item><nf-tab>rm -f -- $(TXT_SOURCE)
640     <item>clean: clean_txt
641   </nf-chunk||>
643   <section|Extracting Program Source>
645   The program source is extracted using fangle, which is designed to operate
646   on text or a <LaTeX> documents<\footnote>
647     <LaTeX> documents are just slightly special text documents
648   </footnote>.
650   <\nf-chunk|Makefile.inc-vars>
651     <item>FANGLE_SOURCE=$(TXT_SOURCE)
652   </nf-chunk||>
654   The literate document can result in any number of source files, but not all
655   of these will be changed each time the document is updated. We certainly
656   don't want to update the timestamps of these files and cause the whole
657   source tree to be recompiled just because the literate explanation was
658   revised. We use <verbatim|CPIF> from the <em|Noweb> tools to avoid updating
659   the file if the content has not changed, but should probably write our own.
661   However, if a source file is not updated, then the fangle file will always
662   have a newer time-stamp and the makefile would always re-attempt to extact
663   a newer source file which would be a waste of time.
665   Because of this, we use a stamp file which is always updated each time the
666   sources are fully extracted from the <LaTeX> document. If the stamp file is
667   newer than the document, then we can avoid an attempt to re-extract any of
668   the sources. Because this stamp file is only updated when extraction is
669   complete, it is safe for the user to interrupt the build-process
670   mid-extraction.
672   We use <verbatim|echo> rather than <verbatim|touch> to update the stamp
673   file beause the <verbatim|touch> command does not work very well over an
674   <verbatim|sshfs> mount \ that I was using.
676   <\nf-chunk|Makefile.inc-vars>
677     <item>FANGLE_SOURCE_STAMP=$(FANGLE_SOURCE).stamp
678   </nf-chunk||>
680   <\nf-chunk|Makefile.inc-targets>
681     <item>$(FANGLE_SOURCE_STAMP): $(FANGLE_SOURCE) \\
683     <item><nf-tab> \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ $(FANGLE_SOURCES) ; \\
685     <item><nf-tab>echo -n \<gtr\> $(FANGLE_SOURCE_STAMP)
687     <item>clean_stamp:
689     <item><nf-tab>rm -f $(FANGLE_SOURCE_STAMP)
691     <item>clean: clean_stamp
692   </nf-chunk||>
694   <section|Extracting Source Files>
696   We compute <verbatim|FANGLE_SOURCES> to hold the names of all the source
697   files defined in the document. We compute this only once, by means of
698   <verbatim|:=> in assignent. The sed deletes the any
699   <verbatim|\<less\>\<less\>> and <verbatim|\<gtr\>\<gtr\>> which may
700   surround the roots names (for compatibility with Noweb's noroots command).
702   As we use chunk names beginning with <filename|./> to denote top level
703   fragments that should be extracted, we filter out all fragments that do not
704   begin with <filename|./>
706   <\note>
707     <verbatim|FANGLE_PREFIX> is set to <verbatim|./> by default, but whatever
708     it may be overridden to, the prefix is replaced by a literal
709     <verbatim|./> before extraction so that files will be extracted in the
710     current directory whatever the prefix. This helps namespace or
711     sub-project prefixes like <verbatim|documents:> for chunks like
712     <verbatim|documents:docbook/intro.xml>
713   </note>
715   <todo|This doesn't work though, because it loses the full name and doesn't
716   know what to extact!>
718   <\nf-chunk|Makefile.inc-vars>
719     <item>FANGLE_PREFIX:=\\.\\/
721     <item>FANGLE_SOURCES:=$(shell \\
723     <item> \ $(RUN_FANGLE) -r $(FANGLE_SOURCE) \|\\
725     <item> \ sed -e 's/^[\<less\>][\<less\>]//;s/[\<gtr\>][\<gtr\>]$$//;/^$(FANGLE_PREFIX)/!d'
726     \\
728     <item> \ \ \ \ \ -e 's/^$(FANGLE_PREFIX)/\\.\\//' )
729   </nf-chunk||>
731   The target below, <verbatim|echo_fangle_sources> is a helpful debugging
732   target and shows the names of the files that would be extracted.
734   <\nf-chunk|Makefile.inc-targets>
735     <item>.PHONY: echo_fangle_sources
737     <item>echo_fangle_sources: ; @echo $(FANGLE_SOURCES)
738   </nf-chunk||>
740   We define a convenient target called <verbatim|fangle_sources> so that
741   <verbatim|make -f fangle_sources> will re-extract the source if the
742   literate document has been updated.\ 
744   <\nf-chunk|Makefile.inc-targets>
745     <item>.PHONY: fangle_sources
747     <item>fangle_sources: $(FANGLE_SOURCE_STAMP)
748   </nf-chunk||>
750   And also a convenient target to remove extracted sources.
752   <\nf-chunk|Makefile.inc-targets>
753     <item>.PHONY: clean_fangle_sources
755     <item>clean_fangle_sources: ; \\
757     <item> \ \ \ \ \ \ \ rm -f -- $(FANGLE_SOURCE_STAMP) $(FANGLE_SOURCES)
758   </nf-chunk||>
760   We now look at the extraction of the source files.
762   This makefile macro <verbatim|if_extension> takes 4 arguments: the filename
763   <verbatim|$(1)>, some extensions to match <verbatim|$(2)> and a shell
764   command to return if the filename does match the exensions <verbatim|$(3)>,
765   and a shell command to return if it does not match the extensions
766   <verbatim|$(4)>.
768   <\nf-chunk|Makefile.inc-vars>
769     <item>if_extension=$(if $(findstring $(suffix $(1)),$(2)),$(3),$(4))
770   </nf-chunk||>
772   For some source files like C files, we want to output the line number and
773   filename of the original <LaTeX> document from which the source
774   came<\footnote>
775     I plan to replace this option with a separate mapping file so as not to
776     pollute the generated source, and also to allow a code pretty-printing
777     reformatter like <verbatim|indent> be able to re-format the file and
778     adjust for changes through comparing the character streams.
779   </footnote>.
781   To make this easier we define the file extensions for which we want to do
782   this.
784   <\nf-chunk|Makefile.inc-vars>
785     <item>C_EXTENSIONS=.c .h
786   </nf-chunk||>
788   We can then use the <verbatim|if_extensions> macro to define a macro which
789   expands out to the <verbatim|-L> option if fangle is being invoked in a C
790   source file, so that C compile errors will refer to the line number in the
791   <TeX> document.\ 
793   <\nf-chunk|Makefile.inc-vars>
794     <item>TABS=8
796     <item>nf_line=-L -T$(TABS)
798     <item>fangle=$(RUN_FANGLE) $(call if_extension,$(2),$(C_EXTENSIONS),$(nf_line))
799     -R"$(2)" $(1)
800   </nf-chunk||>
802   We can use a similar trick to define an indent macro which takes just the
803   filename as an argument and can return a pipeline stage calling the indent
804   command. Indent can be turned off with <verbatim|make fangle_sources
805   indent=>
807   <\nf-chunk|Makefile.inc-vars>
808     <item>indent_options=-npro -kr -i8 -ts8 -sob -l80 -ss -ncs
810     <item>indent=$(call if_extension,$(1),$(C_EXTENSIONS), \| indent
811     $(indent_options))
812   </nf-chunk||>
814   We now define the pattern for extracting a file. The files are written
815   using noweb's <verbatim|cpif> so that the file timestamp will not be
816   touched if the contents haven't changed. This avoids the need to rebuild
817   the entire project because of a typographical change in the documentation,
818   or if none or a few C source files have changed.
820   <\nf-chunk|Makefile.inc-vars>
821     <item>fangle_extract=@mkdir -p $(dir $(1)) && \\
823     <item> \ $(call fangle,$(2),$(1)) \<gtr\> "$(1).tmp" && \\
825     <item> \ cat "$(1).tmp" $(indent) \| cpif "$(1)" \\
827     <item> \ && rm -f -- "$(1).tmp" \|\| \\
829     <item> \ (echo error fangling $(1) from $(2) ; exit 1)
830   </nf-chunk||>
832   We define a target which will extract or update all sources. To do this we
833   first defined a makefile template that can do this for any source file in
834   the <LaTeX> document.
836   <\nf-chunk|Makefile.inc-vars>
837     <item>define FANGLE_template
839     <item> \ $(1): $(2)
841     <item><nf-tab>$$(call fangle_extract,$(1),$(2))
843     <item> \ FANGLE_TARGETS+=$(1)
845     <item>endef
846   </nf-chunk||>
848   We then enumerate the discovered <verbatim|FANGLE_SOURCES> to generate a
849   makefile rule for each one using the makefile template we defined above.
851   <\nf-chunk|Makefile.inc-targets>
852     <item>$(foreach source,$(FANGLE_SOURCES),\\
854     <item> \ $(eval $(call FANGLE_template,$(source),$(FANGLE_SOURCE))) \\
856     <item>)
857   </nf-chunk||>
859   These will all be built with <verbatim|FANGLE_SOURCE_STAMP>.
861   We also remove the generated sources on a make distclean.
863   <\nf-chunk|Makefile.inc-targets>
864     <item>_distclean: clean_fangle_sources
865   </nf-chunk||>
867   <section|Extracting Documentation>
869   We then identify the intermediate stages of the documentation and their
870   build and clean targets.
872   <\nf-chunk|Makefile.inc-default-targets>
873     <item>.PHONEY : clean_pdf
874   </nf-chunk||>
876   <subsection|Formatting <TeX>>
878   <subsubsection|Running pdflatex>
880   We produce a pdf file from the tex file.
882   <\nf-chunk|Makefile.inc-vars>
883     <item>FANGLE_PDF+=$(TEX_SOURCE:.tex=.pdf)
884   </nf-chunk||>
886   We run pdflatex twice to be sure that the contents and aux files are up to
887   date. We certainly are <em|required> to run pdflatex at least twice if
888   these files do not exist.
890   <\nf-chunk|Makefile.inc-targets>
891     <item>.SUFFIXES: .tex .pdf
893     <item>.tex.pdf:
895     <item><nf-tab>pdflatex $\<less\> && pdflatex $\<less\>
897     <item>
899     <item>clean_pdf_tex:
901     <item><nf-tab>rm -f -- $(FANGLE_PDF) $(TEX_SOURCE:.tex=.toc) \\
903     <item><nf-tab> \ $(TEX_SOURCE:.tex=.log) $(TEX_SOURCE:.tex=.aux)
905     <item>clean_pdf: clean_pdf_tex
906   </nf-chunk||>
908   <subsection|Formatting <TeXmacs>>
910   <TeXmacs> can produce a PDF file directly.
912   <\nf-chunk|Makefile.inc-vars>
913     <item>FANGLE_PDF+=$(LITERATE_SOURCE:.tm=.pdf)
914   </nf-chunk||>
916   <\todo>
917     Outputting the PDF may not be enough to update the links and page
918     references. I think
920     we need to update twice, generate a pdf, update twice mode and generate a
921     new PDF.
923     Basically the PDF export of <TeXmacs> is pretty rotten and doesn't work
924     properly from the CLI
925   </todo>
927   <\nf-chunk|Makefile.inc-targets>
928     <item>.SUFFIXES: .tm .pdf
930     <item>.tm.pdf:
932     <item><nf-tab>texmacs -s -c $\<less\> $@ -q
934     <item>
936     <item>clean_pdf_texmacs:
938     <item><nf-tab>rm -f -- $(FANGLE_PDF)
940     <item>clean_pdf: clean_pdf_texmacs
941   </nf-chunk||>
943   <subsection|Building the Documentation as a Whole>
945   Currently we only build pdf as a final format, but <verbatim|FANGLE_DOCS>
946   may later hold other output formats.
948   <\nf-chunk|Makefile.inc-vars>
949     <item>FANGLE_DOCS=$(FANGLE_PDF)
950   </nf-chunk||>
952   We also define <verbatim|fangle_docs> as a convenient phony target.
954   <\nf-chunk|Makefile.inc-targets>
955     <item>.PHONY: fangle_docs
957     <item>fangle_docs: $(FANGLE_DOCS)
959     <item>docs: fangle_docs
960   </nf-chunk||>
962   And define a convenient <verbatim|clean_fangle_docs> which we add to the
963   regular clean target
965   <\nf-chunk|Makefile.inc-targets>
966     <item>.PHONEY: clean_fangle_docs
968     <item>clean_fangle_docs: clean_tex clean_pdf
970     <item>clean: clean_fangle_docs
972     <item>
974     <item>distclean_fangle_docs: clean_tex clean_fangle_docs
976     <item>distclean: clean distclean_fangle_docs
977   </nf-chunk||>
979   <section|Other helpers>
981   If <filename|Makefile.inc> is included into <filename|Makefile>, then
982   extracted files can be updated with this command:
984   <verbatim|make fangle_sources>
986   otherwise, with:
988   <verbatim|make -f Makefile.inc fangle_sources>
990   <section|Boot-strapping the extraction>
992   As well as having the makefile extract or update the source files as part
993   of it's operation, it also seems convenient to have the makefile
994   re-extracted itself from <em|this> document.
996   It would also be convenient to have the code that extracts the makefile
997   from this document to also be part of this document, however we have to
998   start somewhere and this unfortunately requires us to type at least a few
999   words by hand to start things off.
1001   Therefore we will have a minimal root fragment, which, when extracted, can
1002   cope with extracting the rest of the source. This shell script fragment can
1003   do that. It's name is <verbatim|*> <emdash> out of regard for <name|Noweb>,
1004   but when extracted might better be called <verbatim|autoupdate>.
1006   <todo|De-lyxify>
1008   <\nf-chunk|*>
1009     <item>#! /bin/sh
1011     <item>
1013     <item>MAKE_SRC="${1:-${NW_LYX:-../../noweb-lyx/noweb-lyx3.lyx}}"
1015     <item>MAKE_SRC=`dirname "$MAKE_SRC"`/`basename "$MAKE_SRC" .lyx`
1017     <item>NOWEB_SRC="${2:-${NOWEB_SRC:-$MAKE_SRC.lyx}}"
1019     <item>lyx -e latex $MAKE_SRC
1021     <item>
1023     <item>fangle -R./Makefile.inc ${MAKE_SRC}.tex \\
1025     <item> \ \| sed "/FANGLE_SOURCE=/s/^/#/;T;aNOWEB_SOURCE=$FANGLE_SRC" \\
1027     <item> \ \| cpif ./Makefile.inc
1029     <item>
1031     <item>make -f ./Makefile.inc fangle_sources
1032   </nf-chunk|sh|>
1034   The general Makefile can be invoked with <filename|./autoboot> and can also
1035   be included into any automake file to automatically re-generate the source
1036   files.
1038   The <em|autoboot> can be extracted with this command:
1040   <\verbatim>
1041     lyx -e latex fangle.lyx && \\
1043     \ \ fangle fangle.lyx \<gtr\> ./autoboot
1044   </verbatim>
1046   This looks simple enough, but as mentioned, fangle has to be had from
1047   somewhere before it can be extracted.
1049   On a unix system this will extract <filename|fangle.module> and the
1050   <filename|fangle> awk script, and run some basic tests.\ 
1052   <todo|cross-ref to test chapter when it is a chapter all on its own>
1054   <section|Incorporating Makefile.inc into existing projects>
1056   If you are writing a literate module of an existing non-literate program
1057   you may find it easier to use a slight recursive make instead of directly
1058   including <verbatim|Makefile.inc> in the projects makefile.\ 
1060   This way there is less chance of definitions in <verbatim|Makefile.inc>
1061   interfering with definitions in the main makefile, or with definitions in
1062   other <verbatim|Makefile.inc> from other literate modules of the same
1063   project.
1065   To do this we add some <em|glue> to the project makefile that invokes
1066   Makefile.inc in the right way. The glue works by adding a <verbatim|.PHONY>
1067   target to call the recursive make, and adding this target as an additional
1068   pre-requisite to the existing targets.
1070   <paragraph|Example>Sub-module of existing system
1072   In this example, we are building <verbatim|module.so> as a literate module
1073   of a larger project.
1075   We will show the sort glue that can be inserted into the projects Makefile
1076   <emdash> or more likely <emdash> a regular Makefile included in or invoked
1077   by the projects Makefile.
1079   <\nf-chunk|makefile-glue>
1080     <item>module_srcdir=modules/module
1082     <item>MODULE_SOURCE=module.tm
1084     <item>MODULE_STAMP=$(MODULE_SOURCE).stamp
1085   </nf-chunk||>
1087   The existing build system may already have a build target for
1088   <filename|module.o>, but we just add another pre-requisite to that. In this
1089   case we use <filename|module.tm.stamp> as a pre-requisite, the stamp file's
1090   modified time indicating when all sources were extracted<\footnote>
1091     If the projects build system does not know how to build the module from
1092     the extracted sources, then just add build actions here as normal.
1093   </footnote>.
1095   <\nf-chunk|makefile-glue>
1096     <item>$(module_srcdir)/module.o: $(module_srcdir)/$(MODULE_STAMP)
1097   </nf-chunk|make|>
1099   The target for this new pre-requisite will be generated by a recursive make
1100   using <filename|Makefile.inc> which will make sure that the source is up to
1101   date, before it is built by the main projects makefile.
1103   <\nf-chunk|makefile-glue>
1104     <item>$(module_srcdir)/$(MODULE_STAMP): $(module_srcdir)/$(MODULE_SOURCE)
1106     <item><nf-tab>$(MAKE) -C $(module_srcdir) -f Makefile.inc fangle_sources
1107     LITERATE_SOURCE=$(MODULE_SOURCE)
1108   </nf-chunk||>
1110   We can do similar glue for the docs, clean and distclean targets. In this
1111   example the main prject was using a double colon for these targets, so we
1112   must use the same in our glue.
1114   <\nf-chunk|makefile-glue>
1115     <item>docs:: docs_module
1117     <item>.PHONY: docs_module
1119     <item>docs_module:
1121     <item><nf-tab>$(MAKE) -C $(module_srcdir) -f Makefile.inc docs
1122     LITERATE_SOURCE=$(MODULE_SOURCE)
1124     <item>
1126     <item>clean:: clean_module
1128     <item>.PHONEY: clean_module
1130     <item>clean_module:
1132     <item><nf-tab>$(MAKE) -C $(module_srcdir) -f Makefile.inc clean
1133     LITERATE_SOURCE=$(MODULE_SOURCE)
1135     <item>
1137     <item>distclean:: distclean_module
1139     <item>.PHONY: distclean_module
1141     <item>distclean_module:
1143     <item><nf-tab>$(MAKE) -C $(module_srcdir) -f Makefile.inc distclean
1144     LITERATE_SOURCE=$(MODULE_SOURCE)
1145   </nf-chunk||>
1147   We could do similarly for install targets to install the generated docs.
1149   <part|Source Code>
1151   <chapter|Fangle Makefile>
1153   We use the copyright notice from chapter <reference|License>, and the
1154   Makefile.inc from chapter <reference|makefile.inc>
1156   <\nf-chunk|./Makefile>
1157     <item># <nf-ref|gpl3-copyright|>
1159     <item>
1161     <item><nf-ref|make-fix-make-shell|>
1163     <item>
1165     <item>LITERATE_SOURCE=fangle.tm
1167     <item>BINDIR=/usr/local/bin
1169     <item>TEXMACS_DIR=/usr/share/texmacs/TeXmacs
1171     <item>LYX_DIR=/usr/share/lyx
1173     <item>
1175     <item>all: fangle_sources
1177     <item>include Makefile.inc
1179     <item>
1181     <item>fangle: test
1183     <item>./fangle: test
1185     <item>
1187     <item>.PHONEY: test
1189     <item>test: fangle.txt
1191     <item><nf-tab>$(RUN_FANGLE) -R"test:*" fangle.txt \<gtr\> test.sh
1193     <item><nf-tab>bash test.sh ; echo pass $$?
1195     <item>
1197     <item>install-local: BINDIR=$$HOME/.local/bin
1199     <item>install-local: TEXMACS_DIR=$$HOME/.TeXmacs
1201     <item>install-local: LYX_DIR=$$HOME/.lyx
1203     <item>install-local: install
1205     <item>.PHONEY: install-local
1207     <item>
1209     <item>install-system: install
1211     <item>.PHONEY: install-local
1213     <item>
1215     <item>install:
1217     <item><nf-tab>test -n "$(BINDIR)" -a -n "$(TEXMACS_DIR)"
1219     <item><nf-tab>mkdir -p "$(BINDIR)"
1221     <item><nf-tab>install fangle "$(BINDIR)"
1223     <item><nf-tab>mkdir -p "$(TEXMACS_DIR)/plugins/fangle"
1225     <item><nf-tab>mkdir -p "$(TEXMACS_DIR)/plugins/fangle/packages"
1227     <item><nf-tab>install fangle.ts "$(TEXMACS_DIR)/plugins/fangle/packages"
1229     <item><nf-tab>mkdir -p "$(TEXMACS_DIR)/plugins/fangle/progs"
1231     <item><nf-tab>install init-fangle.scm
1232     "$(TEXMACS_DIR)/plugins/fangle/progs"
1234     <item><nf-tab>mkdir -p "$(LYX_DIR)/modules"
1236     <item><nf-tab>install fangle.module "$(LYX_DIR)/modules"
1238     <item>.PHONEY: install
1239   </nf-chunk|make|>
1241   <chapter|Fangle awk source code>
1243   We use the copyright notice from chapter <reference|License>.
1245   <\nf-chunk|./fangle>
1246     <item>#! /usr/bin/awk -f
1248     <item># <nf-ref|gpl3-copyright|>
1249   </nf-chunk|awk|>
1251   We also use code from <person|Arnold Robbins> public domain getopt (1993
1252   revision) defined in <reference|getopt>, and naturally want to attribute
1253   this appropriately.
1255   <\nf-chunk|./fangle>
1256     <item># NOTE: Arnold Robbins public domain getopt for awk is also used:
1258     <item><nf-ref|getopt.awk-header|>
1260     <item><nf-ref|getopt.awk-getopt()|>
1262     <item>
1263   </nf-chunk||>
1265   And include the following chunks (which are explained further on) to make
1266   up the program:
1268   <\nf-chunk|./fangle>
1269     <item><nf-ref|helper-functions|>
1271     <item><nf-ref|mode-tracker|>
1273     <item><nf-ref|parse_chunk_args|>
1275     <item><nf-ref|chunk-storage-functions|>
1277     <item><nf-ref|output_chunk_names()|>
1279     <item><nf-ref|output_chunks()|>
1281     <item><nf-ref|write_chunk()|>
1283     <item><nf-ref|expand_chunk_args()|>
1285     <item>
1287     <item><nf-ref|begin|>
1289     <item><nf-ref|recognize-chunk|>
1291     <item><nf-ref|end|>
1292   </nf-chunk||>
1294   <section|AWK tricks>
1296   The portable way to erase an array in awk is to split the empty string, so
1297   we define a fangle macro that can split an array, like this:
1299   <\nf-chunk|awk-delete-array>
1300     <item>split("", <nf-arg|ARRAY>);
1301   </nf-chunk|awk|<tuple|ARRAY>>
1303   For debugging it is sometimes convenient to be able to dump the contents of
1304   an array to <verbatim|stderr>, and so this macro is also useful.
1306   <\nf-chunk|dump-array>
1307     <item>print "\\nDump: <nf-arg|ARRAY>\\n--------\\n" \<gtr\>
1308     "/dev/stderr";
1310     <item>for (_x in <nf-arg|ARRAY>) {
1312     <item> \ print _x "=" <nf-arg|ARRAY>[_x] "\\n" \<gtr\> "/dev/stderr";
1314     <item>}
1316     <item>print "========\\n" \<gtr\> "/dev/stderr";
1317   </nf-chunk|awk|<tuple|ARRAY>>
1319   <section|Catching errors>
1321   Fatal errors are issued with the error function:
1323   <\nf-chunk|error()>
1324     <item>function error(message)
1326     <item>{
1328     <item> \ print "ERROR: " FILENAME ":" FNR " " message \<gtr\>
1329     "/dev/stderr";
1331     <item> \ exit 1;
1333     <item>}
1334   </nf-chunk|awk|>
1336   and likewise for non-fatal warnings:
1338   <\nf-chunk|error()>
1339     <item>function warning(message)
1341     <item>{
1343     <item> \ print "WARNING: " FILENAME ":" FNR " " message \<gtr\>
1344     "/dev/stderr";
1346     <item> \ warnings++;
1348     <item>}
1349   </nf-chunk|awk|>
1351   and debug output too:
1353   <\nf-chunk|error()>
1354     <item>function debug_log(message)
1356     <item>{
1358     <item> \ print "DEBUG: " FILENAME ":" FNR " " message \<gtr\>
1359     "/dev/stderr";
1361     <item>}
1362   </nf-chunk|awk|>
1364   <todo|append=helper-functions>
1366   <\nf-chunk|helper-functions>
1367     <item><nf-ref|error()|>
1368   </nf-chunk||>
1370   <chapter|<TeXmacs> args>
1372   <TeXmacs> functions with arguments<\footnote>
1373     or function declarations with parameters
1374   </footnote> appear like this:
1376   <math|<math-tt|blah(><wide*|<wide|<math-tt|I came, I saw, I
1377   conquered>|\<wide-overbrace\>><rsup|argument 1><wide|<math-tt|<key|^K>>,
1378   |\<wide-overbrace\>><rsup|sep.><wide|and then went home
1379   asd|\<wide-overbrace\>><rsup|argument 3><wide|<math-tt|<key|^K>><math-tt|)>|\<wide-overbrace\>><rsup|term.>|\<wide-underbrace\>><rsub|arguments>>
1381   Arguments commence after the opening parenthesis. The first argument runs
1382   up till the next <key|^K>.\ 
1384   If the following character is a <key|,> then another argument follows. If
1385   the next character after the <key|,> is a space character, then it is also
1386   eaten. The fangle stylesheet emits <key|^K><key|,><key|space> as
1387   separators, but the fangle untangler will forgive a missing space.
1389   If the following character is <key|)> then this is a terminator and there
1390   are no more arguments.
1392   <\nf-chunk|constants>
1393     <item>ARG_SEPARATOR=sprintf("%c", 11);
1394   </nf-chunk||>
1396   To process the <verbatim|text> in this fashion, we split the string on
1397   <key|^K>
1399   \;
1401   <\nf-chunk|get_chunk_args>
1402     <item>function get_texmacs_chunk_args(text, args, \ \ a, done) {
1404     <item> \ split(text, args, ARG_SEPARATOR);
1406     <item>
1408     <item> \ done=0
1410     <item> \ for (a=1; (a in args); a++) if (a\<gtr\>1) {
1412     <item> \ \ \ if (args[a] == "" \|\| substr(args[a], 1, 1) == ")") done=1;
1414     <item> \ \ \ if (done) {
1416     <item> \ \ \ \ \ delete args[a];
1418     <item> \ \ \ \ \ break;
1420     <item> \ \ \ }
1422     <item>
1424     <item> \ \ \ if (substr(args[a], 1, 2) == ", ") args[a]=substr(args[a],
1425     3);
1427     <item> \ \ \ else if (substr(args[a], 1, 1) == ",")
1428     args[a]=substr(args[a], 2); \ 
1430     <item> \ }
1432     <item>}
1433   </nf-chunk||>
1435   <chapter|<LaTeX> and lstlistings>
1437   <todo|Split LyX and TeXmacs parts>
1439   For <LyX> and <LaTeX>, the <verbatim|lstlistings> package is used to format
1440   the lines of code chunks. You may recal from chapter XXX that arguments to
1441   a chunk definition are pure <LaTeX> code. This means that fangle needs to
1442   be able to parse <LaTeX> a little.
1444   <LaTeX> arguments to <verbatim|lstlistings> macros are a comma seperated
1445   list of key-value pairs, and values containing commas are enclosed in
1446   <verbatim|{> braces <verbatim|}> (which is to be expected for <LaTeX>).
1448   A sample expressions is:
1450   <verbatim|name=thomas, params={a, b}, something, something-else>
1452   but we see that this is just a simpler form of this expression:
1454   <verbatim|name=freddie, foo={bar=baz, quux={quirk, a=fleeg}}, etc>
1456   We may consider that we need a function that can parse such <LaTeX>
1457   expressions and assign the values to an AWK associated array, perhaps using
1458   a recursive parser into a multi-dimensional hash<\footnote>
1459     as AWK doesn't have nested-hash support
1460   </footnote>, resulting in:
1462   <tabular|<tformat|<cwith|2|6|1|2|cell-lborder|0.5pt>|<cwith|2|6|1|2|cell-rborder|0.5pt>|<cwith|2|6|1|2|cell-bborder|0.5pt>|<cwith|2|6|1|2|cell-tborder|0.5pt>|<cwith|1|1|1|2|cell-lborder|0.5pt>|<cwith|1|1|1|2|cell-rborder|0.5pt>|<cwith|1|1|1|2|cell-bborder|0.5pt>|<cwith|1|1|1|2|cell-tborder|0.5pt>|<table|<row|<cell|key>|<cell|value>>|<row|<cell|a[name]>|<cell|freddie>>|<row|<cell|a[foo,
1463   bar]>|<cell|baz>>|<row|<cell|a[foo, quux,
1464   quirk]>|<cell|>>|<row|<cell|a[foo, quux,
1465   a]>|<cell|fleeg>>|<row|<cell|a[etc]>|<cell|>>>>>
1467   Yet, also, on reflection it seems that sometimes such nesting is not
1468   desirable, as the braces are also used to delimit values that contain
1469   commas --- we may consider that
1471   <verbatim|name={williamson, freddie}>
1473   should assign <verbatim|williamson, freddie> to <verbatim|name>.
1475   In fact we are not so interested in the detail so as to be bothered by
1476   this, which turns out to be a good thing for two reasons. Firstly <TeX> has
1477   a malleable parser with no strict syntax, and secondly whether or not
1478   <verbatim|williamson> and <verbatim|freddie> should count as two items will
1479   be context dependant anyway.
1481   We need to parse this latex for only one reason; which is that we are
1482   extending lstlistings to add some additional arguments which will be used
1483   to express chunk parameters and other chunk options.
1485   <section|Additional lstlstings parameters>
1487   Further on we define a <verbatim|\\Chunk> <LaTeX> macro whose arguments
1488   will consist of a the chunk name, optionally followed by a comma and then a
1489   comma separated list of arguments. In fact we will just need to prefix
1490   <verbatim|name=> to the arguments to in order to create valid lstlistings
1491   arguments.\ 
1493   There will be other arguments supported too;\ 
1495   <\description-long>
1496     <item*|params>As an extension to many literate-programming styles, fangle
1497     permits code chunks to take parameters and thus operate somewhat like C
1498     pre-processor macros, or like C++ templates. Chunk parameters are
1499     declared with a chunk argument called params, which holds a semi-colon
1500     separated list of parameters, like this:
1502     <verbatim|achunk,language=C,params=name;address>
1504     <item*|addto>a named chunk that this chunk is to be included into. This
1505     saves the effort of having to declare another listing of the named chunk
1506     merely to include this one.
1507   </description-long>
1509   Function get_chunk_args() will accept two paramters, text being the text to
1510   parse, and values being an array to receive the parsed values as described
1511   above. The optional parameter path is used during recursion to build up the
1512   multi-dimensional array path.
1514   <\nf-chunk|./fangle>
1515     <item><nf-ref|get_chunk_args()|>
1516   </nf-chunk||>
1518   <\nf-chunk|get_chunk_args()>
1519     <item>function get_tex_chunk_args(text, values,
1521     <item> \ # optional parameters
1523     <item> \ path, # hierarchical precursors
1525     <item> \ # local vars
1527     <item> \ a, name)
1528   </nf-chunk||>
1530   The strategy is to parse the name, and then look for a value. If the value
1531   begins with a brace <verbatim|{>, then we recurse and consume as much of
1532   the text as necessary, returning the remaining text when we encounter a
1533   leading close-brace <verbatim|}>. This being the strategy --- and executed
1534   in a loop --- we realise that we must first look for the closing brace
1535   (perhaps preceded by white space) in order to terminate the recursion, and
1536   returning remaining text.
1538   <\nf-chunk|get_chunk_args()>
1539     <item>{
1541     <item> \ split("", values);
1543     <item> \ while(length(text)) {
1545     <item> \ \ \ if (match(text, "^ *}(.*)", a)) {
1547     <item> \ \ \ \ \ return a[1];
1549     <item> \ \ \ }
1551     <item> \ \ \ <nf-ref|parse-chunk-args|>
1553     <item> \ }
1555     <item> \ return text;
1557     <item>}
1558   </nf-chunk||>
1560   We can see that the text could be inspected with this regex:
1562   <\nf-chunk|parse-chunk-args>
1563     <item>if (! match(text, " *([^,=]*[^,= ]) *(([,=]) *(([^,}]*) *,*
1564     *(.*))\|)$", a)) {
1566     <item> \ return text;
1568     <item>}
1569   </nf-chunk||>
1571   and that <verbatim|a> will have the following values:
1573   <tabular|<tformat|<cwith|2|7|1|2|cell-lborder|0.5pt>|<cwith|2|7|1|2|cell-rborder|0.5pt>|<cwith|2|7|1|2|cell-bborder|0.5pt>|<cwith|2|7|1|2|cell-tborder|0.5pt>|<cwith|1|1|1|2|cell-lborder|0.5pt>|<cwith|1|1|1|2|cell-rborder|0.5pt>|<cwith|1|1|1|2|cell-bborder|0.5pt>|<cwith|1|1|1|2|cell-tborder|0.5pt>|<table|<row|<cell|a[n]>|<cell|assigned
1574   text>>|<row|<cell|1>|<cell|freddie>>|<row|<cell|2>|<cell|=freddie,
1575   foo={bar=baz, quux={quirk, a=fleeg}}, etc>>|<row|<cell|3>|<cell|=>>|<row|<cell|4>|<cell|freddie,
1576   foo={bar=baz, quux={quirk, a=fleeg}}, etc>>|<row|<cell|5>|<cell|freddie>>|<row|<cell|6>|<cell|,
1577   foo={bar=baz, quux={quirk, a=fleeg}}, etc>>>>>
1579   <verbatim|a[3]> will be either <verbatim|=> or <verbatim|,> and signify
1580   whether the option named in <verbatim|a[1]> has a value or not
1581   (respectively).
1583   If the option does have a value, then if the expression
1584   <verbatim|substr(a[4],1,1)> returns a brace <verbatim|{> it will signify
1585   that we need to recurse:
1587   <\nf-chunk|parse-chunk-args>
1588     <item>name=a[1];
1590     <item>if (a[3] == "=") {
1592     <item> \ if (substr(a[4],1,1) == "{") {
1594     <item> \ \ \ text = get_tex_chunk_args(substr(a[4],2), values, path name
1595     SUBSEP);
1597     <item> \ } else {
1599     <item> \ \ \ values[path name]=a[5];
1601     <item> \ \ \ text = a[6];
1603     <item> \ }
1605     <item>} else {
1607     <item> \ values[path name]="";
1609     <item> \ text = a[2];
1611     <item>}
1612   </nf-chunk||>
1614   We can test this function like this:
1616   <\nf-chunk|gca-test.awk>
1617     <item><nf-ref|get_chunk_args()|>
1619     <item>BEGIN {
1621     <item> \ SUBSEP=".";
1623     <item>
1625     <item> \ print get_tex_chunk_args("name=freddie, foo={bar=baz,
1626     quux={quirk, a=fleeg}}, etc", a);
1628     <item> \ for (b in a) {
1630     <item> \ \ \ print "a[" b "] =\<gtr\> " a[b];
1632     <item> \ }
1634     <item>}
1635   </nf-chunk||>
1637   which should give this output:
1639   <\nf-chunk|gca-test.awk-results>
1640     <item>a[foo.quux.quirk] =\<gtr\>\ 
1642     <item>a[foo.quux.a] =\<gtr\> fleeg
1644     <item>a[foo.bar] =\<gtr\> baz
1646     <item>a[etc] =\<gtr\>\ 
1648     <item>a[name] =\<gtr\> freddie
1649   </nf-chunk||>
1651   <section|Parsing chunk arguments><label|Chunk Arguments>
1653   Arguments to paramterized chunks are expressed in round brackets as a comma
1654   separated list of optional arguments. For example, a chunk that is defined
1655   with:
1657   <verbatim|\\Chunk{achunk, params=name ; address}>
1659   could be invoked as:
1661   <verbatim|\\chunkref{achunk}(John Jones, jones@example.com)>
1663   An argument list may be as simple as in <verbatim|\\chunkref{pull}(thing,
1664   otherthing)> or as complex as:
1666   <verbatim|\\chunkref{pull}(things[x, y], get_other_things(a, "(all)"))>
1668   --- which for all it's commas and quotes and parenthesis represents only
1669   two parameters: <verbatim|things[x, y]> and <verbatim|get_other_things(a,
1670   "(all)")>.
1672   If we simply split parameter list on commas, then the comma in
1673   <verbatim|things[x,y]> would split into two seperate arguments:
1674   <verbatim|things[x> and <verbatim|y]>--- neither of which make sense on
1675   their own.
1677   One way to prevent this would be by refusing to split text between matching
1678   delimiters, such as <verbatim|[>, <verbatim|]>, <verbatim|(>, <verbatim|)>,
1679   <verbatim|{>, <verbatim|}> and most likely also <verbatim|">, <verbatim|">
1680   and <verbatim|'>, <verbatim|'>. Of course this also makes it impossible to
1681   pass such mis-matched code fragments as parameters, but I think that it
1682   would be hard for readers to cope with authors who would pass such code
1683   unbalanced fragments as chunk parameters<\footnote>
1684     I know that I couldn't cope with users doing such things, and although
1685     the GPL3 license prevents me from actually forbidding anyone from trying,
1686     if they want it to work they'll have to write the code themselves and not
1687     expect any support from me.
1688   </footnote>.
1690   Unfortunately, the full set of matching delimiters may vary from language
1691   to language. In certain C++ template contexts, <verbatim|\<less\>> and
1692   <verbatim|\<gtr\>> would count as delimiters, and yet in other contexts
1693   they would not.
1695   This puts me in the unfortunate position of having to parse-somewhat all
1696   programming languages without knowing what they are!
1698   However, if this universal mode-tracking is possible, then parsing the
1699   arguments would be trivial. Such a mode tracker is described in chapter
1700   <reference|modes> and used here with simplicity.
1702   <\nf-chunk|parse_chunk_args>
1703     <item>function parse_chunk_args(language, text, values, mode,
1705     <item> \ # local vars
1707     <item> \ c, context, rest)
1709     <item>{
1711     <item> \ <nf-ref|new-mode-tracker|<tuple|context|language|mode>>
1713     <item> \ rest = mode_tracker(context, text, values);
1715     <item> \ # extract values
1717     <item> \ for(c=1; c \<less\>= context[0, "values"]; c++) {
1719     <item> \ \ \ values[c] = context[0, "values", c];
1721     <item> \ }
1723     <item> \ return rest;
1725     <item>}
1726   </nf-chunk||>
1728   <section|Expanding parameters in the text>
1730   Within the body of the chunk, the parameters are referred to with:
1731   <verbatim|${name}> and <verbatim|${address}>. There is a strong case that a
1732   <LaTeX> style notation should be used, like <verbatim|\\param{name}> which
1733   would be expressed in the listing as <verbatim|=\<less\>\\param{name}\<gtr\>>
1734   and be rendered as <verbatim|<nf-arg|name>>. Such notation would make me go
1735   blind, but I do intend to adopt it.
1737   We therefore need a function <verbatim|expand_chunk_args> which will take a
1738   block of text, a list of permitted parameters, and the arguments which must
1739   substitute for the parameters.\ 
1741   Here we split the text on <verbatim|${> which means that all parts except
1742   the first will begin with a parameter name which will be terminated by
1743   <verbatim|}>. The split function will consume the literal <verbatim|${> in
1744   each case.
1746   <\nf-chunk|expand_chunk_args()>
1747     <item>function expand_chunk_args(text, params, args, \ 
1749     <item> \ p, text_array, next_text, v, t, l)
1751     <item>{
1753     <item> \ if (split(text, text_array, "\\\\${")) {
1755     <item> \ \ \ <nf-ref|substitute-chunk-args|>
1757     <item> \ }
1759     <item>
1761     <item> \ return text;
1763     <item>}
1764   </nf-chunk||>
1766   First, we produce an associative array of substitution values indexed by
1767   parameter names. This will serve as a cache, allowing us to look up the
1768   replacement values as we extract each name.
1770   <\nf-chunk|substitute-chunk-args>
1771     <item>for(p in params) {
1773     <item> \ v[params[p]]=args[p];
1775     <item>}
1776   </nf-chunk||>
1778   We accumulate substituted text in the variable text. As the first part of
1779   the split function is the part before the delimiter --- which is
1780   <verbatim|${> in our case --- this part will never contain a parameter
1781   reference, so we assign this directly to the result kept in
1782   <verbatim|$text>.
1784   <\nf-chunk|substitute-chunk-args>
1785     <item>text=text_array[1];
1786   </nf-chunk||>
1788   We then iterate over the remaining values in the array, and substitute each
1789   reference for it's argument.
1791   <\nf-chunk|substitute-chunk-args>
1792     <item>for(t=2; t in text_array; t++) {
1794     <item> \ <nf-ref|substitute-chunk-arg|>
1796     <item>}
1797   </nf-chunk||>
1799   After the split on <verbatim|${> a valid parameter reference will consist
1800   of valid parameter name terminated by a close-brace <verbatim|}>. A valid
1801   character name begins with the underscore or a letter, and may contain
1802   letters, digits or underscores.
1804   A valid looking reference that is not actually the name of a parameter will
1805   be and not substituted. This is good because there is nothing to substitute
1806   anyway, and it avoids clashes when writing code for languages where
1807   <verbatim|${...}> is a valid construct --- such constructs will not be
1808   interfered with unless the parameter name also matches.
1810   <\nf-chunk|substitute-chunk-arg>
1811     <item>if (match(text_array[t], "^([a-zA-Z_][a-zA-Z0-9_]*)}", l) &&
1813     <item> \ \ \ l[1] in v)\ 
1815     <item>{
1817     <item> \ text = text v[l[1]] substr(text_array[t], length(l[1])+2);
1819     <item>} else {
1821     <item> \ text = text "${" text_array[t];
1823     <item>}
1824   </nf-chunk||>
1826   <chapter|Language Modes & Quoting><label|modes>
1828   <verbatim|lstlistings> and <verbatim|fangle> both recognize source
1829   languages, and perform some basic parsing and syntax highlighting in the
1830   rendered document<\footnote>
1831     although lstlisting supports many more languages
1832   </footnote>. <verbatim|lstlistings> can detect strings and comments within
1833   a language definition and perform suitable rendering, such as italics for
1834   comments, and visible-spaces within strings.
1836   Fangle similarly can recognize strings, and comments, etc, within a
1837   language, so that any chunks included with <verbatim|\\chunkref{a-chunk}>
1838   or <nf-ref|a-chunk|> can be suitably escape or quoted.
1840   <section|Modes explanation>
1842   As an example, the C language has a few parse modes, which affect the
1843   interpretation of characters.
1845   One parse mode is the string mode. The string mode is commenced by an
1846   un-escaped quotation mark <verbatim|"> and terminated by the same. Within
1847   the string mode, only one additional mode can be commenced, it is the
1848   backslash mode <verbatim|\\>, which is always terminated by the following
1849   character.
1851   Another mode is <verbatim|[> which is terminated by a <verbatim|]> (unless
1852   it occurs in a string).
1854   Consider this fragment of C code:
1856   <math|<math-tt|do_something><wide|<around*|(|<math-tt|things><wide|<around|[|<math-tt|x>,
1857   <math-tt|y>|]>|\<wide-overbrace\>><rsup|2. <math-tt|[> mode><math-tt|,
1858   get_other_things><wide|<around|(|<math-tt|a>,
1859   <wide*|<text|"><math-tt|<around|(|all|)>><text|">|\<wide-underbrace\>><rsub|4.
1860   <text|"> mode>|)>|\<wide-overbrace\>><rsup|3. <math-tt|(>
1861   mode>|)>|\<wide-overbrace\>><rsup|1. <math-tt|(> mode>>
1863   \;
1865   Mode nesting prevents the close parenthesis in the quoted string (part 4)
1866   from terminating the parenthesis mode (part 3).
1868   Each language has a set of modes, the default mode being the null mode.
1869   Each mode can lead to other modes.
1871   <section|Modes affect included chunks>
1873   For instance, consider this chunk with <verbatim|language=perl>:
1875   <\nf-chunk|test:example-perl>
1876     <item>print "hello world $0\\n";
1877   </nf-chunk|perl|>
1879   If it were included in a chunk with <verbatim|language=sh>, like this:
1881   <\nf-chunk|test:example-sh>
1882     <item>perl -e "<nf-ref|test:example-perl|>"
1883   </nf-chunk|sh|>
1885   we might want fangle would to generate output like this:
1887   <\nf-chunk|test:example-sh.result>
1888     <item>perl -e "print \\"hello world \\$0\\\\n\\";"
1889   </nf-chunk|sh|>
1891   See that the double quote <verbatim|">, back-slash <verbatim|\\> and
1892   <verbatim|$> have been quoted with a back-slash to protect them from shell
1893   interpretation.
1895   If that were then included in a chunk with language=make, like this:
1897   <\nf-chunk|test:example-makefile>
1898     <item>target: pre-req
1900     <item><nf-tab><nf-ref|test:example-sh|>
1901   </nf-chunk|make|>
1903   We would need the output to look like this --- note the <verbatim|$$> as
1904   the single <verbatim|$> has been makefile-quoted with another <verbatim|$>.
1906   <\nf-chunk|test:example-makefile.result>
1907     <item>target: pre-req
1909     <item><nf-tab>perl -e "print \\"hello world \\$$0\\\\n\\";"
1910   </nf-chunk|make|>
1912   <section|Language Mode Definitions>
1914   In order to make this work, we must define a mode-tracker supporting each
1915   language, that can detect the various quoting modes, and provide a
1916   transformation that may be applied to any included text so that included
1917   text will be interpreted correctly after any interpolation that it may be
1918   subject to at run-time.
1920   For example, the sed transformation for text to be inserted into shell
1921   double-quoted strings would be something like:
1923   <verbatim|s/\\\\/\\\\\\\\/g;s/$/\\\\$/g;s/"/\\\\"/g;>
1925   which would protect <verbatim|\\ $ ">
1927   All modes definitions are stored in a single multi-dimensional hash called
1928   modes:
1930   <verbatim|modes[language, mode, properties]>
1932   The first index is the language, and the second index is the mode. The
1933   third indexes hold properties such as terminators, possible submodes,
1934   transformations, and so forth.
1936   <\nf-chunk|xmode:set-terminators>
1937     <item>modes["<nf-arg|language>", "<nf-arg|mode>",
1938     "terminators"]="<nf-arg|terminators>";
1939   </nf-chunk||<tuple|language|mode|terminators>>
1941   <\nf-chunk|xmode:set-submodes>
1942     <item>modes["<nf-arg|language>", "<nf-arg|mode>",
1943     \ "submodes"]="<nf-arg|submodes>";
1944   </nf-chunk||<tuple|language|mode|submodes>>
1946   A useful set of mode definitions for a nameless general C-type language is
1947   shown here.
1949   Don't be confused by the double backslash escaping needed in awk. One set
1950   of escaping is for the string, and the second set of escaping is for the
1951   regex.
1953   <\todo>
1954     TODO: Add =\<less\>\\mode{}\<gtr\> command which will allow us to signify
1955     that a string is
1957     \ regex and thus fangle will quote it for us.
1958   </todo>
1960   Sub-modes are identified by a backslash, a double or single quote, various
1961   bracket styles or a <verbatim|/*> comment; specifically: <verbatim|\\>
1962   <verbatim|"> <verbatim|'> <verbatim|{> <verbatim|(> <verbatim|[>
1963   <verbatim|/*>
1965   For each of these sub-modes modes we must also identify at a mode
1966   terminator, and any sub-modes or delimiters that may be entered<\footnote>
1967     Because we are using the sub-mode characters as the mode identifier it
1968     means we can't currently have a mode character dependant on it's context;
1969     i.e. <verbatim|{> can't behave differently when it is inside
1970     <verbatim|[>.
1971   </footnote>.
1973   <\nf-chunk|common-mode-definitions>
1974     <item>modes[<nf-arg|language>, "", \ "submodes"]="\\\\\\\\\|\\"\|'\|{\|\\\\(\|\\\\[";
1975   </nf-chunk||<tuple|language>>
1977   In the default mode, a comma surrounded by un-important white space is a
1978   delimiter of language items<\footnote>
1979     whatever a <em|language item> might be
1980   </footnote>. Delimiters are used so that fangle can parse and recognise
1981   arguments individually.
1983   <\nf-chunk|common-mode-definitions>
1984     <item>modes[<nf-arg|language>, "", \ "delimiters"]=" *, *";
1985   </nf-chunk||language>
1987   and should pass this test:<todo|Why do the tests run in ?(? mode and not ??
1988   mode>
1990   <\nf-chunk|test:mode-definitions>
1991     <item>parse_chunk_args("c-like", "1,2,3", a, "");
1993     <item>if (a[1] != "1") e++;
1995     <item>if (a[2] != "2") e++;
1997     <item>if (a[3] != "3") e++;
1999     <item>if (length(a) != 3) e++;
2001     <item><nf-ref|pca-test.awk:summary|>
2003     <item>
2005     <item>parse_chunk_args("c-like", "joe, red", a, "");
2007     <item>if (a[1] != "joe") e++;
2009     <item>if (a[2] != "red") e++;
2011     <item>if (length(a) != 2) e++;
2013     <item><nf-ref|pca-test.awk:summary|>
2015     <item>
2017     <item>parse_chunk_args("c-like", "${colour}", a, "");
2019     <item>if (a[1] != "${colour}") e++;
2021     <item>if (length(a) != 1) e++;
2023     <item><nf-ref|pca-test.awk:summary|>
2024   </nf-chunk||>
2026   <subsection|Backslash>
2028   The backslash mode has no submodes or delimiters, and is terminated by any
2029   character. Note that we are not so much interested in evaluating or
2030   interpolating content as we are in delineating content. It is no matter
2031   that a double backslash (<verbatim|\\\\>) may represent a single backslash
2032   while a backslash-newline may represent white space, but it does matter
2033   that the newline in a backslash newline should not be able to terminate a C
2034   pre-processor statement; and so the newline will be consumed by the
2035   backslash terminator however it may uultimately be interpreted.
2037   <\nf-chunk|common-mode-definitions>
2038     <item>modes[<nf-arg|language>, "\\\\", "terminators"]=".";
2039   </nf-chunk||>
2041   <subsection|Strings>
2043   Common languages support two kinds of strings quoting, double quotes and
2044   single quotes.
2046   In a string we have one special mode, which is the backslash. This may
2047   escape an embedded quote and prevent us thinking that it should terminate
2048   the string.
2050   <\nf-chunk|mode:common-string>
2051     <item>modes[<nf-arg|language>, <nf-arg|quote>, "submodes"]="\\\\\\\\";
2052   </nf-chunk||<tuple|language|quote>>
2054   Otherwise, the string will be terminated by the same character that
2055   commenced it.
2057   <\nf-chunk|mode:common-string>
2058     <item>modes[<nf-arg|language>, <nf-arg|quote>,
2059     "terminators"]=<nf-arg|quote>;
2060   </nf-chunk||language>
2062   In C type languages, certain escape sequences exist in strings. We need to
2063   define mechanism to enclode any chunks included in this mode using those
2064   escape sequences. These are expressed in two parts, s meaning search, and r
2065   meaning replace.
2067   The first substitution is to replace a backslash with a double backslash.
2068   We do this first as other substitutions may introduce a backslash which we
2069   would not then want to escape again here.
2071   Note: Backslashes need double-escaping in the search pattern but not in the
2072   replacement string, hence we are replacing a literal <verbatim|\\> with a
2073   literal <verbatim|\\\\>.
2075   <\nf-chunk|mode:common-string>
2076     <item>escapes[<nf-arg|language>, <nf-arg|quote>,
2077     ++escapes[<nf-arg|language>, <nf-arg|quote>], "s"]="\\\\\\\\";
2079     <item>escapes[<nf-arg|language>, <nf-arg|quote>,
2080     \ \ escapes[<nf-arg|language>, <nf-arg|quote>], "r"]="\\\\\\\\";
2081   </nf-chunk||language>
2083   If the quote character occurs in the text, it should be preceded by a
2084   backslash, otherwise it would terminate the string unexpectedly.
2086   <\nf-chunk|mode:common-string>
2087     <item>escapes[<nf-arg|language>, <nf-arg|quote>,
2088     ++escapes[<nf-arg|language>, <nf-arg|quote>], "s"]=<nf-arg|quote>;
2090     <item>escapes[<nf-arg|language>, <nf-arg|quote>,
2091     \ \ escapes[<nf-arg|language>, <nf-arg|quote>], "r"]="\\\\"
2092     <nf-arg|quote>;
2093   </nf-chunk||language>
2095   Any newlines in the string, must be replaced by <verbatim|\\n>.
2097   <\nf-chunk|mode:common-string>
2098     <item>escapes[<nf-arg|language>, <nf-arg|quote>,
2099     ++escapes[<nf-arg|language>, <nf-arg|quote>], "s"]="\\n";
2101     <item>escapes[<nf-arg|language>, <nf-arg|quote>,
2102     \ \ escapes[<nf-arg|language>, <nf-arg|quote>], "r"]="\\\\n";
2103   </nf-chunk||language>
2105   For the common modes, we define this string handling for double and single
2106   quotes.
2108   <\nf-chunk|common-mode-definitions>
2109     <item><nf-ref|mode:common-string|<tuple|<nf-arg|language>|"\\"">>
2111     <item><nf-ref|mode:common-string|<tuple|<nf-arg|language>|"'">>
2112   </nf-chunk||>
2114   Working strings should pass this test:
2116   <\nf-chunk|test:mode-definitions>
2117     <item>parse_chunk_args("c-like", "say \\"I said, \\\\\\"Hello, how are
2118     you\\\\\\".\\", for me", a, "");
2120     <item>if (a[1] != "say \\"I said, \\\\\\"Hello, how are you\\\\\\".\\"")
2121     e++;
2123     <item>if (a[2] != "for me") e++;
2125     <item>if (length(a) != 2) e++;
2127     <item><nf-ref|pca-test.awk:summary|>
2128   </nf-chunk||>
2130   <subsection|Parentheses, Braces and Brackets>
2132   Where quotes are closed by the same character, parentheses, brackets and
2133   braces are closed by an alternate character.
2135   <\nf-chunk|mode:common-brackets>
2136     <item>modes[<nf-arg|language>, <nf-arg|open>, \ "submodes"
2137     ]="\\\\\\\\\|\\"\|{\|\\\\(\|\\\\[\|'\|/\\\\*";
2139     <item>modes[<nf-arg|language>, <nf-arg|open>, \ "delimiters"]=" *, *";
2141     <item>modes[<nf-arg|language>, <nf-arg|open>,
2142     \ "terminators"]=<nf-arg|close>;
2143   </nf-chunk||<tuple|language|open|close>>
2145   Note that the open is NOT a regex but the close token IS. <todo|When we can
2146   quote regex we won't have to put the slashes in here>
2148   <\nf-chunk|common-mode-definitions>
2149     <item><nf-ref|mode:common-brackets|<tuple|<nf-arg|language>|"{"|"}">>
2151     <item><nf-ref|mode:common-brackets|<tuple|<nf-arg|language>|"["|"\\\\]">>
2153     <item><nf-ref|mode:common-brackets|<tuple|<nf-arg|language>|"("|"\\\\)">>
2154   </nf-chunk||>
2156   <subsection|Customizing Standard Modes>
2158   <\nf-chunk|mode:add-submode>
2159     <item>modes[<nf-arg|language>, <nf-arg|mode>, "submodes"] =
2160     modes[<nf-arg|language>, <nf-arg|mode>, "submodes"] "\|"
2161     <nf-arg|submode>;
2162   </nf-chunk||<tuple|language|mode|submode>>
2164   <\nf-chunk|mode:add-escapes>
2165     <item>escapes[<nf-arg|language>, <nf-arg|mode>,
2166     ++escapes[<nf-arg|language>, <nf-arg|mode>], "s"]=<nf-arg|search>;
2168     <item>escapes[<nf-arg|language>, <nf-arg|mode>,
2169     \ \ escapes[<nf-arg|language>, <nf-arg|mode>], "r"]=<nf-arg|replace>;
2170   </nf-chunk||<tuple|language|mode|search|replace>>
2172   \;
2174   <subsection|Comments>
2176   We can define <verbatim|/* comment */> style comments and
2177   <verbatim|//comment> style comments to be added to any language:
2179   <\nf-chunk|mode:multi-line-comments>
2180     <item><nf-ref|mode:add-submode|<tuple|<nf-arg|language>|""|"/\\\\*">>
2182     <item>modes[<nf-arg|language>, "/*", "terminators"]="\\\\*/";
2183   </nf-chunk||<tuple|language>>
2185   <\nf-chunk|mode:single-line-slash-comments>
2186     <item><nf-ref|mode:add-submode|<tuple|<nf-arg|language>|""|"//">>
2188     <item>modes[<nf-arg|language>, "//", "terminators"]="\\n";
2190     <item><nf-ref|mode:add-escapes|<tuple|<nf-arg|language>|"//"|"\\n"|"\\n//">>
2191   </nf-chunk||language>
2193   We can also define <verbatim|# comment> style comments (as used in awk and
2194   shell scripts) in a similar manner.
2196   <todo|I'm having to use # for hash and \textbackslash{} for \ and have
2197   hacky work-arounds in the parser for now>
2199   <\nf-chunk|mode:add-hash-comments>
2200     <item><nf-ref|mode:add-submode|<tuple|<nf-arg|language>|""|"#">>
2202     <item>modes[<nf-arg|language>, "#", "terminators"]="\\n";
2204     <item><nf-ref|mode:add-escapes|<tuple|<nf-arg|language>|"#"|"\\n"|"\\n#">>
2205   </nf-chunk||<tuple|language>>
2207   In C, the <verbatim|#> denotes pre-processor directives which can be
2208   multi-line
2210   <\nf-chunk|mode:add-hash-defines>
2211     <item><nf-ref|mode:add-submode|<tuple|<nf-arg|language>|""|"#">>
2213     <item>modes[<nf-arg|language>, "#", "submodes" ]="\\\\\\\\";
2215     <item>modes[<nf-arg|language>, "#", "terminators"]="\\n";
2217     <item><nf-ref|mode:add-escapes|<tuple|<nf-arg|language>|"#"|"\\n"|"\\\\\\\\\\n">>
2218   </nf-chunk||<tuple|language>>
2220   <\nf-chunk|mode:quote-dollar-escape>
2221     <item>escapes[<nf-arg|language>, <nf-arg|quote>,
2222     ++escapes[<nf-arg|language>, <nf-arg|quote>], "s"]="\\\\$";
2224     <item>escapes[<nf-arg|language>, <nf-arg|quote>,
2225     \ \ escapes[<nf-arg|language>, <nf-arg|quote>], "r"]="\\\\$";
2226   </nf-chunk||<tuple|language|quote>>
2228   We can add these definitions to various languages
2230   <\nf-chunk|mode-definitions>
2231     <item><nf-ref|common-mode-definitions|<tuple|"c-like">>
2233     <item>
2235     <item><nf-ref|common-mode-definitions|<tuple|"c">>
2237     <item><nf-ref|mode:multi-line-comments|<tuple|"c">>
2239     <item><nf-ref|mode:single-line-slash-comments|<tuple|"c">>
2241     <item><nf-ref|mode:add-hash-defines|<tuple|"c">>
2243     <item>
2245     <item><nf-ref|common-mode-definitions|<tuple|"awk">>
2247     <item><nf-ref|mode:add-hash-comments|<tuple|"awk">>
2249     <item><nf-ref|mode:add-naked-regex|<tuple|"awk">>
2250   </nf-chunk||>
2252   The awk definitions should allow a comment block like this:
2254   <nf-chunk|test:comment-quote|<item># Comment:
2255   <nf-ref|test:comment-text|>|awk|>
2257   <\nf-chunk|test:comment-text>
2258     <item>Now is the time for
2260     <item>the quick brown fox to bring lemonade
2262     <item>to the party
2263   </nf-chunk||>
2265   to come out like this:
2267   <\nf-chunk|test:comment-quote:result>
2268     <item># Comment: Now is the time for
2270     <item>#the quick brown fox to bring lemonade
2272     <item>#to the party
2273   </nf-chunk||>
2275   The C definition for such a block should have it come out like this:
2277   <\nf-chunk|test:comment-quote:C-result>
2278     <item># Comment: Now is the time for\\
2280     <item>the quick brown fox to bring lemonade\\
2282     <item>to the party
2283   </nf-chunk||>
2285   <subsection|Regex>
2287   This pattern is incomplete, but meant to detect naked regular expressions
2288   in awk and perl; e.g. <verbatim|/.*$/>, however required capabilities are
2289   not present.
2291   Current it only detects regexes anchored with ^ as used in fangle.
2293   For full regex support, modes need to be named not after their starting
2294   character, but some other more fully qualified name.
2296   <\nf-chunk|mode:add-naked-regex>
2297     <item><nf-ref|mode:add-submode|<tuple|<nf-arg|language>|""|"/\\\\^">>
2299     <item>modes[<nf-arg|language>, "/^", "terminators"]="/";
2300   </nf-chunk||<tuple|language>>
2302   <subsection|Perl>
2304   <\nf-chunk|mode-definitions>
2305     <item><nf-ref|common-mode-definitions|<tuple|"perl">>
2307     <item><nf-ref|mode:multi-line-comments|<tuple|"perl">>
2309     <item><nf-ref|mode:add-hash-comments|<tuple|"perl">>
2310   </nf-chunk||>
2312   Still need to add add <verbatim|s/>, submode <verbatim|/>, terminate both
2313   with <verbatim|//>. This is likely to be impossible as perl regexes can
2314   contain perl.
2316   <subsection|sh>
2318   Shell single-quote strings are different to other strings and have no
2319   escape characters. The only special character is the single quote
2320   <verbatim|'> which always closes the string. Therefore we cannot use
2321   <nf-ref|common-mode-definitions|<tuple|"sh">> but we will invoke most of
2322   it's definition apart from single-quote strings.\ 
2324   <\nf-chunk|mode-definitions>
2325     <item>modes["sh", "", \ "submodes"]="\\\\\\\\\|\\"\|'\|{\|\\\\(\|\\\\[\|\\\\$\\\\(";
2327     <item>modes["sh", "\\\\", "terminators"]=".";
2329     <item>
2331     <item>modes["sh", "\\"", "submodes"]="\\\\\\\\\|\\\\$\\\\(";
2333     <item>modes["sh", "\\"", "terminators"]="\\"";
2335     <item>escapes["sh", "\\"", ++escapes["sh", "\\""], "s"]="\\\\\\\\";
2337     <item>escapes["sh", "\\"", \ \ escapes["sh", "\\""], "r"]="\\\\\\\\";
2339     <item>escapes["sh", "\\"", ++escapes["sh", "\\""], "s"]="\\"";
2341     <item>escapes["sh", "\\"", \ \ escapes["sh", "\\""], "r"]="\\\\" "\\"";
2343     <item>escapes["sh", "\\"", ++escapes["sh", "\\""], "s"]="\\n";
2345     <item>escapes["sh", "\\"", \ \ escapes["sh", "\\""], "r"]="\\\\n";
2347     <item>
2349     <item>modes["sh", "'", "terminators"]="'";
2351     <item>escapes["sh", "'", ++escapes["sh", "'"], "s"]="'";
2353     <item>escapes["sh", "'", \ \ escapes["sh", "'"], "r"]="'\\\\'" "'";
2355     <item><nf-ref|mode:common-brackets|<tuple|"sh"|"$("|"\\\\)">>
2357     <item><nf-ref|mode:add-tunnel|<tuple|"sh"|"$("|"">>
2359     <item><nf-ref|mode:common-brackets|<tuple|"sh"|"{"|"}">>
2361     <item><nf-ref|mode:common-brackets|<tuple|"sh"|"["|"\\\\]">>
2363     <item><nf-ref|mode:common-brackets|<tuple|"sh"|"("|"\\\\)">>
2365     <item><nf-ref|mode:add-hash-comments|<tuple|"sh">>
2367     <item><nf-ref|mode:quote-dollar-escape|<tuple|"sh"|"\\"">>
2368   </nf-chunk|awk|>
2370   The definition of add-tunnel is:
2372   <\nf-chunk|mode:add-tunnel>
2373     <item>escapes[<nf-arg|language>, <nf-arg|mode>,
2374     ++escapes[<nf-arg|language>, <nf-arg|mode>], "tunnel"]=<nf-arg|tunnel>;
2375   </nf-chunk||<tuple|language|mode|tunnel>>
2377   <subsection|Make>
2379   BUGS: makefile tab mode is terminated by newline, but chunks never end in a
2380   newline! So tab mode is never closed unless there is a trailing blank line!
2382   For makefiles, we currently recognize 2 modes: the <em|null> mode and
2383   <nf-tab> mode, which is tabbed mode and contains the makefile recipie.\ 
2385   \;
2387   <\nf-chunk|mode-definitions>
2388     <item>modes["make", "", \ "submodes"]="<nf-tab>";
2389   </nf-chunk|awk|>
2391   In the <em|null> mode the only escape is <verbatim|$> which must be
2392   converted to <verbatim|$$>, and hash-style comments. POSIX requires that
2393   line-continuations extend hash-style comments and so fangle-style
2394   transformations to replicate the hash at the start of each line is not
2395   strictly required, however it is harmless, easier to read, and required by
2396   some implementations of <verbatim|make> which do not implement POSIX
2397   requirements correctly.
2399   <\nf-chunk|mode-definitions>
2400     <item>escapes["make", "", ++escapes["make", ""], "s"]="\\\\$";
2402     <item>escapes["make", "", escapes["make", ""], "r"]="$$";
2404     <item><nf-ref|mode:add-hash-comments|<tuple|"make">>
2405   </nf-chunk|awk|>
2407   Tabbed mode is harder to manage, as the GNU Make Manual says in the section
2408   on <hlink|splitting lines|http://www.gnu.org/s/hello/manual/make/Splitting-Lines.html>.
2409   There is no obvious way to escape a multi-line text that occurs as part of
2410   a makefile recipe.
2412   Traditionally, if the newline's in the shell script all occur at points of
2413   top-level shell syntax, then we could replace them with <verbatim|
2414   ;\\n<nf-tab>>and largely get the right effect.
2416   <\with|par-columns|2>
2417     <\nf-chunk|test:make:1>
2418       <label|test-make-line-quoting><item>all:
2420       <item><nf-tab>echo making
2422       <item><nf-tab><nf-ref|test:make:1-inc|$@>
2423     </nf-chunk|make|>
2425     \;
2427     \;
2429     <\nf-chunk|test:make:1-inc>
2430       <item>if test "<nf-arg|target>" = "all"
2432       <item>then echo yes, all
2434       <item>else echo "<nf-arg|target>" \| sed -e '/^\\//{
2436       <item> \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ p;s/^/../
2438       <item> \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ }'
2440       <item>fi
2441     </nf-chunk|sh|<tuple|target>>
2442   </with>
2444   The two chunks above could reasonably produce something like this:
2446   <\nf-chunk|test:make:1.result.bad>
2447     <item>all:
2449     <item><nf-tab>echo making
2451     <item><nf-tab>if test "$@" = "all" ;\\
2453     <item><nf-tab>then echo yes, all ;\\
2455     <item><nf-tab>else echo "$@" \| sed -e '/^\\//{ ;\\
2457     <item><nf-tab> \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ p;s/^/../
2458     ;\\
2460     <item><nf-tab> \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ }' ;\\
2462     <item><nf-tab>fi
2463   </nf-chunk|make|>
2465   However <verbatim|;\\> is not a proper continuation inside a multi-line sed
2466   script. There is no simple continuation that fangle could use <emdash> and
2467   in any case it would depend on what type of quote marks were used in the
2468   bash that contained the sed.\ 
2470   We would prefer to use a more intuitive single backslash at the end of the
2471   line, giving these results.
2473   <\nf-chunk|test:make:1.result>
2474     <item>all:
2476     <item><nf-tab>echo making
2478     <item><nf-tab>if test "$$@" = "all"\\
2480     <item><nf-tab> then echo yes, all\\
2482     <item><nf-tab> else echo "$$@" \| sed -e '/^\\//{\\
2484     <item><nf-tab> \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ p;s/^/../\\
2486     <item><nf-tab> \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ }'\\
2488     <item><nf-tab> fi
2489   </nf-chunk|make|>
2491   The difficulty lies in the way that make handles the recipe. Each line of
2492   the recipe is invoked as a separate shell command (using <verbatim|$(SHELL)
2493   -c>) unless the last character of the line was a backslash. In such a case,
2494   the backslash and the newline and the nextline are handed to the shell
2495   (although the tab character that prefixes the next line is stripped).
2497   This behaviour makes it impossible to hand a newline character to the shell
2498   unless it is prefixed by a backslash. If an included shell fragment
2499   contained strings with literal newline characters then there would be no
2500   easy way to escape these and preserve the value of the string.
2502   A different style of makefile construction might be used <emdash> the
2503   recipe could be stored in a <hlink|target specific
2504   variable|http://www.gnu.org/s/hello/manual/make/Target_002dspecific.html>
2505   which contains the recipe with a more normal escape mechanism.
2507   A better solution is to use a shell helper that strips the back-slash which
2508   precedes the newline character and then passes the arguments to the normal
2509   shell.
2511   Because this is a simple operation and because bash is so flexible, this
2512   can be managed in a single line <em|within the makefile itself.>
2514   As a newline will only exist when preceded by the backslash, and as the
2515   purpose of the backash is to protect th newline, that is needed is to
2516   remove any backslash that is followed by a newline.
2518   Bash is capable of doing this with its pattern substitution. If
2519   <verbatim|A=123:=456:=789> then <verbatim|${A//:=/=}> will be
2520   <verbatim|123=456=789>. We don't want to just perform the substitution in a
2521   single variable but in fact in all of <verbatim|$@''>, however bash will
2522   repeat substitution over all members of an array, so this is done
2523   automatically.
2525   In bash, <verbatim|$'\\012'> represents the newline character (expressed as
2526   an octal escape sequence), so this expression will replace
2527   backslash-newline with a single newline.
2529   <\nf-chunk|fix-requote-newline>
2530     <item>"${@//\\\\$'\\012'/$'\\012'}"
2531   </nf-chunk|sh|>
2533   We use this as part of a larger statement which will invoke such a
2534   transformed command ine using any particular shell. The trailing
2535   <verbatim|--> prevents any options in the command line from being
2536   interpreted as options to our bash command <emdash> instead they will be
2537   transformed and passed to the inner shell which is invoked with
2538   <verbatim|exec> so that our fixup-shell does not hang around longer than is
2539   needed.
2541   <\nf-chunk|fix-make-shell>
2542     <item>bash -c 'exec <nf-arg|shell> <nf-ref|fix-requote-newline|>' --
2543   </nf-chunk|sh|<tuple|shell>>
2545   We can then cinlude a line like this in our makefiles. We should rather
2546   pass <verbatim|$(SHELL)> as the chunk argument than <verbatim|bash>, but
2547   currently fangle will not track which nested-inclusion level the argument
2548   comes from and will quote the <verbatim|$> in <verbatim|$(SHELL)> in the
2549   same way it quotes a <verbatim|$> that may occur in the bash script, so
2550   this would come out as <verbatim|$$(SHELL) and have the wrong effect.>
2552   <\nf-chunk|make-fix-make-shell>
2553     <item>SHELL:=<nf-ref|fix-make-shell|<tuple|bash>>
2554   </nf-chunk||>
2556   The full escaped and quoted text with <verbatim|$(SHELL)> and suitale for
2557   inclusion in a Makefile is:
2559   <\verbatim>
2560     SHELL:=bash -c 'exec $(SHELL) "$${@//\\\\$$'\\''\\012'\\''/$$'\\''\\012'\\''}"'
2561     --
2562   </verbatim>
2564   Based on this, we just need to escape newlines (in tabbed mode) with a
2565   regular backslash:
2567   Note that terminators applies to literal, not included text, escapes apply
2568   to included, not literal text; also that the tab character is hard-wired
2569   into the pattern, and that the make variable <verbatim|.RECIPEPREFIX> might
2570   change this to something else.
2572   <\nf-chunk|mode-definitions>
2573     <item>modes["make", "<nf-tab>", "terminators"]="\\\\n";
2575     <item>escapes["make", "<nf-tab>", ++escapes["make", "<nf-tab>"],
2576     "s"]="\\\\n";
2578     <item>escapes["make", "<nf-tab>", \ \ escapes["make", "<nf-tab>"],
2579     "r"]="\\\\\\n<nf-tab>";
2580   </nf-chunk|awk|>
2582   With this improved quoting, the test on <reference|test-make-line-quoting>
2583   will actually produce this:
2585   <\nf-chunk|test:make:1.result-actual>
2586     <item>all:
2588     <item><nf-tab>echo making
2590     <item><nf-tab>if test "$$@" = "all"\\
2592     <item><nf-tab> then echo yes, all\\
2594     <item><nf-tab> else echo not all\\
2596     <item><nf-tab> fi
2597   </nf-chunk|make|>
2599   The chunk argument <verbatim|$@> has been quoted (which would have been
2600   fine if we were passing the name of a shell variable), and the other shell
2601   lines are (harmlessly) indented by 1 space as part of fangle
2602   indent-matching which should have taken into account the expanded tab size,
2603   and should generally take into account the expanded prefix of the line
2604   whose indent it is trying to match, but which in this case we want to have
2605   no effect at all!
2607   <\todo>
2608     The $@ was passed from a make fragment. In what cases should it be
2609     converted to $$@?
2611     Do we need to track the language of sources of arguments?
2612   </todo>
2614   A more ugly work-around until this problem can be solved would be to use
2615   this notation:
2617   <\nf-chunk|test:make:2>
2618     <item>all:
2620     <item><nf-tab>echo making
2622     <item><nf-tab>ARG="$@"; <nf-ref|test:make:1-inc|$ARG>
2623   </nf-chunk|make|>
2625   which produces this output which is more useful (because it works):
2627   <\nf-chunk|test:make:2.result>
2628     <item>all:
2630     <item><nf-tab>echo making
2632     <item><nf-tab>ARG="$@"; if test "$$ARG" = "all"\\
2634     <item><nf-tab> \ \ \ \ \ \ \ \ \ \ then echo yes, all\\
2636     <item><nf-tab> \ \ \ \ \ \ \ \ \ \ else echo "$$ARG" \| sed -e '/^\\//{\\
2638     <item><nf-tab> \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ p;s/^/../\\
2640     <item><nf-tab> \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ }'\\
2642     <item><nf-tab> \ \ \ \ \ \ \ \ \ \ fi
2643   </nf-chunk|make|>
2645   <section|Quoting scenarios>
2647   <subsection|Direct quoting>
2649   He we give examples of various quoting scenarios and discuss what the
2650   expected outcome might be and how this could be obtained.
2652   <\with|par-columns|2>
2653     <\nf-chunk|test:q:1>
2654       <item>echo "$(<nf-ref|test:q:1-inc|>)"
2655     </nf-chunk|sh|>
2657     <\nf-chunk|test:q:1-inc>
2658       <item>echo "hello"
2659     </nf-chunk|sh|>
2660   </with>
2662   Should this examples produce <verbatim|echo "$(echo "hello")"> or
2663   <verbatim|echo "$(echo \\"hello\\")"> ?
2665   This depends on what the author intended, but we must provde a way to
2666   express that intent.
2668   We might argue that as both chunks have <verbatim|lang=sh> the intent must
2669   have been to quote the included chunk <emdash> but consider that this might
2670   be shell script that writes shell script.
2672   If <nf-ref|test:q:1-inc|> had <verbatim|lang=text> then it certainly would
2673   have been right to quote it, which leads us to ask: in what ways can we
2674   reduce quoting if lang of the included chunk is compatible with the lang of
2675   the including chunk?
2677   If we take a completely nested approach then even though <verbatim|$(> mode
2678   might do no quoting of it's own, <verbatim|"> mode will still do it's own
2679   quoting. We need a model where the nested <verbatim|$(> mode will prevent
2680   <verbatim|"> from quoting.
2682   This leads rise to the <em|tunneling> feature. In bash, the <verbatim|$(>
2683   gives rise to a new top-level parsing scenario, so we need to enter the
2684   <em|null> mode, and also ignore any quoting and then undo-this when the
2685   <verbatim|$(> mode is terminated by the corresponding close <verbatim|)>.
2687   We shall say that tunneling is when a mode in a language ignores other
2688   modes in the same language and arrives back at an earlier <em|null> mode of
2689   the same language.
2691   In example <nf-ref|test:q:1|> above, the nesting of modes is: <em|null>,
2692   <verbatim|">, <verbatim|$(>
2694   When mode <verbatim|$(> is commenced, the stack of nest modes will be
2695   traversed. If the <em|null> mode can be found in the same language, without
2696   the language varying, then a tunnel will be established so that the
2697   intervening modes, <verbatim|"> in this case, can be skipped when the modes
2698   are enumerated to quote the texted being emitted.
2700   In such a case, the correct result would be:
2702   <\nf-chunk|test:q:1.result>
2703     <item>echo "$(echo "hello")"
2704   </nf-chunk|sh|>
2706   <section|Some tests>
2708   Also, the parser must return any spare text at the end that has not been
2709   processed due to a mode terminator being found.
2711   <\nf-chunk|test:mode-definitions>
2712     <item>rest = parse_chunk_args("c-like", "1, 2, 3) spare", a, "(");
2714     <item>if (a[1] != 1) e++;
2716     <item>if (a[2] != 2) e++;
2718     <item>if (a[3] != 3) e++;
2720     <item>if (length(a) != 3) e++;
2722     <item>if (rest != " spare") e++;
2724     <item><nf-ref|pca-test.awk:summary|>
2725   </nf-chunk||>
2727   We must also be able to parse the example given earlier.
2729   <\nf-chunk|test:mode-definitions>
2730     <item>parse_chunk_args("c-like", "things[x, y], get_other_things(a,
2731     \\"(all)\\"), 99", a, "(");
2733     <item>if (a[1] != "things[x, y]") e++;
2735     <item>if (a[2] != "get_other_things(a, \\"(all)\\")") e++;
2737     <item>if (a[3] != "99") e++;
2739     <item>if (length(a) != 3) e++;
2741     <item><nf-ref|pca-test.awk:summary|>
2742   </nf-chunk||>
2744   <section|A non-recursive mode tracker>
2746   As each chunk is output a new mode tracker for that language is initialized
2747   in it's normal state. As text is output for that chunk the output mode is
2748   tracked. When a new chunk is included, a transformation appropriate to that
2749   mode is selected and pushed onto a stack of transformations. Any text to be
2750   output is passed through this stack of transformations.
2752   It remains to consider if the chunk-include function should return it's
2753   generated text so that the caller can apply any transformations (and
2754   formatting), or if it should apply the stack of transformations itself.
2756   Note that the transformed included text should have the property of not
2757   being able to change the mode in the current chunk.
2759   <todo|Note chunk parameters should probably also be transformed>
2761   <subsection|Constructor>
2763   The mode tracker holds its state in a stack based on a numerically indexed
2764   hash. This function, when passed an empty hash, will intialize it.
2766   <\nf-chunk|new_mode_tracker()>
2767     <item>function new_mode_tracker(context, language, mode) {
2769     <item> \ context[""] = 0;
2771     <item> \ context[0, "language"] = language;
2773     <item> \ context[0, "mode"] = mode;
2775     <item>}
2776   </nf-chunk||>
2778   Awk functions cannot return an array, but arrays are passed by reference.
2779   Because of this we must create the array first and pass it in, so we have a
2780   fangle macro to do this:
2782   <\nf-chunk|new-mode-tracker>
2783     <item><nf-ref|awk-delete-array|<tuple|<nf-arg|context>>>
2785     <item>new_mode_tracker(<nf-arg|context>, <nf-arg|language>,
2786     <nf-arg|mode>);
2787   </nf-chunk|awk|<tuple|context|language|mode>>
2789   <subsection|Management>
2791   And for tracking modes, we dispatch to a mode-tracker action based on the
2792   current language
2794   <\nf-chunk|mode_tracker>
2795     <item>function push_mode_tracker(context, language, mode,
2797     <item> \ # local vars
2799     <item> \ top)
2801     <item>{
2803     <item> \ if (! ("" in context)) {
2805     <item> \ \ \ <nf-ref|new-mode-tracker|<tuple|context|language|mode>>
2807     <item> \ \ \ return;
2809     <item> \ } else {
2811     <item> \ \ \ top = context[""];
2813     <item># \ \ \ if (context[top, "language"] == language && mode=="") mode
2814     = context[top, "mode"];
2816     <item> \ \ \ if (context[top, "language"] == language && context[top,
2817     "mode"] == mode) return top - 1;
2819     <item> \ \ \ old_top = top;
2821     <item> \ \ \ top++;
2823     <item> \ \ \ context[top, "language"] = language;
2825     <item> \ \ \ context[top, "mode"] = mode;
2827     <item> \ \ \ context[""] = top;
2829     <item> \ }
2831     <item> \ return old_top;
2833     <item>}
2834   </nf-chunk|awk|>
2836   <\nf-chunk|mode_tracker>
2837     <item>function dump_mode_tracker(context, \ 
2839     <item> \ c, d)
2841     <item>{
2843     <item> \ for(c=0; c \<less\>= context[""]; c++) {
2845     <item> \ \ \ printf(" %2d \ \ %s:%s\\n", c, context[c, "language"],
2846     context[c, "mode"]) \<gtr\> "/dev/stderr";
2848     <item># \ \ \ for(d=1; ( (c, "values", d) in context); d++) {
2850     <item># \ \ \ \ \ printf(" \ \ %2d %s\\n", d, context[c, "values", d])
2851     \<gtr\> "/dev/stderr";
2853     <item># \ \ \ }
2855     <item> \ }
2857     <item>}
2858   </nf-chunk||>
2860   <\nf-chunk|mode_tracker>
2861     <item>function pop_mode_tracker(context, context_origin)
2863     <item>{
2865     <item> \ if ( (context_origin) && ("" in context) && context[""] !=
2866     (1+context_origin) && context[""] != context_origin) {
2868     <item> \ \ \ print "Context level: " context[""] ", origin: "
2869     context_origin "\\n" \<gtr\> "/dev/stderr"
2871     <item> \ \ \ return 0;
2873     <item> \ }
2875     <item> \ context[""] = context_origin;
2877     <item> \ return 1;
2879     <item>}
2880   </nf-chunk||>
2882   This implies that any chunk must be syntactically whole; for instance, this
2883   is fine:
2885   <\nf-chunk|test:whole-chunk>
2886     <item>if (1) {
2888     <item> \ <nf-ref|test:say-hello|>
2890     <item>}
2891   </nf-chunk||>
2893   <\nf-chunk|test:say-hello>
2894     <item>print "hello";
2895   </nf-chunk||>
2897   But this is not fine; the chunk <nf-ref|test:hidden-else|> is not properly
2898   cromulent.
2900   <\nf-chunk|test:partial-chunk>
2901     <item>if (1) {
2903     <item> \ <nf-ref|test:hidden-else|>
2905     <item>}
2906   </nf-chunk||>
2908   <\nf-chunk|test:hidden-else>
2909     <item> \ print "I'm fine";
2911     <item>} else {
2913     <item> \ print "I'm not";
2914   </nf-chunk||>
2916   These tests will check for correct behaviour:
2918   <\nf-chunk|test:cromulence>
2919     <item>echo Cromulence test
2921     <item>passtest $FANGLE -Rtest:whole-chunk $TXT_SRC &\<gtr\>/dev/null \|\|
2922     ( echo "Whole chunk failed" && exit 1 )
2924     <item>failtest $FANGLE -Rtest:partial-chunk $TXT_SRC &\<gtr\>/dev/null
2925     \|\| ( echo "Partial chunk failed" && exit 1 )
2926   </nf-chunk||>
2928   <subsection|Tracker>
2930   We must avoid recursion as a language construct because we intend to employ
2931   mode-tracking to track language mode of emitted code, and the code is
2932   emitted from a function which is itself recursive, so instead we implement
2933   psuedo-recursion using our own stack based on a hash.
2935   <\nf-chunk|mode_tracker()>
2936     <item>function mode_tracker(context, text, values,\ 
2938     <item> \ # optional parameters
2940     <item> \ # local vars
2942     <item> \ mode, submodes, language,
2944     <item> \ cindex, c, a, part, item, name, result, new_values, new_mode,\ 
2946     <item> \ delimiters, terminators)
2948     <item>{
2949   </nf-chunk|awk|>
2951   We could be re-commencing with a valid context, so we need to setup the
2952   state according to the last context.
2954   <\nf-chunk|mode_tracker()>
2955     <item> \ cindex = context[""] + 0;
2957     <item> \ mode = context[cindex, "mode"];
2959     <item> \ language = context[cindex, "language" ];
2960   </nf-chunk||>
2962   First we construct a single large regex combining the possible sub-modes
2963   for the current mode along with the terminators for the current mode.
2965   <\nf-chunk|parse_chunk_args-reset-modes>
2966     <item> \ submodes=modes[language, mode, "submodes"];
2968     <item>
2970     <item> \ if ((language, mode, "delimiters") in modes) {
2972     <item> \ \ \ delimiters = modes[language, mode, "delimiters"];
2974     <item> \ \ \ if (length(submodes)\<gtr\>0) submodes = submodes "\|";
2976     <item> \ \ \ submodes=submodes delimiters;
2978     <item> \ } else delimiters="";
2980     <item> \ if ((language, mode, "terminators") in modes) {
2982     <item> \ \ \ terminators = modes[language, mode, "terminators"];
2984     <item> \ \ \ if (length(submodes)\<gtr\>0) submodes = submodes "\|";
2986     <item> \ \ \ submodes=submodes terminators;
2988     <item> \ } else terminators="";
2989   </nf-chunk||>
2991   If we don't find anything to match on --- probably because the language is
2992   not supported --- then we return the entire text without matching anything.
2994   <\nf-chunk|parse_chunk_args-reset-modes>
2995     <item> if (! length(submodes)) return text;
2996   </nf-chunk||>
2998   <\nf-chunk|mode_tracker()>
2999     <item><nf-ref|parse_chunk_args-reset-modes|>
3000   </nf-chunk||>
3002   We then iterate the text (until there is none left) looking for sub-modes
3003   or terminators in the regex.
3005   <\nf-chunk|mode_tracker()>
3006     <item> \ while((cindex \<gtr\>= 0) && length(text)) {
3008     <item> \ \ \ if (match(text, "(" submodes ")", a)) {
3009   </nf-chunk||>
3011   A bug that creeps in regularly during development is bad regexes of zero
3012   length which result in an infinite loop (as no text is consumed), so I
3013   catch that right away with this test.
3015   <\nf-chunk|mode_tracker()>
3016     <item> \ \ \ \ \ if (RLENGTH\<less\>1) {
3018     <item> \ \ \ \ \ \ \ error(sprintf("Internal error, matched zero length
3019     submode, should be impossible - likely regex computation error\\n" \\
3021     <item> \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ "Language=%s\\nmode=%s\\nmatch=%s\\n",
3022     language, mode, submodes));
3024     <item> \ \ \ \ \ }
3025   </nf-chunk||>
3027   part is defined as the text up to the sub-mode or terminator, and this is
3028   appended to item --- which is the current text being gathered. If a mode
3029   has a delimiter, then item is reset each time a delimiter is found.
3031   <math|<wide|<with|mode|prog|"><wide*|hello|\<wide-underbrace\>><rsub|item>,
3032   <wide*|there|\<wide-underbrace\>><rsub|item><with|mode|prog|">|\<wide-overbrace\>><rsup|item>,
3033   \ <wide|he said.|\<wide-overbrace\>><rsup|item>>
3035   <\nf-chunk|mode_tracker()>
3036     <item> \ \ \ \ \ part = substr(text, 1, RSTART -1);
3038     <item> \ \ \ \ \ item = item part;
3039   </nf-chunk||>
3041   We must now determine what was matched. If it was a terminator, then we
3042   must restore the previous mode.
3044   <\nf-chunk|mode_tracker()>
3045     <item> \ \ \ \ \ if (match(a[1], "^" terminators "$")) {
3047     <item>#printf("%2d EXIT \ MODE [%s] by [%s] [%s]\\n", cindex, mode, a[1],
3048     text) \<gtr\> "/dev/stderr"
3050     <item> \ \ \ \ \ \ \ context[cindex, "values", ++context[cindex,
3051     "values"]] = item;
3053     <item> \ \ \ \ \ \ \ delete context[cindex];
3055     <item> \ \ \ \ \ \ \ context[""] = --cindex;
3057     <item> \ \ \ \ \ \ \ if (cindex\<gtr\>=0) {
3059     <item> \ \ \ \ \ \ \ \ \ mode = context[cindex, "mode"];
3061     <item> \ \ \ \ \ \ \ \ \ language = context[cindex, "language"];
3063     <item> \ \ \ \ \ \ \ \ \ <nf-ref|parse_chunk_args-reset-modes|>
3065     <item> \ \ \ \ \ \ \ }
3067     <item> \ \ \ \ \ \ \ item = item a[1];
3069     <item> \ \ \ \ \ \ \ text = substr(text, 1 + length(part) +
3070     length(a[1]));
3072     <item> \ \ \ \ \ }
3073   </nf-chunk||>
3075   If a delimiter was matched, then we must store the current item in the
3076   parsed values array, and reset the item.
3078   <\nf-chunk|mode_tracker()>
3079     <item> \ \ \ \ \ else if (match(a[1], "^" delimiters "$")) {
3081     <item> \ \ \ \ \ \ \ if (cindex==0) {
3083     <item> \ \ \ \ \ \ \ \ \ context[cindex, "values", ++context[cindex,
3084     "values"]] = item;
3086     <item> \ \ \ \ \ \ \ \ \ item = "";
3088     <item> \ \ \ \ \ \ \ } else {
3090     <item> \ \ \ \ \ \ \ \ \ item = item a[1];
3092     <item> \ \ \ \ \ \ \ }
3094     <item> \ \ \ \ \ \ \ text = substr(text, 1 + length(part) +
3095     length(a[1]));
3097     <item> \ \ \ \ \ }
3098   </nf-chunk||>
3100   otherwise, if a new submode is detected (all submodes have terminators), we
3101   must create a nested parse context until we find the terminator for this
3102   mode.
3104   <\nf-chunk|mode_tracker()>
3105     <item> else if ((language, a[1], "terminators") in modes) {
3107     <item> \ \ \ \ \ \ \ #check if new_mode is defined
3109     <item> \ \ \ \ \ \ \ item = item a[1];
3111     <item>#printf("%2d ENTER MODE [%s] in [%s]\\n", cindex, a[1], text)
3112     \<gtr\> "/dev/stderr"
3114     <item> \ \ \ \ \ \ \ text = substr(text, 1 + length(part) +
3115     length(a[1]));
3117     <item> \ \ \ \ \ \ \ context[""] = ++cindex;
3119     <item> \ \ \ \ \ \ \ context[cindex, "mode"] = a[1];
3121     <item> \ \ \ \ \ \ \ context[cindex, "language"] = language;
3123     <item> \ \ \ \ \ \ \ mode = a[1];
3125     <item> \ \ \ \ \ \ \ <nf-ref|parse_chunk_args-reset-modes|>
3127     <item> \ \ \ \ \ } else {
3129     <item> \ \ \ \ \ \ \ error(sprintf("Submode '%s' set unknown mode in
3130     text: %s\\nLanguage %s Mode %s\\n", a[1], text, language, mode));
3132     <item> \ \ \ \ \ \ \ text = substr(text, 1 + length(part) +
3133     length(a[1]));
3135     <item> \ \ \ \ \ }
3137     <item> \ \ \ }
3138   </nf-chunk||>
3140   In the final case, we parsed to the end of the string. If the string was
3141   entire, then we should have no nested mode context, but if the string was
3142   just a fragment we may have a mode context which must be preserved for the
3143   next fragment. Todo: Consideration ought to be given if sub-mode strings
3144   are split over two fragments.
3146   <\nf-chunk|mode_tracker()>
3147     <item>else {
3149     <item> \ \ \ \ \ context[cindex, "values", ++context[cindex, "values"]] =
3150     item text;
3152     <item> \ \ \ \ \ text = "";
3154     <item> \ \ \ \ \ item = "";
3156     <item> \ \ \ }
3158     <item> \ }
3160     <item>
3162     <item> \ context["item"] = item;
3164     <item>
3166     <item> \ if (length(item)) context[cindex, "values", ++context[cindex,
3167     "values"]] = item;
3169     <item> \ return text;
3171     <item>}
3172   </nf-chunk||>
3174   <subsubsection|One happy chunk>
3176   All the mode tracker chunks are referred to here:
3178   <\nf-chunk|mode-tracker>
3179     <item><nf-ref|new_mode_tracker()|>
3181     <item><nf-ref|mode_tracker()|>
3182   </nf-chunk||>
3184   <subsubsection|Tests>
3186   We can test this function like this:
3188   <\nf-chunk|pca-test.awk>
3189     <item><nf-ref|error()|>
3191     <item><nf-ref|mode-tracker|>
3193     <item><nf-ref|parse_chunk_args()|>
3195     <item>BEGIN {
3197     <item> \ SUBSEP=".";
3199     <item> \ <nf-ref|mode-definitions|>
3201     <item>
3203     <item> \ <nf-ref|test:mode-definitions|>
3205     <item>}
3206   </nf-chunk|awk|>
3208   <\nf-chunk|pca-test.awk:summary>
3209     <item>if (e) {
3211     <item> \ printf "Failed " e
3213     <item> \ for (b in a) {
3215     <item> \ \ \ print "a[" b "] =\<gtr\> " a[b];
3217     <item> \ }
3219     <item>} else {
3221     <item> \ print "Passed"
3223     <item>}
3225     <item>split("", a);
3227     <item>e=0;
3228   </nf-chunk|awk|>
3230   which should give this output:
3232   <\nf-chunk|pca-test.awk-results>
3233     <item>a[foo.quux.quirk] =\<gtr\>\ 
3235     <item>a[foo.quux.a] =\<gtr\> fleeg
3237     <item>a[foo.bar] =\<gtr\> baz
3239     <item>a[etc] =\<gtr\>\ 
3241     <item>a[name] =\<gtr\> freddie
3242   </nf-chunk||>
3244   <section|Escaping and Quoting>
3246   For the time being and to get around <TeXmacs> inability to export a
3247   <kbd|TAB> character, the right arrow <with|mode|math|\<mapsto\>> whose
3248   UTF-8 sequence is ...
3250   <todo|complete>
3252   Another special character is used, the left-arrow
3253   <with|mode|math|\<mapsfrom\>> with UTF-8 sequence 0xE2 0x86 0xA4 is used to
3254   strip any preceding white space as a way of un-tabbing and removing indent
3255   that has been applied <emdash> this is important for bash here documents,
3256   and the like. It's a filthy hack.
3258   <todo|remove the hack>
3260   <\nf-chunk|mode_tracker>
3261     \;
3263     <item>function untab(text) {
3265     <item> \ gsub("[[:space:]]*\\xE2\\x86\\xA4","", text);
3267     <item> \ return text;
3269     <item>}
3270   </nf-chunk||>
3272   Each nested mode can optionally define a set of transforms to be applied to
3273   any text that is included from another language.
3275   This code can perform transforms from index c downwards.
3277   <\nf-chunk|mode_tracker>
3278     <item>function transform_escape(context, text, top,
3280     <item> \ c, cp, cpl, s, r)
3282     <item>{
3284     <item> \ for(c = top; c \<gtr\>= 0; c--) {
3286     <item> \ \ \ if ( (context[c, "language"], context[c, "mode"]) in
3287     escapes) {
3289     <item> \ \ \ \ \ cpl = escapes[context[c, "language"], context[c,
3290     "mode"]];
3292     <item> \ \ \ \ \ for (cp = 1; cp \<less\>= cpl; cp ++) {
3294     <item> \ \ \ \ \ \ \ s = escapes[context[c, "language"], context[c,
3295     "mode"], cp, "s"];
3297     <item> \ \ \ \ \ \ \ r = escapes[context[c, "language"], context[c,
3298     "mode"], cp, "r"];
3300     <item> \ \ \ \ \ \ \ if (length(s)) {
3302     <item> \ \ \ \ \ \ \ \ \ gsub(s, r, text);
3304     <item> \ \ \ \ \ \ \ }
3306     <item> \ \ \ \ \ \ \ if ( (context[c, "language"], context[c, "mode"],
3307     cp, "t") in escapes ) {
3309     <item> \ \ \ \ \ \ \ \ \ quotes[src, "t"] = escapes[context[c,
3310     "language"], context[c, "mode"], cp, "t"];
3312     <item> \ \ \ \ \ \ \ }
3314     <item> \ \ \ \ \ }
3316     <item> \ \ \ }
3318     <item> \ }
3320     <item> \ return text;
3322     <item>}
3324     <item>function dump_escaper(quotes, r, cc) {
3326     <item> \ for(cc=1; cc\<less\>=c; cc++) {
3328     <item> \ \ \ printf("%2d s[%s] r[%s]\\n", cc, quotes[cc, "s"], quotes[cc,
3329     "r"]) \<gtr\> "/dev/stderr"
3331     <item> \ }
3333     <item>}
3334   </nf-chunk|awk|>
3336   <\nf-chunk|test:escapes>
3337     <item>echo escapes test
3339     <item>passtest $FANGLE -Rtest:comment-quote $TXT_SRC &\<gtr\>/dev/null
3340     \|\| ( echo "Comment-quote failed" && exit 1 )
3341   </nf-chunk|sh|>
3343   <chapter|Recognizing Chunks>
3345   Fangle recognizes noweb chunks, but as we also want better <LaTeX>
3346   integration we will recognize any of these:
3348   <\itemize>
3349     <item>notangle chunks matching the pattern
3350     <verbatim|^\<less\>\<less\>.*?\<gtr\>\<gtr\>=>
3352     <item>chunks beginning with <verbatim|\\begin{lstlistings}>, possibly
3353     with <verbatim|\\Chunk{...}> on the previous line
3355     <item>an older form I have used, beginning with
3356     <verbatim|\\begin{Chunk}[options]> --- also more suitable for plain
3357     <LaTeX> users<\footnote>
3358       Is there such a thing as plain <LaTeX>?
3359     </footnote>.
3360   </itemize>
3362   <section|Chunk start>
3364   The variable chunking is used to signify that we are processing a code
3365   chunk and not document. In such a state, input lines will be assigned to
3366   the current chunk; otherwise they are ignored.
3368   <subsection|<TeXmacs>>
3370   We don't handle <TeXmacs> files natively yet, but rather instead emit
3371   unicode character sequences to mark up the text-export file which we do
3372   process.
3374   These hacks detect the unicode character sequences and retro-fit in the old
3375   <TeX> parsing.
3377   We convert <math|\<mapsto\>> into a tab character.
3379   <\nf-chunk|recognize-chunk>
3380     \;
3382     <item>#/\\n/ {
3384     <item># \ gsub("\\n*$","");
3386     <item># \ gsub("\\n", " ");
3388     <item>#}
3390     <item>#===
3392     <item>/\\xE2\\x86\\xA6/ {
3394     <item> \ gsub("\\\\xE2\\\\x86\\\\xA6", "\\x09");
3396     <item>}
3397   </nf-chunk||>
3399   <TeXmacs> back-tick handling is obscure, and a cut-n-paste back-tick from a
3400   shell window comes out as a unicode sequence<\footnote>
3401     that won't export to html, except as a NULL character (literal 0x00)
3402   </footnote> that is fixed-up here.
3404   <\nf-chunk|recognize-chunk>
3405     <item>
3407     <item>/\\xE2\\x80\\x98/ {
3409     <item> \ gsub("\\\\xE2\\\\x80\\\\x98", "`");
3411     <item>}
3412   </nf-chunk||>
3414   In the <TeXmacs> output, the start of a chunk will appear like this:
3416   <verbatim| \ 5b\<less\>example-chunk<key|^K>[1](arg1,<key|^K>
3417   arg2<key|^K><key|^K>), lang=C\<gtr\> <math|\<equiv\>>>
3419   We detect the the start of a <TeXmacs> chunk by detecting the
3420   <math|\<equiv\>> symbol which occurs near the end of the line. We obtain
3421   the chunk name, the chunk parameters, and the chunk language.
3423   <\nf-chunk|recognize-chunk>
3424     <item>
3426     <item>/\\xE2\\x89\\xA1/ {
3428     <item> \ if (match($0, "^ *([^[ ]* \|)\<less\>([^[
3429     ]*)\\\\[[0-9]*\\\\][(](.*)[)].*, lang=([^ ]*)\<gtr\>", line)) {
3431     <item> \ \ \ next_chunk_name=line[2];
3433     <item> \ \ \ get_texmacs_chunk_args(line[3], next_chunk_params);
3435     <item> \ \ \ gsub(ARG_SEPARATOR ",? ?", ";", line[3]);
3437     <item> \ \ \ params = "params=" line[3];
3439     <item> \ \ \ if ((line[4])) {
3441     <item> \ \ \ \ \ params = params ",language=" line[4]
3443     <item> \ \ \ }
3445     <item> \ \ \ get_tex_chunk_args(params, next_chunk_opts);
3447     <item> \ \ \ new_chunk(next_chunk_name, next_chunk_opts,
3448     next_chunk_params);
3450     <item> \ \ \ texmacs_chunking = 1;
3452     <item> \ } else {
3454     <item> \ \ \ # warning(sprintf("Unexpected chunk match: %s\\n", $_))
3456     <item> \ }
3458     <item> \ next;
3460     <item>}
3461   </nf-chunk||>
3463   <subsection|lstlistings>
3465   Our current scheme is to recognize the new lstlisting chunks, but these may
3466   be preceded by a <verbatim|\\Chunk> command which in <LyX> is a more
3467   convenient way to pass the chunk name to the
3468   <verbatim|\\begin{lstlistings}> command, and a more visible way to specify
3469   other <verbatim|lstset> settings.
3471   The arguments to the <verbatim|\\Chunk> command are a name, and then a
3472   comma-seperated list of key-value pairs after the manner of
3473   <verbatim|\\lstset>. (In fact within the <LaTeX> <verbatim|\\Chunk> macro
3474   (section <reference|sub:The-chunk-command>) the text <verbatim|name=> is
3475   prefixed to the argument which is then literally passed to
3476   <verbatim|\\lstset>).
3478   <\nf-chunk|recognize-chunk>
3479     <item>/^\\\\Chunk{/ {
3481     <item> \ if (match($0, "^\\\\\\\\Chunk{ *([^ ,}]*),?(.*)}", line)) {
3483     <item> \ \ \ next_chunk_name = line[1];
3485     <item> \ \ \ get_tex_chunk_args(line[2], next_chunk_opts);
3487     <item> \ }
3489     <item> \ next;
3491     <item>}
3492   </nf-chunk|awk|>
3494   We also make a basic attempt to parse the name out of the
3495   <verbatim|\\lstlistings[name=chunk-name]> text, otherwise we fall back to
3496   the name found in the previous chunk command. This attempt is very basic
3497   and doesn't support commas or spaces or square brackets as part of the
3498   chunkname. We also recognize <verbatim|\\begin{Chunk}> which is convenient
3499   for some users<\footnote>
3500     but not yet supported in the <LaTeX> macros
3501   </footnote>.
3503   <\nf-chunk|recognize-chunk>
3504     <item>/^\\\\begin{lstlisting}\|^\\\\begin{Chunk}/ {
3506     <item> \ if (match($0, "}.*[[,] *name= *{? *([^], }]*)", line)) {
3508     <item> \ \ \ new_chunk(line[1]);
3510     <item> \ } else {
3512     <item> \ \ \ new_chunk(next_chunk_name, next_chunk_opts);
3514     <item> \ }
3516     <item> \ chunking=1;
3518     <item> \ next;
3520     <item>}
3521   </nf-chunk||>
3523   <section|Chunk Body>
3525   <subsection|<TeXmacs>>
3527   A chunk body in <TeXmacs> ends with <verbatim|\|________>... if it is the
3528   final chunklet of a chunk, or if there are further chunklets it ends with
3529   <verbatim|\|\\/\\/\\/>... which is a depiction of a jagged line of torn
3530   paper.
3532   <\nf-chunk|recognize-chunk>
3533     <item>/^ *\\\|____________*/ && texmacs_chunking {
3535     <item> \ active_chunk="";
3537     <item> \ texmacs_chunking=0;
3539     <item> \ chunking=0;
3541     <item>}
3543     <item>/^ *\\\|\\/\\\\/ && texmacs_chunking {
3545     <item> \ texmacs_chunking=0;
3547     <item> \ chunking=0;
3549     <item> \ active_chunk="";
3551     <item>}
3552   </nf-chunk||>
3554   It has been observed that not every line of output when a <TeXmacs> chunk
3555   is active is a line of chunk. This may no longer be true, but we set a
3556   variable <verbatim|texmacs_chunk> if the current line is a chunk line.
3558   Initially we set this to zero...
3560   <\nf-chunk|recognize-chunk>
3561     <item>texmacs_chunk=0;
3562   </nf-chunk||>
3564   ...and then we look to see if the current line is a chunk line.
3566   <TeXmacs> lines look like this: <verbatim| \ 3 \| main() {> so we detect
3567   the lines by leading white space, digits, more whiter space and a vertical
3568   bar followed by at least once space.
3570   If we find such a line, we remove this line-header and set
3571   <verbatim|texmacs_chunk=1> as well as <verbatim|chunking=1>
3573   <\nf-chunk|recognize-chunk>
3574     <item>/^ *[1-9][0-9]* *\\\| / {
3576     <item> \ if (texmacs_chunking) {
3578     <item> \ \ \ chunking=1;
3580     <item> \ \ \ texmacs_chunk=1;
3582     <item> \ \ \ gsub("^ *[1-9][0-9]* *\\\\\| ", "")
3584     <item> \ }
3586     <item>}
3587   </nf-chunk||>
3589   When <TeXmacs> chunking, lines that commence with <verbatim|\\/> or
3590   <verbatim|__> are not chunk content but visual framing, and are skipped.
3592   <\nf-chunk|recognize-chunk>
3593     <item>/^ *\\.\\/\\\\/ && texmacs_chunking {
3595     <item> \ next;
3597     <item>}
3599     <item>/^ *__*$/ && texmacs_chunking {
3601     <item> \ next;
3603     <item>}
3604   </nf-chunk||>
3606   Any other line when <TeXmacs> chunking is considered to be a line-wrapped
3607   line.
3609   <\nf-chunk|recognize-chunk>
3610     <item>texmacs_chunking {
3612     <item> \ if (! texmacs_chunk) {
3614     <item> \ \ \ # must be a texmacs continued line
3616     <item> \ \ \ chunking=1;
3618     <item> \ \ \ texmacs_chunk=1;
3620     <item> \ }
3622     <item>}
3623   </nf-chunk||>
3625   This final chunklet seems bogus and probably stops <LyX> working.
3627   <\nf-chunk|recognize-chunk>
3628     <item>! texmacs_chunk {
3630     <item># \ texmacs_chunking=0;
3632     <item> \ chunking=0;
3634     <item>}
3635   </nf-chunk||>
3637   <subsection|Noweb>
3639   We recognize notangle style chunks too:
3641   <\nf-chunk|recognize-chunk>
3642     <item>/^[\<less\>]\<less\>.*[\<gtr\>]\<gtr\>=/ {
3644     <item> \ if (match($0, "^[\<less\>]\<less\>(.*)[\<gtr\>]\<gtr\>= *$",
3645     line)) {
3647     <item> \ \ \ chunking=1;
3649     <item> \ \ \ notangle_mode=1;
3651     <item> \ \ \ new_chunk(line[1]);
3653     <item> \ \ \ next;
3655     <item> \ }
3657     <item>}
3658   </nf-chunk|awk|>
3660   <section|Chunk end>
3662   Likewise, we need to recognize when a chunk ends.
3664   <subsection|lstlistings>
3666   The <verbatim|e> in <verbatim|[e]nd{lislisting}> is surrounded by square
3667   brackets so that when this document is processed, this chunk doesn't
3668   terminate early when the lstlistings package recognizes it's own
3669   end-string!<\footnote>
3670     This doesn't make sense as the regex is anchored with ^, which this line
3671     does not begin with!
3672   </footnote>
3674   <\nf-chunk|recognize-chunk>
3675     <item>/^\\\\[e]nd{lstlisting}\|^\\\\[e]nd{Chunk}/ {
3677     <item> \ chunking=0;
3679     <item> \ active_chunk="";
3681     <item> \ next;
3683     <item>}
3684   </nf-chunk||>
3686   <subsection|noweb>
3688   <\nf-chunk|recognize-chunk>
3689     <item>/^@ *$/ {
3691     <item> \ chunking=0;
3693     <item> \ active_chunk="";
3695     <item>}
3696   </nf-chunk||>
3698   All other recognizers are only of effect if we are chunking; there's no
3699   point in looking at lines if they aren't part of a chunk, so we just ignore
3700   them as efficiently as we can.
3702   <\nf-chunk|recognize-chunk>
3703     <item>! chunking { next; }
3704   </nf-chunk||>
3706   <section|Chunk contents>
3708   Chunk contents are any lines read while <verbatim|chunking> is true. Some
3709   chunk contents are special in that they refer to other chunks, and will be
3710   replaced by the contents of these chunks when the file is generated.
3712   <label|sub:ORS-chunk-text>We add the output record separator <verbatim|ORS>
3713   to the line now, because we will set <verbatim|ORS> to the empty string
3714   when we generate the output<\footnote>
3715     So that we can partial print lines using <verbatim|print> instead of
3716     <verbatim|printf>. <todo|This does't make sense>
3717   </footnote>.
3719   <\nf-chunk|recognize-chunk>
3720     <item>length(active_chunk) {
3722     <item> \ <nf-ref|process-chunk-tabs|>
3724     <item> \ <nf-ref|process-chunk|>
3726     <item>}
3727   </nf-chunk||>
3729   If a chunk just consisted of plain text, we could handle the chunk like
3730   this:
3732   <\nf-chunk|process-chunk-simple>
3733     <item>chunk_line(active_chunk, $0 ORS);
3734   </nf-chunk||>
3736   but in fact a chunk can include references to other chunks. Chunk includes
3737   are traditionally written as <verbatim|\<less\>\<less\>chunk-name\<gtr\>\<gtr\>>
3738   but we support other variations, some of which are more suitable for
3739   particular editing systems.
3741   However, we also process tabs at this point. A tab at input can be replaced
3742   by a number of spaces defined by the <verbatim|tabs> variable, set by the
3743   <verbatim|-T> option. Of course this is poor tab behaviour, we should
3744   probably have the option to use proper counted tab-stops and process this
3745   on output.
3747   <\nf-chunk|process-chunk-tabs>
3748     <item>if (length(tabs)) {
3750     <item> \ gsub("\\t", tabs);
3752     <item>}
3753   </nf-chunk||>
3755   <subsection|lstlistings><label|sub:lst-listings-includes>
3757   If <verbatim|\\lstset{escapeinside={=\<less\>}{\<gtr\>}}> is set, then we
3758   can use <verbatim|<nf-ref|chunk-name|>> in listings. The sequence
3759   <verbatim|=\<less\>> was chosen because:
3761   <\enumerate>
3762     <item>it is a better mnemonic than <verbatim|\<less\>\<less\>chunk-name\<gtr\>\<gtr\>>
3763     in that the <verbatim|=> sign signifies equivalence or substitutability.
3765     <item>and because <verbatim|=\<less\>> is not valid in C or any language
3766     I can think of.
3768     <item>and also because lstlistings doesn't like <verbatim|\<gtr\>\<gtr\>>
3769     as an end delimiter for the <em|texcl> escape, so we must make do with a
3770     single <verbatim|\<gtr\>> which is better complemented by
3771     <verbatim|=\<less\>> than by <verbatim|\<less\>\<less\>>.
3772   </enumerate>
3774   Unfortunately the <verbatim|=\<less\>...\<gtr\>> that we use re-enters a
3775   <LaTeX> parsing mode in which some characters are special, e.g. <verbatim|#
3776   \\> and so these cause trouble if used in arguments to
3777   <verbatim|\\chunkref>. At some point I must fix the <LaTeX> command
3778   <verbatim|\\chunkref> so that it can accept these literally, but until
3779   then, when writing chunkref argumemts that need these characters, I must
3780   use the forms <verbatim|\\textbackslash{}> and <verbatim|\\#>; so I also
3781   define a hacky chunk <verbatim|delatex> to be used further on whose purpose
3782   it is to remove these from any arguments parsed by fangle.
3784   <\nf-chunk|delatex>
3785     <item># FILTHY HACK
3787     <item>gsub("\\\\\\\\#", "#", ${text});
3789     <item>gsub("\\\\\\\\textbackslash{}", "\\\\", ${text});
3791     <item>gsub("\\\\\\\\\\\\^", "^", ${text});
3792   </nf-chunk||<tuple|text>>
3794   As each chunk line may contain more than one chunk include, we will split
3795   out chunk includes in an iterative fashion<\footnote>
3796     Contrary to our use of split when substituting parameters in chapter
3797     <reference|Here-we-split>
3798   </footnote>.
3800   First, as long as the chunk contains a <verbatim|\\chunkref> command we
3801   take as much as we can up to the first <verbatim|\\chunkref> command.
3803   <TeXmacs> text output uses <math|\<langle\>>...<math|\<rangle\>> which
3804   comes out as unicode sequences <verbatim|0xC2> <verbatim|0xAB> ...
3805   <verbatim|0xC2> <verbatim|0xBB>. Modern awk will interpret
3806   <verbatim|[^\\xC2\\xBB]> as a single unicode character if <verbatim|LANG>
3807   is set correctly to the sub-type <verbatim|UTF-8>, e.g.
3808   <verbatim|LANG=en_GB.UTF-8>, otherwise <verbatim|[^\\xC2\\xBB]> will be
3809   treated as a two character negated match <emdash> but this should not
3810   interfere with the function.
3812   <\nf-chunk|process-chunk>
3813     <item>chunk = $0;
3815     <item>indent = 0;
3817     <item>while(match(chunk,"(\\xC2\\xAB)([^\\xC2\\xBB]*)
3818     [^\\xC2\\xBB]*\\xC2\\xBB", line) \|\|
3820     <item> \ \ \ \ \ match(chunk,\ 
3822     <item> \ \ \ \ \ \ \ \ \ \ \ "([=]\<less\>\\\\\\\\chunkref{([^}\<gtr\>]*)}(\\\\(.*\\\\)\|)\<gtr\>\|\<less\>\<less\>([a-zA-Z_][-a-zA-Z0-9_]*)\<gtr\>\<gtr\>)",\ 
3824     <item> \ \ \ \ \ \ \ \ \ \ \ line)\\
3826     <item>) {
3828     <item> \ chunklet = substr(chunk, 1, RSTART - 1);
3829   </nf-chunk||>
3831   We keep track of the indent count, by counting the number of literal
3832   characters found. We can then preserve this indent on each output line when
3833   multi-line chunks are expanded.
3835   We then process this first part literal text, and set the chunk which is
3836   still to be processed to be the text after the <verbatim|\\chunkref>
3837   command, which we will process next as we continue around the loop.
3839   <\nf-chunk|process-chunk>
3840     <item> \ indent += length(chunklet);
3842     <item> \ chunk_line(active_chunk, chunklet);
3844     <item> \ chunk = substr(chunk, RSTART + RLENGTH);
3845   </nf-chunk||>
3847   We then consider the type of chunk command we have found, whether it is the
3848   fangle style command beginning with <verbatim|=\<less\>> the older notangle
3849   style beginning with <verbatim|\<less\>\<less\>>.
3851   Fangle chunks may have parameters contained within square brackets. These
3852   will be matched in <verbatim|line[3]> and are considered at this stage of
3853   processing to be part of the name of the chunk to be included.
3855   <\nf-chunk|process-chunk>
3856     <item> \ if (substr(line[1], 1, 1) == "=") {
3858     <item> \ \ \ # chunk name up to }
3860     <item> \ \ \ \ \ \ \ <nf-ref|delatex|<tuple|line[3]>>
3862     <item> \ \ \ chunk_include(active_chunk, line[2] line[3], indent);
3864     <item> \ } else if (substr(line[1], 1, 1) == "\<less\>") {
3866     <item> \ \ \ chunk_include(active_chunk, line[4], indent);
3868     <item> \ } else if (line[1] == "\\xC2\\xAB") {
3870     <item> \ \ \ chunk_include(active_chunk, line[2], indent);
3872     <item> \ } else {
3874     <item> \ \ \ error("Unknown chunk fragment: " line[1]);
3876     <item> \ }
3877   <|nf-chunk>
3878     \;
3879   </nf-chunk|>
3881   The loop will continue until there are no more chunkref statements in the
3882   text, at which point we process the final part of the chunk.
3884   <\nf-chunk|process-chunk>
3885     <item>}
3887     <item>chunk_line(active_chunk, chunk);
3888   </nf-chunk||>
3890   <label|lone-newline>We add the newline character as a chunklet on it's own,
3891   to make it easier to detect new lines and thus manage indentation when
3892   processing the output.
3894   <\nf-chunk|process-chunk>
3895     <item>chunk_line(active_chunk, "\\n");
3896   <|nf-chunk>
3897     \;
3898   </nf-chunk|>
3900   We will also permit a chunk-part number to follow in square brackets, so
3901   that <verbatim|<nf-ref|chunk-name[1]|>> will refer to the first part only.
3902   This can make it easy to include a C function prototype in a header file,
3903   if the first part of the chunk is just the function prototype without the
3904   trailing semi-colon. The header file would include the prototype with the
3905   trailing semi-colon, like this:
3907   <verbatim|<nf-ref|chunk-name[1]|>>
3909   This is handled in section <reference|sub:Chunk-parts>
3911   We should perhaps introduce a notion of language specific chunk options; so
3912   that perhaps we could specify:
3914   <verbatim|=\<less\>\\chunkref{chunk-name[function-declaration]}>
3916   which applies a transform <verbatim|function-declaration> to the chunk ---
3917   which in this case would extract a function prototype from a function.
3918   <todo|Do it>
3920   <chapter|Processing Options>
3922   At the start, first we set the default options.
3924   <\nf-chunk|default-options>
3925     <item>debug=0;
3927     <item>linenos=0;
3929     <item>notangle_mode=0;
3931     <item>root="*";
3933     <item>tabs = "";
3934   </nf-chunk||>
3936   Then we use getopt the standard way, and null out ARGV afterwards in the
3937   normal AWK fashion.
3939   <\nf-chunk|read-options>
3940     <item>Optind = 1 \ \ \ # skip ARGV[0]
3942     <item>while(getopt(ARGC, ARGV, "R:LdT:hr")!=-1) {
3944     <item> \ <nf-ref|handle-options|>
3946     <item>}
3948     <item>for (i=1; i\<less\>Optind; i++) { ARGV[i]=""; }
3949   </nf-chunk||>
3951   This is how we handle our options:
3953   <\nf-chunk|handle-options>
3954     <item>if (Optopt == "R") root = Optarg;
3956     <item>else if (Optopt == "r") root="";
3958     <item>else if (Optopt == "L") linenos = 1;
3960     <item>else if (Optopt == "d") debug = 1;
3962     <item>else if (Optopt == "T") tabs = indent_string(Optarg+0);
3964     <item>else if (Optopt == "h") help();
3966     <item>else if (Optopt == "?") help();
3967   </nf-chunk||>
3969   We do all of this at the beginning of the program
3971   <\nf-chunk|begin>
3972     <item>BEGIN {
3974     <item> \ <nf-ref|constants|>
3976     <item> \ <nf-ref|mode-definitions|>
3978     <item> \ <nf-ref|default-options|>
3980     <item>
3982     <item> \ <nf-ref|read-options|>
3984     <item>}
3985   </nf-chunk||>
3987   And have a simple help function
3989   <\nf-chunk|help()>
3990     <item>function help() {
3992     <item> \ print "Usage:"
3994     <item> \ print " \ fangle [-L] -R\<less\>rootname\<gtr\> [source.tex
3995     ...]"
3997     <item> \ print " \ fangle -r [source.tex ...]"
3999     <item> \ print " \ If the filename, source.tex is not specified then
4000     stdin is used"
4002     <item> \ print
4004     <item> \ print "-L causes the C statement: #line \<less\>lineno\<gtr\>
4005     \\"filename\\"" to be issued"
4007     <item> \ print "-R causes the named root to be written to stdout"
4009     <item> \ print "-r lists all roots in the file (even those used
4010     elsewhere)"
4012     <item> \ exit 1;
4014     <item>}
4015   </nf-chunk||>
4017   <chapter|Generating the Output>
4019   We generate output by calling output_chunk, or listing the chunk names.
4021   <\nf-chunk|generate-output>
4022     <item>if (length(root)) output_chunk(root);
4024     <item>else output_chunk_names();
4025   </nf-chunk||>
4027   We also have some other output debugging:
4029   <\nf-chunk|debug-output>
4030     <item>if (debug) {
4032     <item> \ print "------ chunk names "
4034     <item> \ output_chunk_names();
4036     <item> \ print "====== chunks"
4038     <item> \ output_chunks();
4040     <item> \ print "++++++ debug"
4042     <item> \ for (a in chunks) {
4044     <item> \ \ \ print a "=" chunks[a];
4046     <item> \ }
4048     <item>}
4049   </nf-chunk||>
4051   We do both of these at the end. We also set <verbatim|ORS=""> because each
4052   chunklet is not necessarily a complete line, and we already added
4053   <verbatim|ORS> to each input line in section
4054   <reference|sub:ORS-chunk-text>.
4056   <\nf-chunk|end>
4057     <item>END {
4059     <item> \ <nf-ref|debug-output|>
4061     <item> \ ORS="";
4063     <item> \ <nf-ref|generate-output|>
4065     <item>}
4066   </nf-chunk||>
4068   We write chunk names like this. If we seem to be running in notangle
4069   compatibility mode, then we enclose the name like this
4070   <verbatim|\<less\>\<less\>name\<gtr\>\<gtr\>> the same way notangle does:
4072   <\nf-chunk|output_chunk_names()>
4073     <item>function output_chunk_names( \ \ c, prefix, suffix)\ 
4075     <item>{
4077     <item> \ if (notangle_mode) {
4079     <item> \ \ \ prefix="\<less\>\<less\>";
4081     <item> \ \ \ suffix="\<gtr\>\<gtr\>";
4083     <item> \ }
4085     <item> \ for (c in chunk_names) {
4087     <item> \ \ \ print prefix c suffix "\\n";
4089     <item> \ }
4091     <item>}
4092   </nf-chunk||>
4094   This function would write out all chunks
4096   <\nf-chunk|output_chunks()>
4097     <item>function output_chunks( \ a)\ 
4099     <item>{
4101     <item> \ for (a in chunk_names) {
4103     <item> \ \ \ output_chunk(a);
4105     <item> \ }
4107     <item>}
4109     <item>
4111     <item>function output_chunk(chunk) {
4113     <item> \ newline = 1;
4115     <item> \ lineno_needed = linenos;
4117     <item>
4119     <item> \ write_chunk(chunk);
4121     <item>}
4123     <item>
4124   </nf-chunk||>
4126   <section|Assembling the Chunks>
4128   <verbatim|chunk_path> holds a string consisting of the names of all the
4129   chunks that resulted in this chunk being output. It should probably also
4130   contain the source line numbers at which each inclusion also occured.
4132   We first initialize the mode tracker for this chunk.
4134   <\nf-chunk|write_chunk()>
4135     <item>function write_chunk(chunk_name) {
4137     <item> \ <nf-ref|awk-delete-array|<tuple|context>>
4139     <item> \ return write_chunk_r(chunk_name, context);
4141     <item>}
4143     <item>
4145     <item>function write_chunk_r(chunk_name, context, indent, tail,
4147     <item> \ # optional vars
4149     <item> \ <with|font-shape|italic|chunk_path>, chunk_args,\ 
4151     <item> \ # local vars
4153     <item> \ context_origin,
4155     <item> \ chunk_params, part, max_part, part_line, frag, max_frag, text,\ 
4157     <item> \ chunklet, only_part, call_chunk_args, new_context)
4159     <item>{
4161     <item> \ if (debug) debug_log("write_chunk_r(" chunk_name ")");
4162   </nf-chunk|awk|>
4164   <subsection|Chunk Parts><label|sub:Chunk-parts>
4166   As mentioned in section <reference|sub:lstlistings-includes>, a chunk name
4167   may contain a part specifier in square brackets, limiting the parts that
4168   should be emitted.
4170   <\nf-chunk|write_chunk()>
4171     <item> \ if (match(chunk_name, "^(.*)\\\\[([0-9]*)\\\\]$",
4172     chunk_name_parts)) {
4174     <item> \ \ \ chunk_name = chunk_name_parts[1];
4176     <item> \ \ \ only_part = chunk_name_parts[2];
4178     <item> \ }
4179   </nf-chunk||>
4181   We then create a mode tracker
4183   <\nf-chunk|write_chunk()>
4184     <item> \ context_origin = context[""];
4186     <item> \ new_context = push_mode_tracker(context, chunks[chunk_name,
4187     "language"], "");
4188   </nf-chunk||>
4190   We extract into <verbatim|chunk_params> the names of the parameters that
4191   this chunk accepts, whose values were (optionally) passed in
4192   <verbatim|chunk_args>.
4194   <\nf-chunk|write_chunk()>
4195     <item> \ split(chunks[chunk_name, "params"], chunk_params, " *; *");
4196   </nf-chunk||>
4198   To assemble a chunk, we write out each part.
4200   <\nf-chunk|write_chunk()>
4201     <item> \ if (! (chunk_name in chunk_names)) {
4203     <item> \ \ \ error(sprintf(_"The root module
4204     \<less\>\<less\>%s\<gtr\>\<gtr\> was not defined.\\nUsed by: %s",\\
4206     <item> \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ chunk_name, chunk_path));
4208     <item> \ }
4210     <item>
4212     <item> \ max_part = chunks[chunk_name, "part"];
4214     <item> \ for(part = 1; part \<less\>= max_part; part++) {
4216     <item> \ \ \ if (! only_part \|\| part == only_part) {
4218     <item> \ \ \ \ \ <nf-ref|write-part|>
4220     <item> \ \ \ }
4222     <item> \ }
4224     <item> \ if (! pop_mode_tracker(context, context_origin)) {
4226     <item> \ \ \ dump_mode_tracker(context);
4228     <item> \ \ \ error(sprintf(_"Module %s did not close context
4229     properly.\\nUsed by: %s\\n", chunk_name, chunk_path));
4231     <item> \ }
4233     <item>}
4234   </nf-chunk||>
4236   A part can either be a chunklet of lines, or an include of another chunk.
4238   Chunks may also have parameters, specified in LaTeX style with braces after
4239   the chunk name --- looking like this in the document: chunkname{param1,
4240   param2}. Arguments are passed in square brackets:
4241   <verbatim|\\chunkref{chunkname}[arg1, arg2]>.
4243   Before we process each part, we check that the source position hasn't
4244   changed unexpectedly, so that we can know if we need to output a new
4245   file-line directive.
4247   <\nf-chunk|write-part>
4248     <item><nf-ref|check-source-jump|>
4250     <item>
4252     <item>chunklet = chunks[chunk_name, "part", part];
4254     <item>if (chunks[chunk_name, "part", part, "type"] == part_type_chunk) {
4256     <item> \ <nf-ref|write-included-chunk|>
4258     <item>} else if (chunklet SUBSEP "line" in chunks) {
4260     <item> \ <nf-ref|write-chunklets|>
4262     <item>} else {
4264     <item> \ # empty last chunklet
4266     <item>}
4267   </nf-chunk||>
4269   To write an included chunk, we must detect any optional chunk arguments in
4270   parenthesis. Then we recurse calling <verbatim|write_chunk()>.
4272   <\nf-chunk|write-included-chunk>
4273     <item>if (match(chunklet, "^([^\\\\[\\\\(]*)\\\\((.*)\\\\)$",
4274     chunklet_parts)) {
4276     <item> \ chunklet = chunklet_parts[1];
4278     <item># hack
4280     <item>gsub(sprintf("%c",11), "", chunklet);
4282     <item>gsub(sprintf("%c",11), "", chunklet_parts[2]);
4284     <item> \ parse_chunk_args("c-like", chunklet_parts[2], call_chunk_args,
4285     "(");
4287     <item> \ for (c in call_chunk_args) {
4289     <item> \ \ \ call_chunk_args[c] = expand_chunk_args(call_chunk_args[c],
4290     chunk_params, chunk_args);
4292     <item> \ }
4294     <item>} else {
4296     <item> \ split("", call_chunk_args);
4298     <item>}
4300     <item>
4302     <item>write_chunk_r(chunklet, context,
4304     <item> \ \ \ \ \ \ \ \ \ \ \ chunks[chunk_name, "part", part, "indent"]
4305     indent,
4307     <item> \ \ \ \ \ \ \ \ \ \ \ chunks[chunk_name, "part", part, "tail"],
4309     <item> \ \ \ \ \ \ \ \ \ \ \ chunk_path "\\n \ \ \ \ \ \ \ \ "
4310     chunk_name,
4312     <item> \ \ \ \ \ \ \ \ \ \ \ call_chunk_args);
4313   </nf-chunk||>
4315   Before we output a chunklet of lines, we first emit the file and line
4316   number if we have one, and if it is safe to do so.
4318   Chunklets are generally broken up by includes, so the start of a chunklet
4319   is a good place to do this. Then we output each line of the chunklet.
4321   When it is not safe, such as in the middle of a multi-line macro
4322   definition, <verbatim|lineno_suppressed> is set to true, and in such a case
4323   we note that we want to emit the line statement when it is next safe.
4325   <\nf-chunk|write-chunklets>
4326     <item>max_frag = chunks[chunklet, "line"];
4328     <item>for(frag = 1; frag \<less\>= max_frag; frag++) {
4330     <item> \ <nf-ref|write-file-line|>
4331   </nf-chunk||>
4333   We then extract the chunklet text and expand any arguments.
4335   <\nf-chunk|write-chunklets>
4336     <item>
4338     <item> \ text = chunks[chunklet, frag];
4340     <item>\ 
4342     <item> \ /* check params */
4344     <item> \ text = expand_chunk_args(text, chunk_params, chunk_args);
4345   </nf-chunk||>
4347   If the text is a single newline (which we keep separate - see
4348   <reference|lone-newline>) then we increment the line number. In the case
4349   where this is the last line of a chunk and it is not a top-level chunk we
4350   replace the newline with an empty string --- because the chunk that
4351   included this chunk will have the newline at the end of the line that
4352   included this chunk.
4354   We also note by <verbatim|newline = 1> that we have started a new line, so
4355   that indentation can be managed with the following piece of text.
4357   <\nf-chunk|write-chunklets>
4358     <item>
4360     <item> if (text == "\\n") {
4362     <item> \ \ \ lineno++;
4364     <item> \ \ \ if (part == max_part && frag == max_frag &&
4365     length(chunk_path)) {
4367     <item> \ \ \ \ \ text = "";
4369     <item> \ \ \ \ \ break;
4371     <item> \ \ \ } else {
4373     <item> \ \ \ \ \ newline = 1;
4375     <item> \ \ \ }
4376   </nf-chunk||>
4378   If this text does not represent a newline, but we see that we are the first
4379   piece of text on a newline, then we prefix our text with the current
4380   indent.\ 
4382   <\note>
4383     <verbatim|newline> is a global output-state variable, but the
4384     <verbatim|indent> is not.
4385   </note>
4387   <\nf-chunk|write-chunklets>
4388     <item> \ } else if (length(text) \|\| length(tail)) {
4390     <item> \ \ \ if (newline) text = indent text;
4392     <item> \ \ \ newline = 0;
4394     <item> \ }
4396     <item>
4397   </nf-chunk||>
4399   Tail will soon no longer be relevant once mode-detection is in place.
4401   <\nf-chunk|write-chunklets>
4402     <item> \ text = text tail;
4404     <item> \ mode_tracker(context, text);
4406     <item> \ print untab(transform_escape(context, text, new_context));
4407   </nf-chunk||>
4409   If a line ends in a backslash --- suggesting continuation --- then we
4410   supress outputting file-line as it would probably break the continued
4411   lines.
4413   <\nf-chunk|write-chunklets>
4414     <item> \ if (linenos) {
4416     <item> \ \ \ lineno_suppressed = substr(lastline, length(lastline)) ==
4417     "\\\\";
4419     <item> \ }
4421     <item>}
4422   </nf-chunk||>
4424   Of course there is no point in actually outputting the source filename and
4425   line number (file-line) if they don't say anything new! We only need to
4426   emit them if they aren't what is expected, or if we we not able to emit one
4427   when they had changed.
4429   <\nf-chunk|write-file-line>
4430     <item>if (newline && lineno_needed && ! lineno_suppressed) {
4432     <item> \ filename = a_filename;
4434     <item> \ lineno = a_lineno;
4436     <item> \ print "#line " lineno " \\"" filename "\\"\\n"
4438     <item> \ lineno_needed = 0;
4440     <item>}
4441   </nf-chunk||>
4443   We check if a new file-line is needed by checking if the source line
4444   matches what we (or a compiler) would expect.
4446   <\nf-chunk|check-source-jump>
4447     <item>if (linenos && (chunk_name SUBSEP "part" SUBSEP part SUBSEP
4448     "FILENAME" in chunks)) {
4450     <item> \ a_filename = chunks[chunk_name, "part", part, "FILENAME"];
4452     <item> \ a_lineno = chunks[chunk_name, "part", part, "LINENO"];
4454     <item> \ if (a_filename != filename \|\| a_lineno != lineno) {
4456     <item> \ \ \ lineno_needed++;
4458     <item> \ }
4460     <item>}
4461   </nf-chunk||>
4463   <chapter|Storing Chunks>
4465   Awk has pretty limited data structures, so we will use two main hashes.
4466   Uninterrupted sequences of a chunk will be stored in chunklets and the
4467   chunklets used in a chunk will be stored in <verbatim|chunks>.
4469   <\nf-chunk|constants>
4470     <item>part_type_chunk=1;
4472     <item>SUBSEP=",";
4473   </nf-chunk||>
4475   The params mentioned are not chunk parameters for parameterized chunks, as
4476   mentioned in <reference|Chunk Arguments>, but the lstlistings style
4477   parameters used in the <verbatim|\\Chunk> command<\footnote>
4478     The <verbatim|params> parameter is used to hold the parameters for
4479     parameterized chunks
4480   </footnote>.
4482   <\nf-chunk|chunk-storage-functions>
4483     <item>function new_chunk(chunk_name, opts, args,
4485     <item> \ # local vars
4487     <item> \ p, append )
4489     <item>{
4491     <item> \ # HACK WHILE WE CHANGE TO ( ) for PARAM CHUNKS
4493     <item> \ gsub("\\\\(\\\\)$", "", chunk_name);
4495     <item> \ if (! (chunk_name in chunk_names)) {
4497     <item> \ \ \ if (debug) print "New chunk " chunk_name;
4499     <item> \ \ \ chunk_names[chunk_name];
4501     <item> \ \ \ for (p in opts) {
4503     <item> \ \ \ \ \ chunks[chunk_name, p] = opts[p];
4505     <item> \ \ \ \ \ if (debug) print "chunks[" chunk_name "," p "] = "
4506     opts[p];
4508     <item> \ \ \ }
4510     <item> \ \ \ for (p in args) {
4512     <item> \ \ \ \ \ chunks[chunk_name, "params", p] = args[p];
4514     <item> \ \ \ }
4516     <item> \ \ \ if ("append" in opts) {
4518     <item> \ \ \ \ \ append=opts["append"];
4520     <item> \ \ \ \ \ if (! (append in chunk_names)) {
4522     <item> \ \ \ \ \ \ \ warning("Chunk " chunk_name " is appended to chunk "
4523     append " which is not defined yet");
4525     <item> \ \ \ \ \ \ \ new_chunk(append);
4527     <item> \ \ \ \ \ }
4529     <item> \ \ \ \ \ chunk_include(append, chunk_name);
4531     <item> \ \ \ \ \ chunk_line(append, ORS);
4533     <item> \ \ \ }
4535     <item> \ }
4537     <item> \ active_chunk = chunk_name;
4539     <item> \ prime_chunk(chunk_name);
4541     <item>}
4542   </nf-chunk||>
4544   <\nf-chunk|chunk-storage-functions>
4545     <item>
4547     <item>function prime_chunk(chunk_name)
4549     <item>{
4551     <item> \ chunks[chunk_name, "part", ++chunks[chunk_name, "part"] ] = \\
4553     <item> \ \ \ \ \ \ \ \ chunk_name SUBSEP "chunklet" SUBSEP ""
4554     ++chunks[chunk_name, "chunklet"];
4556     <item> \ chunks[chunk_name, "part", chunks[chunk_name, "part"],
4557     "FILENAME"] = FILENAME;
4559     <item> \ chunks[chunk_name, "part", chunks[chunk_name, "part"], "LINENO"]
4560     = FNR + 1;
4562     <item>}
4564     <item>
4566     <item>function chunk_line(chunk_name, line){
4568     <item> \ chunks[chunk_name, "chunklet", chunks[chunk_name, "chunklet"],
4570     <item> \ \ \ \ \ \ \ \ ++chunks[chunk_name, "chunklet",
4571     chunks[chunk_name, "chunklet"], "line"] \ ] = line;
4573     <item>}
4575     <item>
4576   </nf-chunk||>
4578   Chunk include represents a <em|chunkref> statement, and stores the
4579   requirement to include another chunk. The parameter indent represents the
4580   quanity of literal text characters that preceded this <em|chunkref>
4581   statement and therefore by how much additional lines of the included chunk
4582   should be indented.
4584   <\nf-chunk|chunk-storage-functions>
4585     <item>function chunk_include(chunk_name, chunk_ref, indent, tail)
4587     <item>{
4589     <item> \ chunks[chunk_name, "part", ++chunks[chunk_name, "part"] ] =
4590     chunk_ref;
4592     <item> \ chunks[chunk_name, "part", chunks[chunk_name, "part"], "type" ]
4593     = part_type_chunk;
4595     <item> \ chunks[chunk_name, "part", chunks[chunk_name, "part"], "indent"
4596     ] = indent_string(indent);
4598     <item> \ chunks[chunk_name, "part", chunks[chunk_name, "part"], "tail" ]
4599     = tail;
4601     <item> \ prime_chunk(chunk_name);
4603     <item>}
4605     <item>
4606   </nf-chunk||>
4608   The indent is calculated by indent_string, which may in future convert some
4609   spaces into tab characters. This function works by generating a printf
4610   padded format string, like <verbatim|%22s> for an indent of 22, and then
4611   printing an empty string using that format.
4613   <\nf-chunk|chunk-storage-functions>
4614     <item>function indent_string(indent) {
4616     <item> \ return sprintf("%" indent "s", "");
4618     <item>}
4619   </nf-chunk||>
4621   <chapter|getopt><label|cha:getopt>
4623   I use Arnold Robbins public domain getopt (1993 revision). This is probably
4624   the same one that is covered in chapter 12 of “Edition 3 of GAWK:
4625   Effective AWK Programming: A User's Guide for GNU Awk” but as that is
4626   licensed under the GNU Free Documentation License, Version 1.3, which
4627   conflicts with the GPL3, I can't use it from there (or it's accompanying
4628   explanations), so I do my best to explain how it works here.
4630   The getopt.awk header is:
4632   <\nf-chunk|getopt.awk-header>
4633     <item># getopt.awk --- do C library getopt(3) function in awk
4635     <item>#
4637     <item># Arnold Robbins, arnold@skeeve.com, Public Domain
4639     <item>#
4641     <item># Initial version: March, 1991
4643     <item># Revised: May, 1993
4645     <item>
4646   </nf-chunk||>
4648   The provided explanation is:
4650   <\nf-chunk|getopt.awk-notes>
4651     <item># External variables:
4653     <item># \ \ \ Optind -- index in ARGV of first nonoption argument
4655     <item># \ \ \ Optarg -- string value of argument to current option
4657     <item># \ \ \ Opterr -- if nonzero, print our own diagnostic
4659     <item># \ \ \ Optopt -- current option letter
4661     <item>
4663     <item># Returns:
4665     <item># \ \ \ -1 \ \ \ \ at end of options
4667     <item># \ \ \ ? \ \ \ \ \ for unrecognized option
4669     <item># \ \ \ \<less\>c\<gtr\> \ \ \ a character representing the current
4670     option
4672     <item>
4674     <item># Private Data:
4676     <item># \ \ \ _opti \ -- index in multi-flag option, e.g., -abc
4678     <item>
4679   </nf-chunk||>
4681   The function follows. The final two parameters, <verbatim|thisopt> and
4682   <verbatim|i> are local variables and not parameters --- as indicated by the
4683   multiple spaces preceding them. Awk doesn't care, the multiple spaces are a
4684   convention to help us humans.
4686   <\nf-chunk|getopt.awk-getopt()>
4687     <item>function getopt(argc, argv, options, \ \ \ thisopt, i)
4689     <item>{
4691     <item> \ \ \ if (length(options) == 0) \ \ \ # no options given
4693     <item> \ \ \ \ \ \ \ return -1
4695     <item> \ \ \ if (argv[Optind] == "--") { \ # all done
4697     <item> \ \ \ \ \ \ \ Optind++
4699     <item> \ \ \ \ \ \ \ _opti = 0
4701     <item> \ \ \ \ \ \ \ return -1
4703     <item> \ \ \ } else if (argv[Optind] !~ /^-[^: \\t\\n\\f\\r\\v\\b]/) {
4705     <item> \ \ \ \ \ \ \ _opti = 0
4707     <item> \ \ \ \ \ \ \ return -1
4709     <item> \ \ \ }
4711     <item> \ \ \ if (_opti == 0)
4713     <item> \ \ \ \ \ \ \ _opti = 2
4715     <item> \ \ \ thisopt = substr(argv[Optind], _opti, 1)
4717     <item> \ \ \ Optopt = thisopt
4719     <item> \ \ \ i = index(options, thisopt)
4721     <item> \ \ \ if (i == 0) {
4723     <item> \ \ \ \ \ \ \ if (Opterr)
4725     <item> \ \ \ \ \ \ \ \ \ \ \ printf("%c -- invalid option\\n",
4727     <item> \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ thisopt)
4728     \<gtr\> "/dev/stderr"
4730     <item> \ \ \ \ \ \ \ if (_opti \<gtr\>= length(argv[Optind])) {
4732     <item> \ \ \ \ \ \ \ \ \ \ \ Optind++
4734     <item> \ \ \ \ \ \ \ \ \ \ \ _opti = 0
4736     <item> \ \ \ \ \ \ \ } else
4738     <item> \ \ \ \ \ \ \ \ \ \ \ _opti++
4740     <item> \ \ \ \ \ \ \ return "?"
4742     <item> \ \ \ }
4743   </nf-chunk||>
4745   At this point, the option has been found and we need to know if it takes
4746   any arguments.
4748   <\nf-chunk|getopt.awk-getopt()>
4749     <item> \ \ \ if (substr(options, i + 1, 1) == ":") {
4751     <item> \ \ \ \ \ \ \ # get option argument
4753     <item> \ \ \ \ \ \ \ if (length(substr(argv[Optind], _opti + 1)) \<gtr\>
4754     0)
4756     <item> \ \ \ \ \ \ \ \ \ \ \ Optarg = substr(argv[Optind], _opti + 1)
4758     <item> \ \ \ \ \ \ \ else
4760     <item> \ \ \ \ \ \ \ \ \ \ \ Optarg = argv[++Optind]
4762     <item> \ \ \ \ \ \ \ _opti = 0
4764     <item> \ \ \ } else
4766     <item> \ \ \ \ \ \ \ Optarg = ""
4768     <item> \ \ \ if (_opti == 0 \|\| _opti \<gtr\>= length(argv[Optind])) {
4770     <item> \ \ \ \ \ \ \ Optind++
4772     <item> \ \ \ \ \ \ \ _opti = 0
4774     <item> \ \ \ } else
4776     <item> \ \ \ \ \ \ \ _opti++
4778     <item> \ \ \ return thisopt
4780     <item>}
4781   </nf-chunk||>
4783   A test program is built in, too
4785   <\nf-chunk|getopt.awk-begin>
4786     <item>BEGIN {
4788     <item> \ \ \ Opterr = 1 \ \ \ # default is to diagnose
4790     <item> \ \ \ Optind = 1 \ \ \ # skip ARGV[0]
4792     <item> \ \ \ # test program
4794     <item> \ \ \ if (_getopt_test) {
4796     <item> \ \ \ \ \ \ \ while ((_go_c = getopt(ARGC, ARGV, "ab:cd")) != -1)
4798     <item> \ \ \ \ \ \ \ \ \ \ \ printf("c = \<less\>%c\<gtr\>, optarg =
4799     \<less\>%s\<gtr\>\\n",
4801     <item> \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ _go_c,
4802     Optarg)
4804     <item> \ \ \ \ \ \ \ printf("non-option arguments:\\n")
4806     <item> \ \ \ \ \ \ \ for (; Optind \<less\> ARGC; Optind++)
4808     <item> \ \ \ \ \ \ \ \ \ \ \ printf("\\tARGV[%d] = \<less\>%s\<gtr\>\\n",
4810     <item> \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Optind,
4811     ARGV[Optind])
4813     <item> \ \ \ }
4815     <item>}
4816   </nf-chunk||>
4818   The entire getopt.awk is made out of these chunks in order
4820   <\nf-chunk|getopt.awk>
4821     <item><nf-ref|getopt.awk-header|>
4823     <item>
4825     <item><nf-ref|getopt.awk-notes|>
4827     <item><nf-ref|getopt.awk-getopt()|>
4829     <item><nf-ref|getopt.awk-begin|>
4830   </nf-chunk||>
4832   Although we only want the header and function:
4834   <\nf-chunk|getopt>
4835     <item># try: locate getopt.awk for the full original file
4837     <item># as part of your standard awk installation
4839     <item><nf-ref|getopt.awk-header|>
4841     <item>
4843     <item><nf-ref|getopt.awk-getopt()|>
4844   </nf-chunk||>
4846   <chapter|Fangle LaTeX source code><label|latex-source>
4848   <section|fangle module>
4850   Here we define a <LyX> <verbatim|.module> file that makes it convenient to
4851   use <LyX> for writing such literate programs.
4853   This file <verbatim|./fangle.module> can be installed in your personal
4854   <verbatim|.lyx/layouts> folder. You will need to Tools Reconfigure so that
4855   <LyX> notices it. It adds a new format Chunk, which should precede every
4856   listing and contain the chunk name.
4858   <\nf-chunk|./fangle.module>
4859     <item>#\\DeclareLyXModule{Fangle Literate Listings}
4861     <item>#DescriptionBegin
4863     <item># \ Fangle literate listings allow one to write
4865     <item># \ \ literate programs after the fashion of noweb, but without
4866     having
4868     <item># \ \ to use noweave to generate the documentation. Instead the
4869     listings
4871     <item># \ \ package is extended in conjunction with the noweb package to
4872     implement
4874     <item># \ \ to code formating directly as latex.
4876     <item># \ The fangle awk script
4878     <item>#DescriptionEnd
4880     <item>
4882     <item><nf-ref|gpl3-copyright.hashed|>
4884     <item>
4886     <item>Format 11
4888     <item>
4890     <item>AddToPreamble
4892     <item><nf-ref|./fangle.sty|>
4894     <item>EndPreamble
4896     <item>
4898     <item><nf-ref|chunkstyle|>
4900     <item>
4902     <item><nf-ref|chunkref|>
4903   </nf-chunk|lyx-module|>
4905   Because <LyX> modules are not yet a language supported by fangle or
4906   lstlistings, we resort to this fake awk chunk below in order to have each
4907   line of the GPL3 license commence with a #
4909   <\nf-chunk|gpl3-copyright.hashed>
4910     <item>#<nf-ref|gpl3-copyright|>
4912     <item>
4913   </nf-chunk|awk|>
4915   <subsection|The Chunk style>
4917   The purpose of the <name|chunk> style is to make it easier for <LyX> users
4918   to provide the name to <verbatim|lstlistings>. Normally this requires
4919   right-clicking on the listing, choosing settings, advanced, and then typing
4920   <verbatim|name=chunk-name>. This has the further disadvantage that the name
4921   (and other options) are not generally visible during document editing.
4923   The chunk style is defined as a <LaTeX> command, so that all text on the
4924   same line is passed to the <verbatim|LaTeX> command <verbatim|Chunk>. This
4925   makes it easy to parse using <verbatim|fangle>, and easy to pass these
4926   options on to the listings package. The first word in a chunk section
4927   should be the chunk name, and will have <verbatim|name=> prepended to it.
4928   Any other words are accepted arguments to <verbatim|lstset>.
4930   We set PassThru to 1 because the user is actually entering raw latex.
4932   <\nf-chunk|chunkstyle>
4933     <item>Style Chunk
4935     <item> \ LatexType \ \ \ \ \ \ \ \ \ \ \ \ Command
4937     <item> \ LatexName \ \ \ \ \ \ \ \ \ \ \ \ Chunk
4939     <item> \ Margin \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ First_Dynamic
4941     <item> \ LeftMargin \ \ \ \ \ \ \ \ \ \ \ Chunk:xxx
4943     <item> \ LabelSep \ \ \ \ \ \ \ \ \ \ \ \ \ xx
4945     <item> \ LabelType \ \ \ \ \ \ \ \ \ \ \ \ Static
4947     <item> \ LabelString \ \ \ \ \ \ \ \ \ \ "Chunk:"
4949     <item> \ Align \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Left
4951     <item> \ PassThru \ \ \ \ \ \ \ \ \ \ \ \ \ 1
4953     <item>
4954   </nf-chunk||>
4956   To make the label very visible we choose a larger font coloured red.
4958   <\nf-chunk|chunkstyle>
4959     <item> \ LabelFont
4961     <item> \ \ \ Family \ \ \ \ \ \ \ \ \ \ \ \ \ Sans
4963     <item> \ \ \ Size \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Large
4965     <item> \ \ \ Series \ \ \ \ \ \ \ \ \ \ \ \ \ Bold
4967     <item> \ \ \ Shape \ \ \ \ \ \ \ \ \ \ \ \ \ \ Italic
4969     <item> \ \ \ Color \ \ \ \ \ \ \ \ \ \ \ \ \ \ red
4971     <item> \ EndFont
4973     <item>End
4974   </nf-chunk||>
4976   <subsection|The chunkref style>
4978   We also define the Chunkref style which can be used to express cross
4979   references to chunks.
4981   <\nf-chunk|chunkref>
4982     <item>InsetLayout Chunkref
4984     <item> \ LyxType \ \ \ \ \ \ \ \ \ \ \ \ \ \ charstyle
4986     <item> \ LatexType \ \ \ \ \ \ \ \ \ \ \ \ Command
4988     <item> \ LatexName \ \ \ \ \ \ \ \ \ \ \ \ chunkref
4990     <item> \ PassThru \ \ \ \ \ \ \ \ \ \ \ \ \ 1
4992     <item> \ LabelFont \ \ \ \ \ \ \ \ \ \ \ \ 
4994     <item> \ \ \ Shape \ \ \ \ \ \ \ \ \ \ \ \ \ \ Italic
4996     <item> \ \ \ Color \ \ \ \ \ \ \ \ \ \ \ \ \ \ red
4998     <item> \ EndFont
5000     <item>End
5001   </nf-chunk||>
5003   <section|Latex Macros><label|sec:Latex-Macros>
5005   We require the listings, noweb and xargs packages. As noweb defines it's
5006   own <verbatim|\\code> environment, we re-define the one that <LyX> logical
5007   markup module expects here.
5009   <\nf-chunk|./fangle.sty>
5010     <item>\\usepackage{listings}%
5012     <item>\\usepackage{noweb}%
5014     <item>\\usepackage{xargs}%
5016     <item>\\renewcommand{\\code}[1]{\\texttt{#1}}%
5017   </nf-chunk|tex|>
5019   We also define a <verbatim|CChunk> macro, for use as:
5020   <verbatim|\\begin{CChunk}> which will need renaming to
5021   <verbatim|\\begin{Chunk}> when I can do this without clashing with
5022   <verbatim|\\Chunk>.
5024   <\nf-chunk|./fangle.sty>
5025     <item>\\lstnewenvironment{Chunk}{\\relax}{\\relax}%
5026   </nf-chunk||>
5028   We also define a suitable <verbatim|\\lstset> of parameters that suit the
5029   literate programming style after the fashion of <name|noweave>.
5031   <\nf-chunk|./fangle.sty>
5032     <item>\\lstset{numbers=left, stepnumber=5, numbersep=5pt,
5034     <item> \ \ \ \ \ \ \ breaklines=false,basicstyle=\\ttfamily,
5036     <item> \ \ \ \ \ \ \ numberstyle=\\tiny, language=C}%
5037   </nf-chunk||>
5039   We also define a notangle-like mechanism for escaping to <LaTeX> from the
5040   listing, and by which we can refer to other listings. We declare the
5041   <verbatim|=\<less\>...\<gtr\>> sequence to contain <LaTeX> code, and
5042   include another like this chunk: <verbatim|<nf-ref|chunkname|>>. However,
5043   because <verbatim|=\<less\>...\<gtr\>> is already defined to contain
5044   <LaTeX> code for this document --- this is a fangle document after all ---
5045   the code fragment below effectively contains the <LaTeX> code:
5046   <verbatim|}{>. To avoid problems with document generation, I had to declare
5047   an lstlistings property: <verbatim|escapeinside={}> for this listing only;
5048   which in <LyX> was done by right-clicking the listings inset, choosing
5049   settings-\<gtr\>advanced. Therefore <verbatim|=\<less\>> isn't interpreted
5050   literally here, in a listing when the escape sequence is already defined as
5051   shown... we need to somehow escape this representation...
5053   <\nf-chunk|./fangle.sty>
5054     <item>\\lstset{escapeinside={=\<less\>}{\<gtr\>}}%
5055   </nf-chunk||>
5057   Although our macros will contain the <verbatim|@> symbol, they will be
5058   included in a <verbatim|\\makeatletter> section by <LyX>; however we keep
5059   the commented out <verbatim|\\makeatletter> as a reminder. The listings
5060   package likes to centre the titles, but noweb titles are specially
5061   formatted and must be left aligned. The simplest way to do this turned out
5062   to be by removing the definition of <verbatim|\\lst@maketitle>. This may
5063   interact badly if other listings want a regular title or caption. We
5064   remember the old maketitle in case we need it.
5066   <\nf-chunk|./fangle.sty>
5067     <item>%\\makeatletter
5069     <item>%somehow re-defining maketitle gives us a left-aligned title
5071     <item>%which is extactly what our specially formatted title needs!
5073     <item>\\global\\let\\fangle@lst@maketitle\\lst@maketitle%
5075     <item>\\global\\def\\lst@maketitle{}%
5076   </nf-chunk||>
5078   <subsection|The chunk command><label|sub:The-chunk-command>
5080   Our chunk command accepts one argument, and calls <verbatim|\\ltset>.
5081   Although <verbatim|\\ltset> will note the name, this is erased when the
5082   next <verbatim|\\lstlisting> starts, so we make a note of this in
5083   <verbatim|\\lst@chunkname> and restore in in lstlistings Init hook.
5085   <\nf-chunk|./fangle.sty>
5086     <item>\\def\\Chunk#1{%
5088     <item> \ \\lstset{title={\\fanglecaption},name=#1}%
5090     <item> \ \\global\\edef\\lst@chunkname{\\lst@intname}%
5092     <item>}%
5094     <item>\\def\\lst@chunkname{\\empty}%
5095   </nf-chunk||>
5097   <subsubsection|Chunk parameters>
5099   Fangle permits parameterized chunks, and requires the paramters to be
5100   specified as listings options. The fangle script uses this, and although we
5101   don't do anything with these in the <LaTeX> code right now, we need to stop
5102   the listings package complaining.
5104   <\nf-chunk|./fangle.sty>
5105     <item>\\lst@Key{params}\\relax{\\def\\fangle@chunk@params{#1}}%
5106   </nf-chunk||>
5108   As it is common to define a chunk which then needs appending to another
5109   chunk, and annoying to have to declare a single line chunk to manage the
5110   include, we support an append= option.
5112   <\nf-chunk|./fangle.sty>
5113     <item>\\lst@Key{append}\\relax{\\def\\fangle@chunk@append{#1}}%
5114   </nf-chunk||>
5116   <subsection|The noweb styled caption>
5118   We define a public macro <verbatim|\\fanglecaption> which can be set as a
5119   regular title. By means of <verbatim|\\protect>, It expands to
5120   <verbatim|\\fangle@caption> at the appopriate time when the caption is
5121   emitted.
5123   <nf-chunk|./fangle.sty|\\def\\fanglecaption{\\protect\\fangle@caption}%||>
5125   <\big-figure>
5126     22c <math|\<langle\>>some-chunk 19b<math|\<rangle\>><math|\<equiv\>>+
5127     \ \ <math|\<vartriangleleft\>>22b 24d<math|\<vartriangleright\>>
5129     \;
5131     In this example, the current chunk is 22c, and therefore the third chunk
5132     on page 22.
5134     It's name is some-chunk.\ 
5136     The first chunk with this name (19b) occurs as the second chunk on page
5137     19.
5139     The previous chunk (22d) with the same name is the second chunk on page
5140     22.
5142     The next chunk (24d) is the fourth chunk on page 24.
5143   </big-figure|Noweb Heading<label|noweb heading>>
5145   The general noweb output format compactly identifies the current chunk, and
5146   references to the first chunk, and the previous and next chunks that have
5147   the same name.
5149   This means that we need to keep a counter for each chunk-name, that we use
5150   to count chunks of the same name.
5152   <subsection|The chunk counter>
5154   It would be natural to have a counter for each chunk name, but TeX would
5155   soon run out of counters<\footnote>
5156     ...soon did run out of counters and so I had to re-write the LaTeX macros
5157     to share a counter as described here.
5158   </footnote>, so we have one counter which we save at the end of a chunk and
5159   restore at the beginning of a chunk.
5161   <\nf-chunk|./fangle.sty>
5162     <item>\\newcounter{fangle@chunkcounter}%
5163   </nf-chunk||>
5165   We construct the name of this variable to store the counter to be the text
5166   <verbatim|lst-chunk-> prefixed onto the chunks own name, and store it in
5167   <verbatim|\\chunkcount>.\ 
5169   We save the counter like this:
5171   <nf-chunk|save-counter|\\global\\expandafter\\edef\\csname
5172   \\chunkcount\\endcsname{\\arabic{fangle@chunkcounter}}%||>
5174   and restore the counter like this:
5176   <nf-chunk|restore-counter|\\setcounter{fangle@chunkcounter}{\\csname
5177   \\chunkcount\\endcsname}%||>
5179   If there does not already exist a variable whose name is stored in
5180   <verbatim|\\chunkcount>, then we know we are the first chunk with this
5181   name, and then define a counter.\ 
5183   Although chunks of the same name share a common counter, they must still be
5184   distinguished. We use is the internal name of the listing, suffixed by the
5185   counter value. So the first chunk might be <verbatim|something-1> and the
5186   second chunk be <verbatim|something-2>, etc.
5188   We also calculate the name of the previous chunk if we can (before we
5189   increment the chunk counter). If this is the first chunk of that name, then
5190   <verbatim|\\prevchunkname> is set to <verbatim|\\relax> which the noweb
5191   package will interpret as not existing.
5193   <\nf-chunk|./fangle.sty>
5194     <item>\\def\\fangle@caption{%
5196     <item> \ \\edef\\chunkcount{lst-chunk-\\lst@intname}%
5198     <item> \ \\@ifundefined{\\chunkcount}{%
5200     <item> \ \ \ \\expandafter\\gdef\\csname \\chunkcount\\endcsname{0}%
5202     <item> \ \ \ \\setcounter{fangle@chunkcounter}{\\csname
5203     \\chunkcount\\endcsname}%
5205     <item> \ \ \ \\let\\prevchunkname\\relax%
5207     <item> \ }{%
5209     <item> \ \ \ \\setcounter{fangle@chunkcounter}{\\csname
5210     \\chunkcount\\endcsname}%
5212     <item> \ \ \ \\edef\\prevchunkname{\\lst@intname-\\arabic{fangle@chunkcounter}}%
5214     <item> \ }%
5215   </nf-chunk||>
5217   After incrementing the chunk counter, we then define the name of this
5218   chunk, as well as the name of the first chunk.
5220   <\nf-chunk|./fangle.sty>
5221     <item> \ \\addtocounter{fangle@chunkcounter}{1}%
5223     <item> \ \\global\\expandafter\\edef\\csname
5224     \\chunkcount\\endcsname{\\arabic{fangle@chunkcounter}}%
5226     <item> \ \\edef\\chunkname{\\lst@intname-\\arabic{fangle@chunkcounter}}%
5228     <item> \ \\edef\\firstchunkname{\\lst@intname-1}%
5229   </nf-chunk||>
5231   We now need to calculate the name of the next chunk. We do this by
5232   temporarily skipping the counter on by one; however there may not actually
5233   be another chunk with this name! We detect this by also defining a label
5234   for each chunk based on the chunkname. If there is a next chunkname then it
5235   will define a label with that name. As labels are persistent, we can at
5236   least tell the second time <LaTeX> is run. If we don't find such a defined
5237   label then we define <verbatim|\\nextchunkname> to <verbatim|\\relax>.
5239   <\nf-chunk|./fangle.sty>
5240     <item> \ \\addtocounter{fangle@chunkcounter}{1}%
5242     <item> \ \\edef\\nextchunkname{\\lst@intname-\\arabic{fangle@chunkcounter}}%
5244     <item> \ \\@ifundefined{r@label-\\nextchunkname}{\\let\\nextchunkname\\relax}{}%
5245   </nf-chunk||>
5247   The noweb package requires that we define a <verbatim|\\sublabel> for every
5248   chunk, with a unique name, which is then used to print out it's navigation
5249   hints.
5251   We also define a regular label for this chunk, as was mentioned above when
5252   we calculated <verbatim|\\nextchunkname>. This requires <LaTeX> to be run
5253   at least twice after new chunk sections are added --- but noweb requried
5254   that anyway.
5256   <\nf-chunk|./fangle.sty>
5257     <item> \ \\sublabel{\\chunkname}%
5259     <item>% define this label for every chunk instance, so we
5261     <item>% can tell when we are the last chunk of this name
5263     <item> \ \\label{label-\\chunkname}%
5264   </nf-chunk||>
5266   We also try and add the chunk to the list of listings, but I'm afraid we
5267   don't do very well. We want each chunk name listing once, with all of it's
5268   references.
5270   <\nf-chunk|./fangle.sty>
5271     <item> \ \\addcontentsline{lol}{lstlisting}{\\lst@name~[\\protect\\subpageref{\\chunkname}]}%
5272   </nf-chunk||>
5274   We then call the noweb output macros in the same way that noweave generates
5275   them, except that we don't need to call <verbatim|\\nwstartdeflinemarkup>
5276   or <verbatim|\\nwenddeflinemarkup> <emdash> and if we do, it messes up the
5277   output somewhat.
5279   <\nf-chunk|./fangle.sty>
5280     <item> \ \\nwmargintag{%
5282     <item> \ \ \ {%
5284     <item> \ \ \ \ \ \\nwtagstyle{}%
5286     <item> \ \ \ \ \ \\subpageref{\\chunkname}%
5288     <item> \ \ \ }%
5290     <item> \ }%
5292     <item>%
5294     <item> \ \\moddef{%
5296     <item> \ \ \ {\\lst@name}%
5298     <item> \ \ \ {%
5300     <item> \ \ \ \ \ \\nwtagstyle{}\\/%
5302     <item> \ \ \ \ \ \\@ifundefined{fangle@chunk@params}{}{%
5304     <item> \ \ \ \ \ \ \ (\\fangle@chunk@params)%
5306     <item> \ \ \ \ \ }%
5308     <item> \ \ \ \ \ [\\csname \\chunkcount\\endcsname]~%
5310     <item> \ \ \ \ \ \\subpageref{\\firstchunkname}%
5312     <item> \ \ \ }%
5314     <item> \ \ \ \\@ifundefined{fangle@chunk@append}{}{%
5316     <item> \ \ \ \\ifx{}\\fangle@chunk@append{x}\\else%
5318     <item> \ \ \ \ \ \ \ ,~add~to~\\fangle@chunk@append%
5320     <item> \ \ \ \\fi%
5322     <item> \ \ \ }%
5324     <item>\\global\\def\\fangle@chunk@append{}%
5326     <item>\\lstset{append=x}%
5328     <item> \ }%
5330     <item>%
5332     <item> \ \\ifx\\relax\\prevchunkname\\endmoddef\\else\\plusendmoddef\\fi%
5334     <item>% \ \\nwstartdeflinemarkup%
5336     <item> \ \\nwprevnextdefs{\\prevchunkname}{\\nextchunkname}%
5338     <item>% \ \\nwenddeflinemarkup%
5340     <item>}%
5341   </nf-chunk||>
5343   Originally this was developed as a <verbatim|listings> aspect, in the Init
5344   hook, but it was found easier to affect the title without using a hook
5345   <emdash> <verbatim|\\lst@AddToHookExe{PreSet}> is still required to set the
5346   listings name to the name passed to the <verbatim|\\Chunk> command, though.
5348   <\nf-chunk|./fangle.sty>
5349     <item>%\\lst@BeginAspect{fangle}
5351     <item>%\\lst@Key{fangle}{true}[t]{\\lstKV@SetIf{#1}{true}}
5353     <item>\\lst@AddToHookExe{PreSet}{\\global\\let\\lst@intname\\lst@chunkname}
5355     <item>\\lst@AddToHook{Init}{}%\\fangle@caption}
5357     <item>%\\lst@EndAspect
5358   </nf-chunk||>
5360   <subsection|Cross references>
5362   We define the <verbatim|\\chunkref> command which makes it easy to generate
5363   visual references to different code chunks, e.g.
5365   <block|<tformat|<table|<row|<cell|Macro>|<cell|Appearance>>|<row|<cell|<verbatim|\\chunkref{preamble}>>|<cell|>>|<row|<cell|<verbatim|\\chunkref[3]{preamble}>>|<cell|>>|<row|<cell|<verbatim|\\chunkref{preamble}[arg1,
5366   arg2]>>|<cell|>>>>>
5368   Chunkref can also be used within a code chunk to include another code
5369   chunk. The third optional parameter to chunkref is a comma sepatarated list
5370   of arguments, which will replace defined parameters in the chunkref.
5372   <\note>
5373     Darn it, if I have: <verbatim|=\<less\>\\chunkref{new-mode-tracker}[{chunks[chunk_name,
5374     "language"]},{mode}]\<gtr\>> the inner braces (inside [ ]) cause _ to
5375     signify subscript even though we have <verbatim|lst@ReplaceIn>
5376   </note>
5378   <\nf-chunk|./fangle.sty>
5379     <item>\\def\\chunkref@args#1,{%
5381     <item> \ \\def\\arg{#1}%
5383     <item> \ \\lst@ReplaceIn\\arg\\lst@filenamerpl%
5385     <item> \ \\arg%
5387     <item> \ \\@ifnextchar){\\relax}{, \\chunkref@args}%
5389     <item>}%
5391     <item>\\newcommand\\chunkref[2][0]{%
5393     <item> \ \\@ifnextchar({\\chunkref@i{#1}{#2}}{\\chunkref@i{#1}{#2}()}%
5395     <item>}%
5397     <item>\\def\\chunkref@i#1#2(#3){%
5399     <item> \ \\def\\zero{0}%
5401     <item> \ \\def\\chunk{#2}%
5403     <item> \ \\def\\chunkno{#1}%
5405     <item> \ \\def\\chunkargs{#3}%
5407     <item> \ \\ifx\\chunkno\\zero%
5409     <item> \ \ \ \\def\\chunkname{#2-1}%
5411     <item> \ \\else%
5413     <item> \ \ \ \\def\\chunkname{#2-\\chunkno}%
5415     <item> \ \\fi%
5417     <item> \ \\let\\lst@arg\\chunk%
5419     <item> \ \\lst@ReplaceIn\\chunk\\lst@filenamerpl%
5421     <item> \ \\LA{%\\moddef{%
5423     <item> \ \ \ {\\chunk}%
5425     <item> \ \ \ {%
5427     <item> \ \ \ \ \ \\nwtagstyle{}\\/%
5429     <item> \ \ \ \ \ \\ifx\\chunkno\\zero%
5431     <item> \ \ \ \ \ \\else%
5433     <item> \ \ \ \ \ [\\chunkno]%
5435     <item> \ \ \ \ \ \\fi%
5437     <item> \ \ \ \ \ \\ifx\\chunkargs\\empty%
5439     <item> \ \ \ \ \ \\else%
5441     <item> \ \ \ \ \ \ \ (\\chunkref@args #3,)%
5443     <item> \ \ \ \ \ \\fi%
5445     <item> \ \ \ \ \ ~\\subpageref{\\chunkname}%
5447     <item> \ \ \ }%
5449     <item> \ }%
5451     <item> \ \\RA%\\endmoddef%
5453     <item>}%
5454   </nf-chunk||>
5456   <subsection|The end>
5458   <\nf-chunk|./fangle.sty>
5459     <item>%
5461     <item>%\\makeatother
5462   </nf-chunk||>
5464   <chapter|Extracting fangle>
5466   <section|Extracting from Lyx>
5468   To extract from <LyX>, you will need to configure <LyX> as explained in
5469   section <reference|Configuring-the-build>.
5471   <label|lyx-build-script>And this lyx-build scrap will extract fangle for
5472   me.
5474   <\nf-chunk|lyx-build>
5475     <item>#! /bin/sh
5477     <item>set -x
5479     <item>
5481     <item><nf-ref|lyx-build-helper|>
5483     <item>cd $PROJECT_DIR \|\| exit 1
5485     <item>
5487     <item>/usr/local/bin/fangle -R./fangle $TEX_SRC \<gtr\> ./fangle
5489     <item>/usr/local/bin/fangle -R./fangle.module $TEX_SRC \<gtr\>
5490     ./fangle.module
5492     <item>
5494     <item>export FANGLE=./fangle
5496     <item>export TMP=${TMP:-/tmp}
5498     <item><nf-ref|test:*|>
5499   </nf-chunk|sh|>
5501   With a lyx-build-helper
5503   <\nf-chunk|lyx-build-helper>
5504     <item>PROJECT_DIR="$LYX_r"
5506     <item>LYX_SRC="$PROJECT_DIR/${LYX_i%.tex}.lyx"
5508     <item>TEX_DIR="$LYX_p"
5510     <item>TEX_SRC="$TEX_DIR/$LYX_i"
5512     <item>TXT_SRC="$TEX_SRC"
5513   </nf-chunk|sh|>
5515   <section|Extracting documentation>
5517   <\nf-chunk|./gen-www>
5518     <item>#python -m elyxer --css lyx.css $LYX_SRC \| \\
5520     <item># \ iconv -c -f utf-8 -t ISO-8859-1//TRANSLIT \| \\
5522     <item># \ sed 's/UTF-8"\\(.\\)\<gtr\>/ISO-8859-1"\\1\<gtr\>/' \<gtr\>
5523     www/docs/fangle.html
5525     <item>
5527     <item>python -m elyxer --css lyx.css --iso885915 --html --destdirectory
5528     www/docs/fangle.e \\
5530     <item> \ \ \ \ \ \ fangle.lyx \<gtr\> www/docs/fangle.e/fangle.html
5532     <item>
5534     <item>( mkdir -p www/docs/fangle && cd www/docs/fangle && \\
5536     <item> \ lyx -e latex ../../../fangle.lyx && \\
5538     <item> \ htlatex ../../../fangle.tex "xhtml,fn-in" && \\
5540     <item> \ sed -i -e 's/\<less\>!--l\\. [0-9][0-9]* *--\<gtr\>//g'
5541     fangle.html
5543     <item>)
5545     <item>
5547     <item>( mkdir -p www/docs/literate && cd www/docs/literate && \\
5549     <item> \ lyx -e latex ../../../literate.lyx && \\
5551     <item> \ htlatex ../../../literate.tex "xhtml,fn-in" && \\
5553     <item> \ sed -i -e 's/\<less\>!--l\\. [0-9][0-9]* *--\<gtr\>$//g'
5554     literate.html
5556     <item>)
5557   </nf-chunk||>
5559   <section|Extracting from the command line>
5561   First you will need the tex output, then you can extract:
5563   <\nf-chunk|lyx-build-manual>
5564     <item>lyx -e latex fangle.lyx
5566     <item>fangle -R./fangle fangle.tex \<gtr\> ./fangle
5568     <item>fangle -R./fangle.module fangle.tex \<gtr\> ./fangle.module
5569   </nf-chunk|sh|>
5571   \;
5573   <part|Tests>
5575   <chapter|Tests>
5577   <\nf-chunk|test:*>
5578     <item>#! /bin/bash
5580     <item>
5582     <item>export SRC="${SRC:-./fangle.tm}"
5584     <item>export FANGLE="${FANGLE:-./fangle}"
5586     <item>export TMP="${TMP:-/tmp}"
5588     <item>export TESTDIR="$TMP/$USER/fangle.tests"
5590     <item>export TXT_SRC="${TXT_SRC:-$TESTDIR/fangle.txt}"
5592     <item>export AWK="${AWK:-awk}"
5594     <item>export RUN_FANGLE="${RUN_FANGLE:-$AWK -f}"
5596     <item>
5598     <item>fangle() {
5600     <item> \ ${AWK} -f ${FANGLE} "$@"
5602     <item>}
5604     <item>
5606     <item>mkdir -p "$TESTDIR"
5608     <item>
5610     <item>tm -s -c "$SRC" "$TXT_SRC" -q
5612     <item>
5614     <item><nf-ref|test:helpers|>
5616     <item>run_tests() {
5618     <item> \ <nf-ref|test:run-tests|>
5620     <item>}
5622     <item>
5624     <item># test current fangle
5626     <item>echo Testing current fangle
5628     <item>run_tests
5630     <item>
5632     <item># extract new fangle
5634     <item>echo testing new fangle
5636     <item>fangle -R./fangle "$TXT_SRC" \<gtr\> "$TESTDIR/fangle"
5638     <item>export FANGLE="$TESTDIR/fangle"
5640     <item>run_tests
5642     <item>
5644     <item># Now check that it can extract a fangle that also passes the
5645     tests!
5647     <item>echo testing if new fangle can generate itself
5649     <item>fangle -R./fangle "$TXT_SRC" \<gtr\> "$TESTDIR/fangle.new"
5651     <item>passtest diff -bwu "$FANGLE" "$TESTDIR/fangle.new"
5653     <item>export FANGLE="$TESTDIR/fangle.new"
5655     <item>run_tests
5656   </nf-chunk||>
5658   <\nf-chunk|test:run-tests>
5659     <item># run tests
5661     <item>fangle -Rpca-test.awk $TXT_SRC \| awk -f - \|\| exit 1
5663     <item><nf-ref|test:cromulence|>
5665     <item><nf-ref|test:escapes|>
5667     <item><nf-ref|test:test-chunk|<tuple|test:example-sh>>
5669     <item><nf-ref|test:test-chunk|<tuple|test:example-makefile>>
5671     <item><nf-ref|test:test-chunk|<tuple|test:q:1>>
5673     <item><nf-ref|test:test-chunk|<tuple|test:make:1>>
5675     <item><nf-ref|test:test-chunk|<tuple|test:make:2>>
5677     <item><nf-ref|test:chunk-params|>
5678   </nf-chunk|sh|>
5680   <\nf-chunk|test:helpers>
5681     <item>passtest() {
5683     <item> \ if "$@"
5685     <item> \ then echo "Passed $TEST"
5687     <item> \ else echo "Failed $TEST"
5689     <item> \ \ \ \ \ \ return 1
5691     <item> \ fi
5693     <item>}
5695     <item>
5697     <item>failtest() {
5699     <item> \ if ! "$@"
5701     <item> \ then echo "Passed $TEST"
5703     <item> \ else echo "Failed $TEST"
5705     <item> \ \ \ \ \ \ return 1
5707     <item> \ fi
5709     <item>}
5710   </nf-chunk||>
5712   This chunk will render a named chunk and compare it to another rendered
5713   nameed chunk
5715   <\nf-chunk|test:test-chunk>
5716     <item><nf-ref|test:test-chunk-result|<tuple|<nf-arg|chunk>|<nf-arg|chunk>.result>>
5717   </nf-chunk|sh|<tuple|chunk>>
5719   <\nf-chunk|test:test-chunk-result>
5720     <item>TEST="<nf-arg|result>" passtest diff -u --label "EXPECTED:
5721     <nf-arg|result>" \<less\>( fangle -R<nf-arg|result> $TXT_SRC ) \\
5723     <item> \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ --label
5724     "ACTUAL: <nf-arg|chunk>" \<less\>( fangle -R<nf-arg|chunk> $TXT_SRC )
5725   </nf-chunk|sh|<tuple|chunk|result>>
5727   <chapter|Chunk Parameters>
5729   <section|<LyX>>
5731   <\nf-chunk|test:lyx:chunk-params:sub>
5732     <item>I see a ${THING},
5734     <item>a ${THING} of colour ${colour},\ 
5736     <item>and looking closer =\<less\>\\chunkref{test:lyx:chunk-params:sub:sub}(${colour})\<gtr\>
5737   </nf-chunk||<tuple|THING|colour>>
5739   <\nf-chunk|test:lyx:chunk-params:sub:sub>
5740     <item>a funny shade of ${colour}
5741   </nf-chunk||<tuple|colour>>
5743   <\nf-chunk|test:lyx:chunk-params:text>
5744     <item>What do you see? "=\<less\>\\chunkref{test:lyx:chunk-params:sub}(joe,
5745     red)\<gtr\>"
5747     <item>Well, fancy!
5748   </nf-chunk||>
5750   Should generate output:
5752   <\nf-chunk|test:lyx:chunk-params:result>
5753     <item>What do you see? "I see a joe,
5755     <item> \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ a joe of colour red,\ 
5757     <item> \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ and looking closer a funny shade
5758     of red"
5760     <item>Well, fancy!
5761   </nf-chunk||>
5763   And this chunk will perform the test:
5765   <\nf-chunk|test:chunk-params>
5766     <item><nf-ref|test:test-chunk-result|<tuple|test:lyx:chunk-params:text|test:lyx:chunk-params:result>>
5767     \|\| exit 1
5768   </nf-chunk||>
5770   <section|<TeXmacs>>
5772   <\nf-chunk|test:chunk-params:sub>
5773     <item>I see a <nf-arg|THING>,
5775     <item>a <nf-arg|THING> of colour <nf-arg|colour>,\ 
5777     <item>and looking closer <nf-ref|test:chunk-params:sub:sub|<tuple|<nf-arg|colour>>>
5778   </nf-chunk||<tuple|THING|colour>>
5780   <\nf-chunk|test:chunk-params:sub:sub>
5781     <item>a funny shade of <nf-arg|colour>
5782   </nf-chunk||<tuple|colour>>
5784   <\nf-chunk|test:chunk-params:text>
5785     <item>What do you see? "<nf-ref|test:chunk-params:sub|<tuple|joe|red>>"
5787     <item>Well, fancy!
5788   </nf-chunk||>
5790   Should generate output:
5792   <\nf-chunk|test:chunk-params:result>
5793     <item>What do you see? "I see a joe,
5795     <item> \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ a joe of colour red,\ 
5797     <item> \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ and looking closer a funny shade
5798     of red"
5800     <item>Well, fancy!
5801   </nf-chunk||>
5803   And this chunk will perform the test:
5805   <\nf-chunk|test:chunk-params>
5806     <item><nf-ref|test:test-chunk-result|<tuple|test:chunk-params:text|test:chunk-params:result>>
5807     \|\| exit 1
5808   </nf-chunk||>
5810   <chapter|Compile-log-lyx><label|Compile-log-lyx>
5812   <\nf-chunk|Chunk:./compile-log-lyx>
5813     <item>#! /bin/sh
5815     <item># can't use gtkdialog -i, cos it uses the "source" command which
5816     ubuntu sh doesn't have
5818     <item>
5820     <item>main() {
5822     <item> \ errors="/tmp/compile.log.$$"
5824     <item># \ if grep '^[^ ]*:\\( In \\\|[0-9][0-9]*: [^ ]*:\\)' \<gtr\>
5825     $errors
5827     <item>if grep '^[^ ]*(\\([0-9][0-9]*\\)) *: *\\(error\\\|warning\\)'
5828     \<gtr\> $errors
5830     <item> \ then
5832     <item> \ \ \ sed -i -e 's/^[^ ]*[/\\\\]\\([^/\\\\]*\\)(\\([ 0-9][
5833     0-9]*\\)) *: */\\1:\\2\|\\2\|/' $errors
5835     <item> \ \ \ COMPILE_DIALOG='
5837     <item> \<less\>vbox\<gtr\>
5839     <item> \ \<less\>text\<gtr\>
5841     <item> \ \ \ \<less\>label\<gtr\>Compiler errors:\<less\>/label\<gtr\>
5843     <item> \ \<less\>/text\<gtr\>
5845     <item> \ \<less\>tree exported_column="0"\<gtr\>
5847     <item> \ \ \ \<less\>variable\<gtr\>LINE\<less\>/variable\<gtr\>
5849     <item> \ \ \ \<less\>height\<gtr\>400\<less\>/height\<gtr\>\<less\>width\<gtr\>800\<less\>/width\<gtr\>
5851     <item> \ \ \ \<less\>label\<gtr\>File \| Line \|
5852     Message\<less\>/label\<gtr\>
5854     <item> \ \ \ \<less\>action\<gtr\>'". $SELF ; "'lyxgoto
5855     $LINE\<less\>/action\<gtr\>
5857     <item> \ \ \ \<less\>input\<gtr\>'"cat $errors"'\<less\>/input\<gtr\>
5859     <item> \ \<less\>/tree\<gtr\>
5861     <item> \ \<less\>hbox\<gtr\>
5863     <item> \ \ \<less\>button\<gtr\>\<less\>label\<gtr\>Build\<less\>/label\<gtr\>
5865     <item> \ \ \ \ \<less\>action\<gtr\>lyxclient -c "LYXCMD:build-program"
5866     &\<less\>/action\<gtr\>
5868     <item> \ \ \<less\>/button\<gtr\>
5870     <item> \ \ \<less\>button ok\<gtr\>\<less\>/button\<gtr\>
5872     <item> \ \<less\>/hbox\<gtr\>
5874     <item> \<less\>/vbox\<gtr\>
5876     <item>'
5878     <item> \ \ \ export COMPILE_DIALOG
5880     <item> \ \ \ ( gtkdialog --program=COMPILE_DIALOG ; rm $errors ) &
5882     <item> \ else
5884     <item> \ \ \ rm $errors
5886     <item> \ fi
5888     <item>}
5890     <item>
5892     <item>lyxgoto() {
5894     <item> \ file="${LINE%:*}"
5896     <item> \ line="${LINE##*:}"
5898     <item> \ extraline=`cat $file \| head -n $line \| tac \| sed
5899     '/^\\\\\\\\begin{lstlisting}/q' \| wc -l`
5901     <item> \ extraline=`expr $extraline - 1`
5903     <item> \ lyxclient -c "LYXCMD:command-sequence server-goto-file-row $file
5904     $line ; char-forward ; repeat $extraline paragraph-down ;
5905     paragraph-up-select"
5907     <item>}
5909     <item>
5911     <item>SELF="$0"
5913     <item>if test -z "$COMPILE_DIALOG"
5915     <item>then main "$@"\ 
5917     <item>fi
5918   </nf-chunk|sh|>
5920   \;
5921 </body>
5923 <\initial>
5924   <\collection>
5925     <associate|info-flag|short>
5926     <associate|page-medium|paper>
5927     <associate|page-screen-height|982016tmpt>
5928     <associate|page-screen-margin|false>
5929     <associate|page-screen-width|1686528tmpt>
5930     <associate|page-show-hf|true>
5931     <associate|preamble|false>
5932     <associate|sfactor|5>
5933   </collection>
5934 </initial>
5936 <\references>
5937 </references>
5939 <\auxiliary>
5940 </auxiliary>