1 #LyX 1.6.4 created this file. For more info see http://www.lyx.org/
8 numbers=left, stepnumber=1, numbersep=5pt,
10 basicstyle=\footnotesize\ttfamily,
16 \use_default_options true
25 \font_typewriter default
26 \font_default_family default
33 \paperfontsize default
36 \pdf_title "Newfangle"
37 \pdf_author "Sam Liddicott"
38 \pdf_subject "Literate Programing"
39 \pdf_keywords "notangle noweb noweave literate programming cweb"
41 \pdf_bookmarksnumbered false
42 \pdf_bookmarksopen false
43 \pdf_bookmarksopenlevel 1
55 \paperorientation portrait
58 \paragraph_separation skip
60 \quotes_language english
63 \paperpagestyle default
64 \tracking_changes false
84 \begin_layout Chapter*
88 \begin_layout Standard
93 is a tool for newfangled literate programming.
94 Newfangled is defined as
96 New and often needlessly novel
100 TheFreeDictionary.com
105 \begin_layout Standard
106 In this case, newfangled means yet another new and improved method for literate
110 \begin_layout Standard
115 has a long history starting with the great
119 himself, whose literate programming tools seem to make use of as many escape
120 sequences for semantic markup as TeX itself.
123 \begin_layout Standard
132 set of tools (notangle, noweave and noroots) and helpfully reduced the
133 amount of magic character sequences to pretty much just
134 \begin_inset Flex CharStyle:Code
137 \begin_layout Plain Layout
144 \begin_inset Flex CharStyle:Code
147 \begin_layout Plain Layout
153 , and in doing so brought the wonders of literate programming within my
157 \begin_layout Standard
158 While using the LyX editor for LaTeX editing I had various troubles with
159 the noweb tools, some of which were my fault, some of which were noweb's
160 fault and some of which were LyX's fault.
163 \begin_layout Standard
168 generally brought literate programming to the masses through removing some
169 of the complexity of the original literate programming, but this would
170 be of no advantage to me if the LyX / LaTeX combination brought more complicati
174 \begin_layout Standard
179 was thus born --- as an awk replacement for notangle, adding some important
180 features, like better integration with LyX and LaTeX, multiple output format
181 conversions, and fixing notangle bugs like indentation when using -L for
185 \begin_layout Standard
186 Significantly, newfangle is just one program which replaces various programs
188 Noweave is done away with and implemented directly as LaTeX macros, and
189 noroots is implemented as a function of the untangler
196 \begin_layout Standard
197 Newfangle is written in awk for portability reasons, awk being available
199 A python conversion will probably be attempted for the benefit of LyX.
200 (Hasn't anyone implemented awk in python yet?)
203 \begin_layout Standard
204 As an extension to many literate-programming styles, Newfangle permits code
205 chunks to take parameters and thus operate somewhat like C pre-processor
206 macros, or like C++ templates.
209 \begin_layout Section*
213 \begin_layout Enumerate
214 ^^ is always going to be a problem, see texbytopic 1.2.2 (Work out what I
218 \begin_layout Enumerate
219 copy over up to date Makefile guide from noweb-lyx document
222 \begin_layout Enumerate
223 Make chunk-name settings only apply to chunks with that name
226 \begin_layout Enumerate
227 indent of multi-line chunks may be mode dependant (i.e.
228 not in string literals)
231 \begin_layout Enumerate
232 add support for other commands in =<...>, starting with
234 label which takes the line-number within the chunk, and maybe should also
235 take the chunk name/page
238 \begin_layout Enumerate
239 cant have listing inside a ruled box
242 \begin_layout Enumerate
243 when a parameterized chunk is included as well as the #line emission, say
244 what the paremeters were for that invocation.
247 \begin_layout Enumerate
250 chunkref[3]{preamble} to include a certain chunk needs to work in newfangle.awk
251 instead of failing to be recognized at all
254 \begin_layout Enumerate
255 make in-listins labels track the chunk ref too, and make
257 chunref{[2],thing}> resolve to 41c (or d, or whatever chunk the 2nd chunk
261 \begin_layout Enumerate
264 chunkref in text needs a trailing space maybe, it keeps butting up to the
268 \begin_layout Enumerate
269 because the white-space indent is output by the parent chunk, the #line
270 is that of the parent chunk.
271 White space indents must be passed to the child chunk
274 \begin_layout Chapter*
278 \begin_layout Standard
279 \begin_inset CommandInset label
285 Newfangle is licensed under the GPL 3
286 \begin_inset CommandInset citation
293 This doesn't mean that you can't use or distribute newfangle with sources
294 of an incompatible license, but it means you must make the source of newfangle
298 \begin_layout Standard
299 As newfangle is currently written in
303 , an interpreted language, this should not be too hard.
307 gpl3-copyright,language=
310 \begin_layout Standard
311 \begin_inset listings
315 \begin_layout Plain Layout
317 newfangle - fully featured notangle replacement in awk
320 \begin_layout Plain Layout
324 \begin_layout Plain Layout
326 Copyright (C) 2009 Sam Liddicott <sam@liddicott.com>
329 \begin_layout Plain Layout
333 \begin_layout Plain Layout
335 This program is free software: you can redistribute it and/or modify
338 \begin_layout Plain Layout
340 it under the terms of the GNU General Public License as published by
343 \begin_layout Plain Layout
345 the Free Software Foundation, either version 3 of the License, or
348 \begin_layout Plain Layout
350 (at your option) any later version.
353 \begin_layout Plain Layout
357 \begin_layout Plain Layout
359 This program is distributed in the hope that it will be useful,
362 \begin_layout Plain Layout
364 but WITHOUT ANY WARRANTY; without even the implied warranty of
367 \begin_layout Plain Layout
369 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
373 \begin_layout Plain Layout
375 GNU General Public License for more details.
378 \begin_layout Plain Layout
382 \begin_layout Plain Layout
384 You should have received a copy of the GNU General Public License
387 \begin_layout Plain Layout
389 along with this program.
390 If not, see <http://www.gnu.org/licenses/>.
393 \begin_layout Plain Layout
402 \begin_layout Standard
403 \begin_inset CommandInset toc
404 LatexCommand tableofcontents
415 \begin_layout Chapter
419 \begin_layout Standard
420 Newfangle is a replacement for noweb, which consists of
421 \begin_inset Flex CharStyle:Code
424 \begin_layout Plain Layout
431 \begin_inset Flex CharStyle:Code
434 \begin_layout Plain Layout
441 \begin_inset Flex CharStyle:Code
444 \begin_layout Plain Layout
453 \begin_layout Standard
455 \begin_inset Flex CharStyle:Code
458 \begin_layout Plain Layout
465 \begin_inset Flex CharStyle:Code
468 \begin_layout Plain Layout
474 it can read multiple named files, or from stdin.
477 \begin_layout Section
481 \begin_layout Standard
482 The -r option causes newfangle to behave like noroots.
485 \begin_layout LyX-Code
486 newfangle -r filename.tex
489 \begin_layout Standard
490 will print out the newfangle roots of a tex file.
494 \begin_layout Standard
496 \begin_inset Flex CharStyle:Code
499 \begin_layout Plain Layout
505 command, the roots are not enclosed in
506 \begin_inset Flex CharStyle:Code
509 \begin_layout Plain Layout
515 , unless at least one of the roots is defined using the
516 \begin_inset Flex CharStyle:Code
519 \begin_layout Plain Layout
526 \begin_inset Flex CharStyle:Code
529 \begin_layout Plain Layout
538 \begin_layout Standard
539 Also, unlike noroots, it prints out all roots --- not just those that are
541 I find that a root not being used, doesn't make it particularly top level,
542 and so-called top level roots could also be included in another root as
547 \begin_layout Standard
548 My convention is that top level roots to be extracted begin with
549 \begin_inset Flex CharStyle:Code
552 \begin_layout Plain Layout
558 and have the form of a filename.
561 \begin_layout Standard
562 Makefile.inc, discussed in
563 \begin_inset CommandInset ref
565 reference "cha:makefile.inc"
569 , can automatically extract all such sources.
572 \begin_layout Section
576 \begin_layout Standard
578 \begin_inset Flex CharStyle:Code
581 \begin_layout Plain Layout
588 \begin_inset Flex CharStyle:Code
591 \begin_layout Plain Layout
597 options are supported.
600 \begin_layout Standard
601 The standard way to extract a file would be:
604 \begin_layout LyX-Code
605 newfangle -R./Makefile.inc newfangle.tex > ./Makefile.inc
608 \begin_layout Standard
610 \begin_inset Flex CharStyle:Code
613 \begin_layout Plain Layout
620 \begin_inset Flex CharStyle:Code
623 \begin_layout Plain Layout
629 option does not break indenting.
632 \begin_layout Standard
633 Also, thanks to mode tracking (described in
634 \begin_inset CommandInset ref
636 reference "cha:modes"
641 \begin_inset Flex CharStyle:Code
644 \begin_layout Plain Layout
650 option does not interrupt (and break) multi-line C macros either.
653 \begin_layout Standard
654 This does mean that sometimes the compiler might calculate the source line
655 wrongly when generating error messages in such cases, but there isn't any
656 other way around if multi-line macros include other chunks.
659 \begin_layout Section
660 Formatting source in LaTeX
663 \begin_layout Standard
664 The noweave replacement is a set of LaTeX macros dependant upon
668 , and which can be included with:
671 \begin_layout LyX-Code
674 usepackage{newfangle.sty}
677 \begin_layout Standard
678 The LaTeX macros are shown in section
679 \begin_inset CommandInset ref
681 reference "sec:Latex-Macros"
685 , and are part of a LyX module file
686 \begin_inset Flex CharStyle:Code
689 \begin_layout Plain Layout
695 , which automatically includes the macros in the document pre-amble when
696 the newfangle LyX module is used.
699 \begin_layout Standard
700 Because the noweave replacement is impemented in LaTeX, there is no processing
701 stage required before running the
702 \begin_inset Flex CharStyle:Code
705 \begin_layout Plain Layout
712 LaTeX may need running two or more times, so that the code chunk references
713 can be fully calculated.
716 \begin_layout Standard
718 \begin_inset Flex CharStyle:Code
721 \begin_layout Plain Layout
727 package is required as it is used for formatting the code chunk captions
730 \begin_layout Standard
732 \begin_inset Flex CharStyle:Code
735 \begin_layout Plain Layout
741 package is also required, as it is used for formatting the code chunks
745 \begin_layout Standard
747 \begin_inset Flex CharStyle:Code
750 \begin_layout Plain Layout
756 package is also required.
759 \begin_layout Chapter
760 Literate Programming with Newfangle
763 \begin_layout Standard
765 Should really follow on from a part-0 explanation of what literate programming
769 \begin_layout Chapter
770 Using Newfangle with LyX
773 \begin_layout Section
777 \begin_layout Subsection
778 Installing the LyX module
781 \begin_layout Standard
783 \begin_inset Flex CharStyle:Code
786 \begin_layout Plain Layout
792 to your LyX layouts directory, which for unix users will be
793 \begin_inset Flex CharStyle:Code
796 \begin_layout Plain Layout
805 \begin_layout Standard
806 You will need to reconfigure LyX by clicking Tools\SpecialChar \menuseparator
807 Reconfigure, and then
811 \begin_layout Subsection
812 \begin_inset CommandInset label
814 name "sub:Configuring-the-build"
818 Configuring the build script
821 \begin_layout Standard
822 Make sure you don't have a conversion defined for Lyx → Program
825 \begin_layout Standard
826 From the menu Tools\SpecialChar \menuseparator
827 Preferences, add a conversion from Latex(Plain) → Program
831 \begin_layout LyX-Code
832 set -x ; newfangle -Rlyx-build $$i |
835 \begin_layout LyX-Code
836 env LYX_b=$$b LYX_i=$$i LYX_o=$$o LYX_p=$$p LYX_r=$$r bash
839 \begin_layout Standard
840 (But don't cut-n-paste it from this document or you'll be pasting a multi-line
841 string which will break your lyx preferences file).
845 \begin_layout Standard
846 I hope that one day, LyX will set these into the environment when calling
850 \begin_layout Standard
851 You may also want to consider adding options to this conversion\SpecialChar \ldots{}
855 \begin_layout LyX-Code
856 parselog=/usr/share/lyx/scripts/listerrors
859 \begin_layout Standard
860 \SpecialChar \ldots{}
861 but if you do you will lose your stderr
865 \begin_layout Plain Layout
866 There is some bash plumbing to get a copy of stderr but this footnote is
875 \begin_layout Standard
876 Now, a shell script chunk called
877 \begin_inset Flex CharStyle:Code
880 \begin_layout Plain Layout
886 will be extracted and run whenever you choose the Document\SpecialChar \menuseparator
891 \begin_layout Standard
892 The lyx-build script for this document is in section
893 \begin_inset CommandInset ref
895 reference "lyx-build-script"
899 and on a unix system will extract
900 \begin_inset Flex CharStyle:Code
903 \begin_layout Plain Layout
910 \begin_inset Flex CharStyle:Code
913 \begin_layout Plain Layout
919 awk script, and run some basic tests.
921 \begin_inset Note Note
924 \begin_layout Plain Layout
925 cross-ref to test chapter when it is a chapter all on its own
933 \begin_layout Subsection
934 Preparing your Lyx document
937 \begin_layout Standard
938 It is not necessary to base your literate document on any of the original
939 LyX literate classes; so select a regular class for your document type.
942 \begin_layout Standard
958 \begin_layout Standard
959 In the drop-down style listbox you should notice a new style defined, called
967 \begin_layout Standard
968 When you wish to insert a literate chunk, you enter it's plain name in the
969 Chunk style, instead of the older method that used
970 \begin_inset Flex CharStyle:Code
973 \begin_layout Plain Layout
980 Following the chunk name, you insert a listing with: Insert\SpecialChar \menuseparator
984 \begin_layout Standard
985 Inside the white listing box you can type (or paste using shift+ctrl+V)
987 There is not need to use ctrl+enter at the end of lines as with some older
988 LyX literate techniques --- just press enter as normal.
991 \begin_layout Subsubsection
992 Customising the listing appearance
995 \begin_layout Standard
996 In the final document, the code is formatted using the
1001 The chunk style doesn't just define the chunk name, but can also define
1002 any other chunk options supported by the lstlistings package
1003 \begin_inset Flex CharStyle:Code
1006 \begin_layout Plain Layout
1015 In fact, what you type in the chunk style is raw latex.
1016 If you want to set the chunk language without having to right-click the
1018 \begin_inset Flex CharStyle:Code
1021 \begin_layout Plain Layout
1027 after the chunk name.
1028 (Currently the language will affect all subsequent listings, so you may
1030 \begin_inset Flex CharStyle:Code
1033 \begin_layout Plain Layout
1040 \begin_inset Note Note
1043 \begin_layout Plain Layout
1052 \begin_layout Standard
1053 Of course you can do this by editing the listings box advanced properties
1054 by right-clicking on the listings box, but that takes longer, and you can't
1055 see at-a-glance what the advanced settings are while editing the document;
1056 also advanced settings apply only to that box --- the chunk settings apply
1057 through the rest of the document
1061 \begin_layout Plain Layout
1062 It ought to apply only to subsequent chunks of the same name.
1069 \begin_inset Note Note
1072 \begin_layout Plain Layout
1073 So make sure they only apply to chunks of that name
1081 \begin_layout Subsubsection
1082 Global customisations
1085 \begin_layout Standard
1090 is used to set the code chunks, it's
1091 \begin_inset Flex CharStyle:Code
1094 \begin_layout Plain Layout
1102 command can be used in the pre-amble to set some document wide settings.
1105 \begin_layout Standard
1106 If your source has many words with long sequences of capital letters, then
1108 \begin_inset Flex CharStyle:Code
1111 \begin_layout Plain Layout
1112 columns=fullflexible
1117 may be a good idea, or the capital letters will get crowded.
1118 (I think lstlistings ought to use a slightly smaller font for captial letters
1119 so that they still fit).
1122 \begin_layout Standard
1124 \begin_inset Flex CharStyle:Code
1127 \begin_layout Plain Layout
1135 looks more normal for code, but has no bold (an alternate typewriter font
1140 \begin_layout Standard
1142 \begin_inset Flex CharStyle:Code
1145 \begin_layout Plain Layout
1153 , I must also specify
1154 \begin_inset Flex CharStyle:Code
1157 \begin_layout Plain Layout
1158 columns=fullflexible
1163 or the wrong letter spacing is used.
1166 \begin_layout Standard
1167 In my LeTeX pre-amble I usually specialise my code format with:
1171 document-preamble,language=tex
1174 \begin_layout Standard
1175 \begin_inset listings
1179 \begin_layout Plain Layout
1186 \begin_layout Plain Layout
1188 numbers=left, stepnumber=1, numbersep=5pt,
1191 \begin_layout Plain Layout
1196 \begin_layout Plain Layout
1205 \begin_layout Plain Layout
1212 \begin_layout Plain Layout
1217 \begin_layout Plain Layout
1219 columns=fullflexible,
1222 \begin_layout Plain Layout
1224 numberfirstline=true
1227 \begin_layout Plain Layout
1237 \begin_layout Chapter
1238 Newfangle with Makefiles
1241 \begin_layout Standard
1242 \begin_inset CommandInset label
1244 name "cha:makefile.inc"
1249 \begin_inset Note Note
1252 \begin_layout Plain Layout
1253 This chapter needs revising
1259 \begin_inset Note Greyedout
1262 \begin_layout Plain Layout
1263 This chapter needs revising
1268 Here we describe a Makefile.inc that you can include in your own Makefiles,
1269 or glue as a recursive make to other projects.
1272 \begin_layout Standard
1273 The Makefile.inc described here was put together for a Samba4 vfs module,
1274 but can be used in any Make project, including automake projects.
1277 \begin_layout Section
1278 A word about makefiles formats
1281 \begin_layout Standard
1282 Whitespace formatting is very important in a Makefile.
1283 The first character of each command line must be a TAB.
1286 \begin_layout LyX-Code
1287 target: pre-requisite
1288 \begin_inset Newline newline
1292 \begin_inset Newline newline
1298 \begin_layout Standard
1299 But a TAB is pretty hard to enter into most of the Lyx formats and insets
1301 An alternative is to use a semi-colon after the pre-requisite, and a backslash
1302 at the end of each line (except the last).
1303 Then any whitespace (or none) can prefix each action.
1306 \begin_layout LyX-Code
1307 target: pre-requisite ;
1310 \begin_inset Newline newline
1316 \begin_inset Newline newline
1322 \begin_layout Standard
1323 This is the style that we use and it works pretty well for GNU make at least.
1326 \begin_layout Standard
1327 We also adopt a convention that code chunks whose names beginning with ./
1328 should always be automatically extracted from the document.
1329 Code chunks whose names do not begin with ./ are for internal reference.
1330 (This doesn't prevent such chunks from being extracted directly).
1333 \begin_layout Section
1334 Boot-strapping the extraction
1337 \begin_layout Subsection
1341 \begin_layout Standard
1342 \begin_inset CommandInset label
1344 name "sub:Bootstrap-Using-a-Makefile"
1348 It seems convenient to have the makefile extract or update the C source
1349 files as part of it's operation.
1350 It also seems convenient to have the makefile itself extracted from this
1354 \begin_layout Standard
1355 It would also be convenient to have the code to extract the makefile from
1356 this document to also be part of this document, however we have to start
1357 somewhere and this unfortunately requires us to type at least a few words
1358 by hand to start things off.
1361 \begin_layout Standard
1362 Therefore we will have a minimal root fragment, which, when extracted, can
1363 cope with extracting the rest of the source.
1364 perhaps with this shell script, which could be called
1369 \begin_inset Note Note
1372 \begin_layout Plain Layout
1373 FIX THIS CHUNK AND TEST IT
1385 \begin_layout Standard
1386 \begin_inset listings
1390 \begin_layout Plain Layout
1395 \begin_layout Plain Layout
1399 \begin_layout Plain Layout
1401 MAKE_SRC="${1:-${NW_LYX:-../../noweb-lyx/noweb-lyx3.lyx}}"
1404 \begin_layout Plain Layout
1406 MAKE_SRC=`dirname "$MAKE_SRC"`/`basename "$MAKE_SRC" .lyx`
1409 \begin_layout Plain Layout
1411 NOWEB_SRC="${2:-${NOWEB_SRC:-$MAKE_SRC.lyx}}"
1414 \begin_layout Plain Layout
1416 lyx -e latex $MAKE_SRC
1419 \begin_layout Plain Layout
1423 \begin_layout Plain Layout
1425 newfangle -R./Makefile.inc ${MAKE_SRC}.tex
1430 \begin_layout Plain Layout
1432 | sed "/NEWFANGLE_SOURCE=/s/^/#/;T;aNOWEB_SOURCE=$NEWFANGLE_SRC"
1437 \begin_layout Plain Layout
1439 | cpif ./Makefile.inc
1442 \begin_layout Plain Layout
1446 \begin_layout Plain Layout
1448 make -f ./Makefile.inc newfangle_sources
1456 \begin_layout Standard
1457 The general Makefile can be invoked with
1461 and can also be included into any automake file to automatically re-generate
1465 \begin_layout Standard
1470 can be extracted with this command:
1473 \begin_layout LyX-Code
1474 lyx -e latex newfangle.lyx &&
1479 \begin_layout LyX-Code
1480 newfangle newfangle.lyx > ./autoboot
1483 \begin_layout Standard
1484 This looks simple enough, but as mentioned, newfangle has to be had from
1485 somewhere before it can be extracted.
1488 \begin_layout Subsection
1489 \begin_inset Note Note
1492 \begin_layout Plain Layout
1493 MERGE THIS WITH THE SECTIONS OF THIS DOCUMENT
1498 \SpecialChar \ldots{}
1502 \begin_layout Standard
1503 When the lyx-build chunk is executed, the current directory will be a temporary
1505 \begin_inset Flex CharStyle:Code
1508 \begin_layout Plain Layout
1514 will refer to the tex file in this temporary directory.
1515 This is unfortunate as our makefile wants to run from the project directory
1516 where the Lyx file is kept.
1519 \begin_layout Standard
1520 We can extract the project directory from $$r, and derive the probable Lyx
1521 filename from the noweb file that Lyx generated.
1528 \begin_layout Standard
1529 \begin_inset listings
1533 \begin_layout Plain Layout
1535 PROJECT_DIR="$LYX_r"
1538 \begin_layout Plain Layout
1540 LYX_SRC="$PROJECT_DIR/${LYX_i%.tex}.lyx"
1543 \begin_layout Plain Layout
1548 \begin_layout Plain Layout
1550 TEX_SRC="$TEX_DIR/$LYX_i"
1558 \begin_layout Standard
1559 And then we can define a lyx-build fragment similar to the autoboot fragment
1566 \begin_layout Standard
1567 \begin_inset listings
1571 \begin_layout Plain Layout
1576 \begin_layout Plain Layout
1580 chunkref{lyx-build-helper}>
1583 \begin_layout Plain Layout
1585 cd $PROJECT_DIR || exit 1
1588 \begin_layout Plain Layout
1592 \begin_layout Plain Layout
1594 #/usr/bin/newfangle -filter ./notanglefix-filter
1599 \begin_layout Plain Layout
1601 # -R./Makefile.inc "../../noweb-lyx/noweb-lyx3.lyx"
1606 \begin_layout Plain Layout
1608 # | sed '/NOWEB_SOURCE=/s/=.*/=samba4-dfs.lyx/'
1613 \begin_layout Plain Layout
1618 \begin_layout Plain Layout
1623 \begin_layout Plain Layout
1625 #make -f ./Makefile.inc newfangle_sources
1633 \begin_layout Section
1637 \begin_layout Subsection
1638 Including Makefile.inc
1641 \begin_layout Standard
1642 \begin_inset CommandInset label
1644 name "sub:Keeping-extracted-files"
1648 Makefile.inc will cope with extracting all the other source files from this
1649 document and keeping them up to date.
1653 \begin_layout Standard
1654 It may also be included by a Makefile or Makefile.am defined in a Lyx document
1655 to automatically deal with the extraction of source files and documents.
1658 \begin_layout Standard
1659 A makefile has two parts; variables must be defined before the targets that
1667 \begin_layout Standard
1668 \begin_inset listings
1672 \begin_layout Plain Layout
1676 chunkref{Makefile.inc-vars}>
1679 \begin_layout Plain Layout
1683 chunkref{Makefile.inc-targets}>
1691 \begin_layout Standard
1693 \begin_inset Flex CharStyle:Code
1696 \begin_layout Plain Layout
1702 to hold the name of this Lyx file.
1709 \begin_layout Standard
1710 \begin_inset listings
1714 \begin_layout Plain Layout
1719 \begin_layout Plain Layout
1721 LITERATE_SOURCE=$(LYX_SOURCE)
1729 \begin_layout Subsection
1730 Recursive use of Makefile.inc
1733 \begin_layout Standard
1734 The makefile glue described here is used when building Samba4 vfs modules.
1737 \begin_layout Standard
1738 If you are defining a module of an existing program you may find it easier
1739 to use a slight recursive make instead of including the makefile directly.
1740 This way there is less chance of definitions in Makefile.inc interfering
1741 with definitions in the main makefile, or with definitions in other Makefile.inc
1742 from other noweb modules.
1745 \begin_layout Standard
1746 The glue works by adding a .PHONY target to call the recursive make, and
1747 adding this target as an additional pre-requisite to the existing targets.
1750 \begin_layout Standard
1751 In this example, the existing build system already has a build target for
1753 \begin_inset Flex CharStyle:Code
1756 \begin_layout Plain Layout
1762 , so we just add another pre-requisite to that.
1764 \begin_inset Flex CharStyle:Code
1767 \begin_layout Plain Layout
1773 as a pre-requisite, the stamp file's modified time indicating when all
1774 sources were extracted.
1781 \begin_layout Standard
1782 \begin_inset listings
1786 \begin_layout Plain Layout
1788 $(example_srcdir)/example.o: $(example_srcdir)/example.tex.stamp
1796 \begin_layout Standard
1797 The target for this new pre-requisite is generated by a recursive make using
1798 Makefile.inc which will make sure that the source is up to date, before
1799 it is built by the main projects makefile.
1806 \begin_layout Standard
1807 \begin_inset listings
1811 \begin_layout Plain Layout
1813 $(example_srcdir)/example.tex.stamp: $(example_srcdir)/example.tex ;
1818 \begin_layout Plain Layout
1820 cd $(example_srcdir) &&
1825 \begin_layout Plain Layout
1827 $(MAKE) -f Makefile.inc newfangle_sources
1835 \begin_layout Standard
1836 We can do similar glue for the docs, clean and distclean targets.
1837 In this example our build system is using a double colon for these targets,
1838 so we use the same in our glue.
1845 \begin_layout Standard
1846 \begin_inset listings
1850 \begin_layout Plain Layout
1855 \begin_layout Plain Layout
1857 .PHONY: docs_example
1860 \begin_layout Plain Layout
1862 docs_example:: ; cd $(example_srcdir) &&
1867 \begin_layout Plain Layout
1869 $(MAKE) -f Makefile.inc docs
1872 \begin_layout Plain Layout
1876 \begin_layout Plain Layout
1878 clean:: clean_example
1881 \begin_layout Plain Layout
1883 .PHONEY: clean_example
1886 \begin_layout Plain Layout
1888 clean_example: ; cd $(example_srcdir) &&
1893 \begin_layout Plain Layout
1895 $(MAKE) -f Makefile.inc clean
1898 \begin_layout Plain Layout
1902 \begin_layout Plain Layout
1904 distclean:: distclean_example
1907 \begin_layout Plain Layout
1909 .PHONY: distclean_example
1912 \begin_layout Plain Layout
1914 distclean_example: ; cd $(example_srcdir) &&
1919 \begin_layout Plain Layout
1921 $(MAKE) -f Makefile.inc distclean
1929 \begin_layout Standard
1930 We could do similarly for install targets to install the generated docs.
1933 \begin_layout Subsection
1934 \begin_inset CommandInset label
1936 name "sub:Converting-from-Lyx"
1940 Converting from Lyx to LaTeX
1943 \begin_layout Standard
1944 The first stage will always be to convert the Lyx file to a LaTeX file;
1945 this must be so not only because newfangle needs to to run on a TeX file,
1946 but also because the Lyx command
1948 server-goto-file-line
1952 \begin_layout Plain Layout
1955 server-goto-file-line
1957 is used to position the Lyx cursor at the compiler errors.
1964 insists that the line number provided is a line in the TeX file, and always
1965 reverse maps this to derive the line in the Lyx docment.
1966 \begin_inset Note Note
1969 \begin_layout Plain Layout
1970 The tex file should probably be an automake extra dist sources or something,
1971 so that it gets produced and packaged by make dist
1979 \begin_layout Standard
1980 The command [[lyx -e literate noweb-lyx.lyx]] will produce [[noweb-lyx.nw]]
1981 a tex file, so we define the noweb target to be the same as the Lyx file
1982 but with the .nw extension.
1989 \begin_layout Standard
1990 \begin_inset listings
1994 \begin_layout Plain Layout
1996 TEX_SOURCE=$(LYX_SOURCE:.lyx=.tex)
2005 Makefile.inc-targets
2008 \begin_layout Standard
2009 \begin_inset listings
2013 \begin_layout Plain Layout
2015 $(TEX_SOURCE): $(LYX_SOURCE) ;
2020 \begin_layout Plain Layout
2025 \begin_layout Plain Layout
2027 clean_tex: ; rm -f -- $(TEX_SOURCE)
2035 \begin_layout Subsection
2036 Extracting Program Source
2039 \begin_layout Standard
2040 The program source is extracted using newfangle, which is designed to operate
2041 on a LaTeX document.
2049 \begin_layout Standard
2050 \begin_inset listings
2054 \begin_layout Plain Layout
2056 NEWFANGLE_SOURCE=$(TEX_SOURCE)
2064 \begin_layout Standard
2065 The Lyx document can result in any number of source documents, but not all
2066 of these will be changed each time the Lyx document is updated.
2067 We certainly don't want to update the timestamps of these files and cause
2068 the whole source tree to be recompiled just because the Lyx document was
2073 \begin_layout Standard
2074 To solve this problem we use a stamp file which is always updated each time
2075 the sources are extracted from the LaTeX document.
2076 If the stamp file is older than the LaTeX document, then we can make an
2077 attempt to re-extract the sources.
2084 \begin_layout Standard
2085 \begin_inset listings
2089 \begin_layout Plain Layout
2091 NEWFANGLE_SOURCE_STAMP=$(NEWFANGLE_SOURCE).stamp
2100 Makefile.inc-targets
2103 \begin_layout Standard
2104 \begin_inset listings
2108 \begin_layout Plain Layout
2110 $(NEWFANGLE_SOURCE_STAMP): $(NEWFANGLE_SOURCE)
2115 \begin_layout Plain Layout
2117 $(NEWFANGLE_SOURCES) ;
2122 \begin_layout Plain Layout
2124 echo > $(NEWFANGLE_SOURCE_STAMP)
2127 \begin_layout Plain Layout
2129 clean_stamp: ; rm -f $(NEWFANGLE_SOURCE_STAMP)
2132 \begin_layout Plain Layout
2142 \begin_layout Subsection
2143 Extracting C sources
2146 \begin_layout Standard
2148 \begin_inset Flex CharStyle:Code
2151 \begin_layout Plain Layout
2157 to hold the names of all the C source files defined in this document.
2158 We compute this only once, by means of := in assignent.
2159 The sed deletes the any <
2160 \begin_inset space \hspace*{}
2165 \begin_inset space \hspace*{}
2169 > which may surround the roots names (for noroots compatibility).
2173 \begin_layout Standard
2174 As we use chunk names beginning with ./ to denote top level fragments that
2175 should be extracted, we filter out all fragments that do not begin with
2183 \begin_layout Standard
2184 \begin_inset listings
2188 \begin_layout Plain Layout
2197 \begin_layout Plain Layout
2199 NEWFANGLE_SOURCES:=$(shell
2204 \begin_layout Plain Layout
2206 newfangle -r $(NEWFANGLE_SOURCE) |
2211 \begin_layout Plain Layout
2213 sed -e 's/^[<][<]//;s/[>][>]$$//;/^$(NEWFANGLE_PREFIX)/!d'
2218 \begin_layout Plain Layout
2220 -e 's/^$(NEWFANGLE_PREFIX)/
2227 \begin_layout Plain Layout
2238 Makefile.inc-targets
2241 \begin_layout Standard
2242 \begin_inset listings
2246 \begin_layout Plain Layout
2248 .PHONY: echo_newfangle_sources
2251 \begin_layout Plain Layout
2253 echo_newfangle_sources: ; @echo $(NEWFANGLE_SOURCES)
2261 \begin_layout Standard
2262 We define a convenient target called
2263 \begin_inset Flex CharStyle:Code
2266 \begin_layout Plain Layout
2272 to re-extract the source if the LaTeX file has been updated.
2276 Makefile.inc-targets
2279 \begin_layout Standard
2280 \begin_inset listings
2284 \begin_layout Plain Layout
2286 .PHONY: newfangle_sources
2289 \begin_layout Plain Layout
2291 newfangle_sources: $(NEWFANGLE_SOURCE_STAMP)
2299 \begin_layout Standard
2300 And also a convenient target to remove extracted sources.
2304 Makefile.inc-targets
2307 \begin_layout Standard
2308 \begin_inset listings
2312 \begin_layout Plain Layout
2314 .PHONY: clean_newfangle_sources
2317 \begin_layout Plain Layout
2319 clean_newfangle_sources: ;
2324 \begin_layout Plain Layout
2326 rm -f -- $(NEWFANGLE_SOURCE_STAMP) $(NEWFANGLE_SOURCES)
2334 \begin_layout Standard
2336 \begin_inset Flex CharStyle:Code
2339 \begin_layout Plain Layout
2345 macro takes 4 arguments: the filename (1), some extensions to match (2)
2346 and a some shell command to return if the filename matches the exentions
2354 \begin_layout Standard
2355 \begin_inset listings
2359 \begin_layout Plain Layout
2361 if_extension=$(if $(findstring $(suffix $(1)),$(2)),$(3),$(4))
2369 \begin_layout Standard
2370 For some source files like C files, we want to output the line number and
2371 filename of the original LaTeX document from which the source came.
2374 \begin_layout Standard
2375 To make this easier we define the file extensions for which we want to do
2383 \begin_layout Standard
2384 \begin_inset listings
2388 \begin_layout Plain Layout
2398 \begin_layout Standard
2399 We can then use the if_extensions macro to define a macro which expands
2401 \begin_inset Flex CharStyle:Code
2404 \begin_layout Plain Layout
2410 option if newfangle is being invoked in a C source file, so that C compile
2411 errors will refer to the line number in the Lyx document.
2419 \begin_layout Standard
2420 \begin_inset listings
2424 \begin_layout Plain Layout
2429 \begin_layout Plain Layout
2431 nf_line=-L -T$(TABS)
2434 \begin_layout Plain Layout
2441 \begin_layout Plain Layout
2443 $(call if_extension,$(2),$(C_EXTENSIONS),$(nf_line))
2448 \begin_layout Plain Layout
2458 \begin_layout Standard
2459 We can use a similar trick to define an
2463 macro which takes just the filename as an argument and can return a pipeline
2464 stage calling the indent command.
2465 Indent can be turned off with
2466 \begin_inset Flex CharStyle:Code
2469 \begin_layout Plain Layout
2470 make newfangle_sources indent=
2482 \begin_layout Standard
2483 \begin_inset listings
2487 \begin_layout Plain Layout
2489 indent_options=-npro -kr -i8 -ts8 -sob -l80 -ss -ncs
2492 \begin_layout Plain Layout
2494 indent=$(call if_extension,$(1),$(C_EXTENSIONS),
2499 \begin_layout Plain Layout
2501 | indent $(indent_options))
2509 \begin_layout Standard
2510 We now define the pattern for extracting a file.
2511 The files are written using noweb's
2517 \begin_layout Plain Layout
2520 So you still need noweb installed in order to use cpif
2526 \begin_inset Note Note
2529 \begin_layout Plain Layout
2532 Write an awk version
2539 so that the file timestamp will not be touched if the contents haven't
2541 This avoids the need to rebuild the entire project because of a typographical
2542 change in the documentation, or if only a few C source files have changed.
2549 \begin_layout Standard
2550 \begin_inset listings
2554 \begin_layout Plain Layout
2556 newfangle_extract=@mkdir -p $(dir $(1)) &&
2561 \begin_layout Plain Layout
2563 $(call newfangle,$(2),$(1)) > "$(1).tmp" &&
2568 \begin_layout Plain Layout
2570 cat "$(1).tmp" $(indent) | cpif "$(1)"
2575 \begin_layout Plain Layout
2577 && rm -- "$(1).tmp" ||
2582 \begin_layout Plain Layout
2584 (echo error newfangling $(1) from $(2) ; exit 1)
2592 \begin_layout Standard
2593 We define a target which will extract or update all sources.
2594 To do this we first defined a makefile template that can do this for any
2595 source file in the LaTeX document.
2602 \begin_layout Standard
2603 \begin_inset listings
2607 \begin_layout Plain Layout
2609 define NEWFANGLE_template
2612 \begin_layout Plain Layout
2619 \begin_layout Plain Layout
2621 $$(call newfangle_extract,$(1),$(2))
2624 \begin_layout Plain Layout
2626 NEWFANGLE_TARGETS+=$(1)
2629 \begin_layout Plain Layout
2639 \begin_layout Standard
2640 We then enumerate the discovered
2641 \begin_inset Flex CharStyle:Code
2644 \begin_layout Plain Layout
2650 to generate a makefile rule for each one using the makefile template we
2655 Makefile.inc-targets
2658 \begin_layout Standard
2659 \begin_inset listings
2663 \begin_layout Plain Layout
2665 $(foreach source,$(NEWFANGLE_SOURCES),
2670 \begin_layout Plain Layout
2672 $(eval $(call NEWFANGLE_template,$(source),$(NEWFANGLE_SOURCE)))
2677 \begin_layout Plain Layout
2687 \begin_layout Standard
2688 These will all be built with NEWFANGLE_SOURCE_STAMP.
2691 \begin_layout Standard
2692 We also remove the generated sources on a
2700 Makefile.inc-targets
2703 \begin_layout Standard
2704 \begin_inset listings
2708 \begin_layout Plain Layout
2710 _distclean: clean_newfangle_sources
2718 \begin_layout Subsection
2719 Extracting Documentation
2722 \begin_layout Standard
2723 We then identify the intermediate stages of the documentation and their
2724 build and clean targets.
2727 \begin_layout Subsubsection
2731 \begin_layout Standard
2732 We produce a pdf file from the tex file.
2739 \begin_layout Standard
2740 \begin_inset listings
2744 \begin_layout Plain Layout
2746 NEWFANGLE_PDF=$(TEX_SOURCE:.tex=.pdf)
2754 \begin_layout Standard
2755 We run pdflatex twice to be sure that the contents and aux files are up
2757 We certainly are required to run pdflatex twice if these files do not exist!
2761 Makefile.inc-targets
2764 \begin_layout Standard
2765 \begin_inset listings
2769 \begin_layout Plain Layout
2771 $(NEWFANGLE_PDF): $(TEX_SOURCE); pdflatex $< && pdflatex $<
2774 \begin_layout Plain Layout
2776 clean_pdf: ; rm -f -- $(NEWFANGLE_PDF)
2781 \begin_layout Plain Layout
2783 $(TEX_SOURCE:.tex=.toc)
2788 \begin_layout Plain Layout
2790 $(TEX_SOURCE:.tex=.log)
2795 \begin_layout Plain Layout
2797 $(TEX_SOURCE:.tex=.aux)
2805 \begin_layout Subsubsection
2809 \begin_layout Standard
2810 Currently we only build pdf as a final format, but NEWFANGLE_DOCS may later
2811 hold other output formats.
2818 \begin_layout Standard
2819 \begin_inset listings
2823 \begin_layout Plain Layout
2825 NEWFANGLE_DOCS=$(NEWFANGLE_PDF)
2833 \begin_layout Standard
2834 We also define newfangle_docs as a convenient phony target<
2838 Makefile.inc-targets
2841 \begin_layout Standard
2842 \begin_inset listings
2846 \begin_layout Plain Layout
2848 .PHONY: newfangle_docs
2851 \begin_layout Plain Layout
2853 newfangle_docs: $(NEWFANGLE_DOCS)
2856 \begin_layout Plain Layout
2858 docs: newfangle_docs
2866 \begin_layout Standard
2867 And define a convenient clean_noweb_docs which we add to the regular clean
2872 Makefile.inc-targets
2875 \begin_layout Standard
2876 \begin_inset listings
2880 \begin_layout Plain Layout
2882 .PHONEY: clean_newfangle_docs
2885 \begin_layout Plain Layout
2887 clean_newfangle_docs: clean_tex clean_pdf
2890 \begin_layout Plain Layout
2892 clean: clean_newfangle_docs
2895 \begin_layout Plain Layout
2899 \begin_layout Plain Layout
2901 distclean_newfangle_docs: clean_tex clean_newfangle_docs
2904 \begin_layout Plain Layout
2906 distclean: clean distclean_newfangle_docs
2914 \begin_layout Subsection
2918 \begin_layout Standard
2919 If Makefile.inc is included into Makefile, then extracted files can be updated
2923 \begin_layout LyX-Code
2924 make newfangle_sources
2927 \begin_layout Standard
2931 \begin_layout LyX-Code
2932 make -f Makefile.inc newfangle_sources
2939 \begin_layout Chapter
2940 Newfangle awk source code
2943 \begin_layout Standard
2944 We use the copyright notice from chapter
2945 \begin_inset CommandInset ref
2947 reference "cha:License"
2955 ./newfangle,language=awk,morestring=[b]{/},morekeywords=else
2958 \begin_layout Standard
2959 \begin_inset listings
2963 \begin_layout Plain Layout
2968 \begin_layout Plain Layout
2972 chunkref{gpl3-copyright}>
2975 \begin_layout Plain Layout
2984 \begin_layout Standard
2985 We also use code from Arnold Robbins public domain getopt (1993 revision)
2987 \begin_inset CommandInset ref
2989 reference "cha:getopt"
2993 , and naturally want to attribute this appropriately.
2996 \begin_layout Standard
2997 \begin_inset listings
3001 \begin_layout Plain Layout
3005 \begin_layout Plain Layout
3007 # NOTE: Arnold Robbins public domain getopt for awk is also used:
3010 \begin_layout Plain Layout
3014 chunkref{getopt.awk-header}>
3017 \begin_layout Plain Layout
3021 \begin_layout Plain Layout
3025 chunkref{getopt.awk-getopt()}>
3028 \begin_layout Plain Layout
3037 \begin_layout Standard
3038 And include the following chunks
3045 \begin_layout Standard
3046 \begin_inset listings
3050 \begin_layout Plain Layout
3054 chunkref{helper-functions}>
3057 \begin_layout Plain Layout
3061 chunkref{mode-tracker}>
3064 \begin_layout Plain Layout
3068 chunkref{parse_chunk_args}>
3071 \begin_layout Plain Layout
3075 chunkref{chunk-storage-functions}>
3078 \begin_layout Plain Layout
3082 chunkref{output_chunk_names()}>
3085 \begin_layout Plain Layout
3089 chunkref{output_chunks()}>
3092 \begin_layout Plain Layout
3096 chunkref{write_chunk()}>
3099 \begin_layout Plain Layout
3103 chunkref{expand_chunk_args()}>
3106 \begin_layout Plain Layout
3113 \begin_layout Plain Layout
3117 chunkref{recognize-chunk}>
3120 \begin_layout Plain Layout
3132 \begin_layout Section
3136 \begin_layout Standard
3137 The portable way to erase an array in awk is to split the empty string,
3142 awk-delete-array,params=ARRAY
3145 \begin_layout Standard
3146 \begin_inset listings
3150 \begin_layout Plain Layout
3152 split("", ${ARRAY});
3161 dump-array,params=ARRAY
3164 \begin_layout Standard
3165 \begin_inset listings
3169 \begin_layout Plain Layout
3180 \begin_layout Plain Layout
3182 for (_x in ${ARRAY}) {
3185 \begin_layout Plain Layout
3187 print _x "=" ${ARRAY}[_x] "
3192 \begin_layout Plain Layout
3197 \begin_layout Plain Layout
3213 \begin_layout Section
3217 \begin_layout Standard
3218 Fatal errors are issued with the error function:
3222 error(),append=helper-functions
3225 \begin_layout Standard
3226 \begin_inset listings
3230 \begin_layout Plain Layout
3232 function error(message)
3235 \begin_layout Plain Layout
3240 \begin_layout Plain Layout
3242 print "ERROR: " FILENAME ":" FNR " " message > "/dev/stderr";
3245 \begin_layout Plain Layout
3250 \begin_layout Plain Layout
3260 \begin_layout Standard
3261 \begin_inset listings
3265 \begin_layout Plain Layout
3267 function warning(message)
3270 \begin_layout Plain Layout
3275 \begin_layout Plain Layout
3277 print "WARNING: " FILENAME ":" FNR " " message > "/dev/stderr";
3280 \begin_layout Plain Layout
3285 \begin_layout Plain Layout
3295 \begin_layout Chapter
3299 \begin_layout Standard
3300 LaTeX arguments to lstlistings macros are a comma seperated list of key-value
3302 Values containing commas are enclosed in
3303 \begin_inset Flex CharStyle:Code
3306 \begin_layout Plain Layout
3313 \begin_inset Flex CharStyle:Code
3316 \begin_layout Plain Layout
3322 , which is to be expected for LaTeX.
3325 \begin_layout Standard
3326 A sample expressions is:
3329 \begin_layout LyX-Code
3330 name=thomas, params={a, b}, something, something-else
3333 \begin_layout Standard
3334 but we see that this is just a simpler form of this expression:
3337 \begin_layout LyX-Code
3338 name=freddie, foo={bar=baz, quux={quirk, a=fleeg}}, etc
3341 \begin_layout Standard
3342 We may consider that we need a function that can parse such LaTeX expressions
3343 and assign the values to an
3347 associated array, perhaps using a recursive parser into a multi-dimensional
3352 \begin_layout Plain Layout
3353 as AWK doesn't have nested-hash support
3361 \begin_layout Standard
3362 \begin_inset Tabular
3363 <lyxtabular version="3" rows="6" columns="2">
3365 <column alignment="left" valignment="top" width="0">
3366 <column alignment="left" valignment="top" width="0">
3368 <cell alignment="center" valignment="top" topline="true" bottomline="true" leftline="true" usebox="none">
3371 \begin_layout Plain Layout
3377 <cell alignment="center" valignment="top" topline="true" bottomline="true" leftline="true" rightline="true" usebox="none">
3380 \begin_layout Plain Layout
3388 <cell alignment="left" valignment="top" topline="true" leftline="true" usebox="none">
3391 \begin_layout Plain Layout
3397 <cell alignment="left" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
3400 \begin_layout Plain Layout
3408 <cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
3411 \begin_layout Plain Layout
3417 <cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
3420 \begin_layout Plain Layout
3428 <cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
3431 \begin_layout Plain Layout
3437 <cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
3440 \begin_layout Plain Layout
3448 <cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
3451 \begin_layout Plain Layout
3457 <cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
3460 \begin_layout Plain Layout
3468 <cell alignment="center" valignment="top" topline="true" bottomline="true" leftline="true" usebox="none">
3471 \begin_layout Plain Layout
3477 <cell alignment="center" valignment="top" topline="true" bottomline="true" leftline="true" rightline="true" usebox="none">
3480 \begin_layout Plain Layout
3494 \begin_layout Standard
3495 Oon reflection it seems that sometimes such nesting is not desirable, as
3496 the braces are also used to delimit values that contain commas --- we may
3500 \begin_layout LyX-Code
3501 name={williamson, freddie}
3504 \begin_layout Standard
3506 \begin_inset Flex CharStyle:Code
3509 \begin_layout Plain Layout
3516 \begin_inset Flex CharStyle:Code
3519 \begin_layout Plain Layout
3528 \begin_layout Standard
3529 In fact we are not so interested in the detail so as to be bothered by this,
3530 which turns out to be a good thing for two reasons.
3531 Firstly LaTeX has a malleable parser with no strict syntax, and secondly
3533 \begin_inset Flex CharStyle:Code
3536 \begin_layout Plain Layout
3543 \begin_inset Flex CharStyle:Code
3546 \begin_layout Plain Layout
3552 should count as two items will be context dependant anyway.
3555 \begin_layout Standard
3556 We need to parse this latex for only one reason; which is that we are extending
3557 lstlistings to add some additional arguments which will be used to express
3558 chunk parameters and other chunk options.
3561 \begin_layout Section
3562 Additional lstlstings parameters
3565 \begin_layout Standard
3566 Further on we define a
3567 \begin_inset Flex CharStyle:Code
3570 \begin_layout Plain Layout
3578 LaTeX macro whose arguments will consist of a the chunk name, optionally
3579 followed by a comma and then a comma separated list of arguments.
3580 In fact we will just need to prefix
3581 \begin_inset Flex CharStyle:Code
3584 \begin_layout Plain Layout
3590 to the arguments to in order to create valid lstlistings arguments.
3594 \begin_layout Standard
3595 There will be other arguments supported too;
3598 \begin_layout Description
3599 params As an extension to many literate-programming styles, newfangle permits
3600 code chunks to take parameters and thus operate somewhat like C pre-processor
3601 macros, or like C++ templates.
3602 Chunk parameters are declared with a chunk argument called
3603 \begin_inset Flex CharStyle:Code
3606 \begin_layout Plain Layout
3612 , which holds a semi-colon separated list of parameters, like this:
3615 \begin_layout LyX-Code
3616 achunk,language=C,params=name;address
3619 \begin_layout Description
3620 addto a named chunk that this chunk is to be included into.
3621 This saves the effort of having to declare another listing of the named
3622 chunk merely to include this one.
3625 \begin_layout Standard
3627 \begin_inset Flex Chunkref
3630 \begin_layout Plain Layout
3636 will accept two paramters,
3637 \begin_inset Flex CharStyle:Code
3640 \begin_layout Plain Layout
3646 being the text to parse, and
3647 \begin_inset Flex CharStyle:Code
3650 \begin_layout Plain Layout
3656 being an array to receive the parsed values as described above.
3657 The optional parameter
3658 \begin_inset Flex CharStyle:Code
3661 \begin_layout Plain Layout
3667 is used during recursion to build up the multi-dimensional array path.
3674 \begin_layout Standard
3675 \begin_inset listings
3679 \begin_layout Plain Layout
3683 chunkref{get_chunk_args()}>
3695 \begin_layout Standard
3696 \begin_inset listings
3700 \begin_layout Plain Layout
3702 function get_chunk_args(text, values,
3705 \begin_layout Plain Layout
3707 # optional parameters
3710 \begin_layout Plain Layout
3712 path, # hierarchical precursors
3715 \begin_layout Plain Layout
3720 \begin_layout Plain Layout
3730 \begin_layout Standard
3731 The strategy is to parse the name, and then look for a value.
3732 If the value begins with a brace
3733 \begin_inset Flex CharStyle:Code
3736 \begin_layout Plain Layout
3742 , then we recurse and consume as much of the text as necessary, returning
3743 the remaining text when we encounter a leading close-brace
3744 \begin_inset Flex CharStyle:Code
3747 \begin_layout Plain Layout
3754 This being the strategy --- and executed in a loop --- we realise that
3755 we must first look for the closing brace (perhaps preceded by white space)
3756 in order to terminate the recursion, and returning remaining text.
3759 \begin_layout Standard
3760 \begin_inset listings
3764 \begin_layout Plain Layout
3769 \begin_layout Plain Layout
3771 split("", next_chunk_args);
3774 \begin_layout Plain Layout
3776 while(length(text)) {
3779 \begin_layout Plain Layout
3781 if (match(text, "^ *}(.*)", a)) {
3784 \begin_layout Plain Layout
3789 \begin_layout Plain Layout
3794 \begin_layout Plain Layout
3798 chunkref{parse-chunk-args}>
3801 \begin_layout Plain Layout
3806 \begin_layout Plain Layout
3811 \begin_layout Plain Layout
3821 \begin_layout Standard
3822 \begin_inset Note Note
3825 \begin_layout Plain Layout
3826 Use BNF package here
3831 We can see that the text could be inspected with this regex:
3838 \begin_layout Standard
3839 \begin_inset listings
3843 \begin_layout Plain Layout
3845 if (! match(text, " *([^,=]*[^,= ]) *(([,=]) *(([^,}]*) *,* *(.*))|)$", a))
3849 \begin_layout Plain Layout
3854 \begin_layout Plain Layout
3864 \begin_layout Standard
3866 \begin_inset Flex CharStyle:Code
3869 \begin_layout Plain Layout
3875 will have the following values:
3878 \begin_layout Standard
3879 \begin_inset Tabular
3880 <lyxtabular version="3" rows="7" columns="2">
3882 <column alignment="center" valignment="top" width="0">
3883 <column alignment="left" valignment="top" width="0">
3885 <cell alignment="center" valignment="top" topline="true" bottomline="true" leftline="true" usebox="none">
3888 \begin_layout Plain Layout
3894 <cell alignment="center" valignment="top" topline="true" bottomline="true" leftline="true" rightline="true" usebox="none">
3897 \begin_layout Plain Layout
3905 <cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
3908 \begin_layout Plain Layout
3914 <cell alignment="left" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
3917 \begin_layout Plain Layout
3925 <cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
3928 \begin_layout Plain Layout
3934 <cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
3937 \begin_layout Plain Layout
3938 =freddie, foo={bar=baz, quux={quirk, a=fleeg}}, etc
3945 <cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
3948 \begin_layout Plain Layout
3954 <cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
3957 \begin_layout Plain Layout
3965 <cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
3968 \begin_layout Plain Layout
3974 <cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
3977 \begin_layout Plain Layout
3978 freddie, foo={bar=baz, quux={quirk, a=fleeg}}, etc
3985 <cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
3988 \begin_layout Plain Layout
3994 <cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
3997 \begin_layout Plain Layout
4005 <cell alignment="center" valignment="top" topline="true" bottomline="true" leftline="true" usebox="none">
4008 \begin_layout Plain Layout
4014 <cell alignment="center" valignment="top" topline="true" bottomline="true" leftline="true" rightline="true" usebox="none">
4017 \begin_layout Plain Layout
4018 , foo={bar=baz, quux={quirk, a=fleeg}}, etc
4031 \begin_layout Standard
4033 \begin_inset Flex CharStyle:Code
4036 \begin_layout Plain Layout
4043 \begin_inset Flex CharStyle:Code
4046 \begin_layout Plain Layout
4052 and signify whether the option named in
4053 \begin_inset Flex CharStyle:Code
4056 \begin_layout Plain Layout
4062 has a value or not (respectively).
4065 \begin_layout Standard
4066 If the option does have a value, then if the expression
4067 \begin_inset Flex CharStyle:Code
4070 \begin_layout Plain Layout
4077 \begin_inset Flex CharStyle:Code
4080 \begin_layout Plain Layout
4086 it will signify that we need to recurse:
4089 \begin_layout Standard
4090 \begin_inset listings
4094 \begin_layout Plain Layout
4099 \begin_layout Plain Layout
4104 \begin_layout Plain Layout
4106 if (substr(a[4],1,1) == "{") {
4109 \begin_layout Plain Layout
4111 text = get_chunk_args(substr(a[4],2), values, path name SUBSEP);
4114 \begin_layout Plain Layout
4119 \begin_layout Plain Layout
4121 values[path name]=a[5];
4124 \begin_layout Plain Layout
4129 \begin_layout Plain Layout
4134 \begin_layout Plain Layout
4139 \begin_layout Plain Layout
4141 values[path name]="";
4144 \begin_layout Plain Layout
4149 \begin_layout Plain Layout
4159 \begin_layout Standard
4160 We can test this function like this:
4167 \begin_layout Standard
4168 \begin_inset listings
4172 \begin_layout Plain Layout
4176 chunkref{get_chunk_args()}>
4179 \begin_layout Plain Layout
4184 \begin_layout Plain Layout
4189 \begin_layout Plain Layout
4193 \begin_layout Plain Layout
4195 print get_chunk_args("name=freddie, foo={bar=baz, quux={quirk, a=fleeg}},
4199 \begin_layout Plain Layout
4204 \begin_layout Plain Layout
4206 print "a[" b "] => " a[b];
4209 \begin_layout Plain Layout
4214 \begin_layout Plain Layout
4224 \begin_layout Standard
4225 which should give this output:
4229 gca-test.awk-results
4232 \begin_layout Standard
4233 \begin_inset listings
4237 \begin_layout Plain Layout
4239 a[foo.quux.quirk] =>
4242 \begin_layout Plain Layout
4244 a[foo.quux.a] => fleeg
4247 \begin_layout Plain Layout
4252 \begin_layout Plain Layout
4257 \begin_layout Plain Layout
4267 \begin_layout Section
4268 Parsing chunk arguments
4271 \begin_layout Standard
4272 \begin_inset CommandInset label
4274 name "cha:Chunk Arguments"
4281 \begin_layout Standard
4282 Arguments to paramterized chunks are expressed in round brackets as a comma
4283 separated list of optional arguments.
4284 For example, a chunk that is defined with:
4287 \begin_layout LyX-Code
4290 Chunk{achunk, params=name ; address}
4293 \begin_layout Standard
4294 could be invoked as:
4297 \begin_layout LyX-Code
4300 chunkref{achunk}(John Jones, jones@example.com)
4303 \begin_layout Standard
4304 An argument list may be as simple as in
4305 \begin_inset Flex CharStyle:Code
4308 \begin_layout Plain Layout
4311 chunkref{pull}(thing, otherthing)
4319 \begin_layout LyX-Code
4322 chunkref{pull}(things[x, y], get_other_things(a, "(all)"))
4325 \begin_layout Standard
4326 --- which for all it's commas and quotes and parenthesis represents only
4328 \begin_inset Flex CharStyle:Code
4331 \begin_layout Plain Layout
4338 \begin_inset Flex CharStyle:Code
4341 \begin_layout Plain Layout
4342 get_other_things(a, "(all)")
4350 \begin_layout Standard
4351 If we simply split parameter list on commas, then the comma in
4352 \begin_inset Flex CharStyle:Code
4355 \begin_layout Plain Layout
4361 would split into two seperate arguments:
4362 \begin_inset Flex CharStyle:Code
4365 \begin_layout Plain Layout
4372 \begin_inset Flex CharStyle:Code
4375 \begin_layout Plain Layout
4381 --- neither of which make sense on their own.
4384 \begin_layout Standard
4385 One way to prevent this would be by refusing to split text between matching
4387 \begin_inset Flex CharStyle:Code
4390 \begin_layout Plain Layout
4397 \begin_inset Flex CharStyle:Code
4400 \begin_layout Plain Layout
4407 \begin_inset Flex CharStyle:Code
4410 \begin_layout Plain Layout
4417 \begin_inset Flex CharStyle:Code
4420 \begin_layout Plain Layout
4427 \begin_inset Flex CharStyle:Code
4430 \begin_layout Plain Layout
4437 \begin_inset Flex CharStyle:Code
4440 \begin_layout Plain Layout
4446 and most likely also
4447 \begin_inset Flex CharStyle:Code
4450 \begin_layout Plain Layout
4457 \begin_inset Flex CharStyle:Code
4460 \begin_layout Plain Layout
4467 \begin_inset Flex CharStyle:Code
4470 \begin_layout Plain Layout
4477 \begin_inset Flex CharStyle:Code
4480 \begin_layout Plain Layout
4487 Of course this also makes it impossible to pass such mis-matched code fragments
4488 as parameters, but I think that it would be hard for readers to cope with
4489 authors who would pass such code unbalanced fragments as chunk parameters
4493 \begin_layout Plain Layout
4494 I know that I couldn't cope with users doing such things, and although the
4495 GPL3 license prevents me from actually forbidding anyone from trying, if
4496 they want it to work they'll have to write the code themselves and not
4497 expect any support from me.
4505 \begin_layout Standard
4506 Unfortunately, the full set of matching delimiters may vary from language
4508 In certain C++ template contexts,
4509 \begin_inset Flex CharStyle:Code
4512 \begin_layout Plain Layout
4519 \begin_inset Flex CharStyle:Code
4522 \begin_layout Plain Layout
4528 would count as delimiters, and yet in other contexts they would not.
4531 \begin_layout Standard
4532 This puts me in the unfortunate position of having to parse-somewhat all
4533 programming languages without knowing what they are!
4536 \begin_layout Standard
4537 However, if this universal mode-tracking is possible, then parsing the arguments
4539 Such a mode tracker is described in chapter
4540 \begin_inset CommandInset ref
4542 reference "cha:modes"
4546 and used here with simplicity.
4553 \begin_layout Standard
4554 \begin_inset listings
4558 \begin_layout Plain Layout
4560 function parse_chunk_args(language, text, values, mode,
4563 \begin_layout Plain Layout
4568 \begin_layout Plain Layout
4573 \begin_layout Plain Layout
4578 \begin_layout Plain Layout
4582 chunkref{new-mode-tracker}(context, language, mode)>
4585 \begin_layout Plain Layout
4587 rest = mode_tracker(context, text, values);
4590 \begin_layout Plain Layout
4595 \begin_layout Plain Layout
4597 for(c=1; c <= context[0, "values"]; c++) {
4600 \begin_layout Plain Layout
4602 values[c] = context[0, "values", c];
4605 \begin_layout Plain Layout
4610 \begin_layout Plain Layout
4615 \begin_layout Plain Layout
4625 \begin_layout Section
4626 Expanding parameters in the text
4629 \begin_layout Standard
4630 Within the body of the chunk, the parameters are referred to with:
4631 \begin_inset Flex CharStyle:Code
4634 \begin_layout Plain Layout
4641 \begin_inset Flex CharStyle:Code
4644 \begin_layout Plain Layout
4651 There is a strong case that a LaTeX style notation should be used, like
4654 param{name} which would be expressed in the listing as =<
4656 param{name}> and be rendered as
4657 \begin_inset listings
4661 \begin_layout Plain Layout
4671 Such notation would make me go blind, but I do intend to adopt it
4675 \begin_layout Plain Layout
4676 Probably when LyX's listings inset can recognize and render it, so that
4677 I no longer have to type =<\SpecialChar \ldots{}
4686 \begin_layout Standard
4687 We therefore need a function
4688 \begin_inset Flex CharStyle:Code
4691 \begin_layout Plain Layout
4697 which will take a block of text, a list of permitted parameters, and the
4698 arguments which must substitute for the parameters.
4702 \begin_layout Standard
4703 \begin_inset CommandInset label
4705 name "Here-we-split"
4709 Here we split the text on
4710 \begin_inset Flex CharStyle:Code
4713 \begin_layout Plain Layout
4719 which means that all parts except the first will begin with a parameter
4720 name which will be terminated by
4721 \begin_inset Flex CharStyle:Code
4724 \begin_layout Plain Layout
4731 The split function will consume the literal
4732 \begin_inset Flex CharStyle:Code
4735 \begin_layout Plain Layout
4748 \begin_layout Standard
4749 \begin_inset listings
4753 \begin_layout Plain Layout
4755 function expand_chunk_args(text, params, args,
4758 \begin_layout Plain Layout
4760 p, text_array, next_text, v, t, l)
4763 \begin_layout Plain Layout
4768 \begin_layout Plain Layout
4770 if (split(text, text_array, "
4777 \begin_layout Plain Layout
4781 chunkref{substitute-chunk-args}>
4784 \begin_layout Plain Layout
4789 \begin_layout Plain Layout
4793 \begin_layout Plain Layout
4798 \begin_layout Plain Layout
4808 \begin_layout Standard
4809 First, we produce an associative array of substitution values indexed by
4811 This will serve as a cache, allowing us to look up the replacement values
4812 as we extract each name.
4816 substitute-chunk-args
4819 \begin_layout Standard
4820 \begin_inset listings
4824 \begin_layout Plain Layout
4829 \begin_layout Plain Layout
4831 v[params[p]]=args[p];
4834 \begin_layout Plain Layout
4844 \begin_layout Standard
4845 We accumulate substituted text in the variable
4846 \begin_inset Flex CharStyle:Code
4849 \begin_layout Plain Layout
4856 As the first part of the split function is the part before the delimiter
4858 \begin_inset Flex CharStyle:Code
4861 \begin_layout Plain Layout
4867 in our case --- this part will never contain a parameter reference, so
4868 we assign this directly to the result kept in
4869 \begin_inset Flex CharStyle:Code
4872 \begin_layout Plain Layout
4879 \begin_inset listings
4883 \begin_layout Plain Layout
4893 \begin_layout Standard
4894 We then iterate over the remaining values in the array
4898 \begin_layout Plain Layout
4899 I don't know why I think that it will enumerate the array in order, but
4906 \begin_inset Note Note
4909 \begin_layout Plain Layout
4910 So fix it or porve it
4915 , and substitute each reference for it's argument.
4918 \begin_layout Standard
4919 \begin_inset listings
4923 \begin_layout Plain Layout
4925 for(t=2; t in text_array; t++) {
4928 \begin_layout Plain Layout
4932 chunkref{substitute-chunk-arg}>
4935 \begin_layout Plain Layout
4945 \begin_layout Standard
4947 \begin_inset Flex CharStyle:Code
4950 \begin_layout Plain Layout
4956 a valid parameter reference will consist of valid parameter name terminated
4958 \begin_inset Flex CharStyle:Code
4961 \begin_layout Plain Layout
4968 A valid character name begins with the underscore or a letter, and may
4969 contain letters, digits or underscores.
4972 \begin_layout Standard
4973 A valid looking reference that is not actually the name of a parameter will
4974 be and not substituted.
4975 This is good because there is nothing to substitute anyway, and it avoids
4976 clashes when writing code for languages where ${\SpecialChar \ldots{}
4977 } is a valid construct
4978 --- such constructs will not be interfered with unless the parameter name
4983 substitute-chunk-arg
4986 \begin_layout Standard
4987 \begin_inset listings
4991 \begin_layout Plain Layout
4993 if (match(text_array[t], "^([a-zA-Z_][a-zA-Z0-9_]*)}", l) &&
4996 \begin_layout Plain Layout
5001 \begin_layout Plain Layout
5006 \begin_layout Plain Layout
5008 text = text v[l[1]] substr(text_array[t], length(l[1])+2);
5011 \begin_layout Plain Layout
5016 \begin_layout Plain Layout
5018 text = text "${" text_array[t];
5021 \begin_layout Plain Layout
5031 \begin_layout Chapter
5032 Language Modes & Quoting
5035 \begin_layout Standard
5036 \begin_inset CommandInset label
5045 \begin_layout Section
5049 \begin_layout Standard
5050 lstlistings and newfangle both recognize source languages, and perform some
5052 lstlistings can detect strings and comments within a language definition
5053 and perform suitable rendering, such as italics for comments, and visible-space
5057 \begin_layout Standard
5058 Newfangle similarly can recognize strings, and comments, etc, within a language,
5059 so that any chunks included with
5060 \begin_inset Flex CharStyle:Code
5063 \begin_layout Plain Layout
5071 can be suitably escape or quoted.
5074 \begin_layout Subsection
5075 Modes to keep code together
5078 \begin_layout Standard
5079 As an example, in the C language there are a few parse modes, affecting
5080 the interpretation of characters.
5083 \begin_layout Standard
5084 One parse mode is the strings mode.
5085 The string mode is commenced by an un-escaped quotation mark
5086 \begin_inset Flex CharStyle:Code
5089 \begin_layout Plain Layout
5095 and terminated by the same.
5096 Within the string mode, only one additional mode can be commenced, it is
5098 \begin_inset Flex CharStyle:Code
5101 \begin_layout Plain Layout
5109 , which is always terminated by the folloing character.
5112 \begin_layout Standard
5114 \begin_inset Flex CharStyle:Code
5117 \begin_layout Plain Layout
5123 which is terminated by a
5124 \begin_inset Flex CharStyle:Code
5127 \begin_layout Plain Layout
5133 (unless it occurs in a string).
5136 \begin_layout Standard
5137 Consider this line of C code:
5140 \begin_layout Standard
5141 \begin_inset Formula $\mathtt{things\underbrace{[\mathtt{x,\ y}]}_{1.\ [\ mode},\ get\_other\_things\underbrace{(\mathtt{a,\overbrace{"\mathtt{(all)}"}})}_{2.\ (\ mode}^{3.\ "\ mode}}$
5147 \begin_layout Standard
5148 Mode nesting prevents the close parenthesis in quote mode (part 3) from
5149 terminating the parenthesis mode (part 2).
5152 \begin_layout Standard
5153 Each language has a set of modes, the default mode being the null mode.
5154 Each mode can lead to other modes.
5157 \begin_layout Subsection
5158 Modes to included chunks
5161 \begin_layout Standard
5162 For instance, consider this chunk with
5163 \begin_inset Flex CharStyle:Code
5166 \begin_layout Plain Layout
5176 example-perl,language=perl
5179 \begin_layout Standard
5180 \begin_inset listings
5184 \begin_layout Plain Layout
5186 print "hello world $0
5196 \begin_layout Standard
5197 If it were included in a chunk with
5198 \begin_inset Flex CharStyle:Code
5201 \begin_layout Plain Layout
5211 example-sh,language=sh
5214 \begin_layout Standard
5215 \begin_inset listings
5219 \begin_layout Plain Layout
5223 chunkref{example-perl}>"
5231 \begin_layout Standard
5232 newfangle would need to generate output like this if it were to work:
5235 \begin_layout LyX-Code
5247 \begin_layout Standard
5248 See that the double quote
5249 \begin_inset Flex CharStyle:Code
5252 \begin_layout Plain Layout
5259 \begin_inset Flex CharStyle:Code
5262 \begin_layout Plain Layout
5268 in the regex have been quoted with a back-slash to protect them from shell
5272 \begin_layout Standard
5273 If that were then included in a chunk with
5274 \begin_inset Flex CharStyle:Code
5277 \begin_layout Plain Layout
5287 example-makefile,language=make
5290 \begin_layout Standard
5291 \begin_inset listings
5295 \begin_layout Plain Layout
5300 \begin_layout Plain Layout
5304 chunkref{example-sh}>
5312 \begin_layout Standard
5313 We would need the output to look like this --- note the $$:
5316 \begin_layout LyX-Code
5320 \begin_layout LyX-Code
5328 \begin_layout Standard
5329 In order to make this work, we need to define a mode-tracker supporting
5330 each language, that can detect the various quoting modes, and provide a
5331 transformation that must be applied to any included text so that included
5332 text will be interpreted correctly after any interpolation that it may
5333 be subject to at run-time.
5336 \begin_layout Standard
5337 For example, the sed transformation for text to be inserted into sh double-quote
5338 d strings would be something like:
5341 \begin_layout LyX-Code
5365 \begin_layout Standard
5367 \begin_inset Flex CharStyle:Code
5370 \begin_layout Plain Layout
5381 \begin_layout Standard
5382 \begin_inset Note Note
5385 \begin_layout Plain Layout
5386 I don't think this example is true
5391 The mode tracker must also track nested mode-changes, as in this
5392 \begin_inset Flex CharStyle:Code
5395 \begin_layout Plain Layout
5404 \begin_layout LyX-Code
5405 echo "hello `id \SpecialChar \ldots{}
5409 \begin_layout LyX-Code
5413 \begin_layout Plain Layout
5419 hphantom{echo "hello `id}
5427 \begin_layout Standard
5428 Any characters inserted at the point marked ↑ would need to be escaped,
5430 \begin_inset Flex CharStyle:Code
5433 \begin_layout Plain Layout
5440 First it would need escaping for the back-ticks `, and then for the double-quot
5444 \begin_layout Standard
5445 Escaping need not occur if the format and mode of the included chunk matches
5446 that of the including chunk.
5449 \begin_layout Standard
5450 As each chunk is output a new mode tracker for that language is initialized
5451 in it's normal state.
5452 As text is output for that chunk the output mode is tracked.
5453 When a new chunk is included, a transformation appropriate to that mode
5454 is selected and pushed onto a stack of transformations.
5455 Any text to be output is first passed through this stack of transformations.
5458 \begin_layout Standard
5459 It remains to consider if the chunk-include function should return it's
5460 generated text so that the caller can apply any transformations (and formatting
5461 ), or if it should apply the stack of transformations itself.
5464 \begin_layout Standard
5465 Note that the transformed text should have the property of not being able
5466 to change the mode in the current chunk.
5469 \begin_layout Standard
5470 \begin_inset Note Note
5473 \begin_layout Plain Layout
5474 Note chunk parameters should probably also be transformed
5482 \begin_layout Section
5483 Language Mode Definitions
5486 \begin_layout Standard
5487 All modes are stored in a single multi-dimensional hash.
5488 The first index is the language, and the second index is the mode-identifier.
5489 The third indexes are terminators, and optionally, submodes, and delimiters.
5492 \begin_layout Standard
5493 A useful set of mode definitions for a nameless general C-type language
5495 (Don't be confused by the double backslash escaping needed in awk.
5496 One set of escaping is for the string, and the second set of escaping is
5499 \begin_inset Note Note
5502 \begin_layout Plain Layout
5505 mode{}> command which will allow us to signify that a string is regex and
5506 thus newfangle will quote it for us.
5514 \begin_layout Standard
5515 Submodes are entered by the characters
5516 \begin_inset Flex CharStyle:Code
5519 \begin_layout Plain Layout
5528 \begin_inset Flex CharStyle:Code
5531 \begin_layout Plain Layout
5538 \begin_inset Flex CharStyle:Code
5541 \begin_layout Plain Layout
5548 \begin_inset Flex CharStyle:Code
5551 \begin_layout Plain Layout
5558 \begin_inset Flex CharStyle:Code
5561 \begin_layout Plain Layout
5568 \begin_inset Flex CharStyle:Code
5571 \begin_layout Plain Layout
5578 \begin_inset Flex CharStyle:Code
5581 \begin_layout Plain Layout
5591 common-mode-definitions,params=language
5594 \begin_layout Standard
5595 \begin_inset listings
5599 \begin_layout Plain Layout
5601 modes[${language}, "", "submodes" ]="
5627 \begin_layout Standard
5628 In the default mode, a comma surrounded by un-important white space is a
5629 delimiter of language items.
5632 \begin_layout Standard
5633 \begin_inset listings
5637 \begin_layout Plain Layout
5639 modes[${language}, "", "delimiters"]=" *, *";
5647 \begin_layout Standard
5648 and should pass this test:
5651 \begin_layout Standard
5652 \begin_inset Note Note
5655 \begin_layout Plain Layout
5656 Why do the tests run in
5657 \begin_inset Quotes eld
5661 \begin_inset Quotes erd
5665 \begin_inset Quotes eld
5669 \begin_inset Quotes erd
5681 test:mode-definitions
5684 \begin_layout Standard
5685 \begin_inset listings
5689 \begin_layout Plain Layout
5691 parse_chunk_args("c-like", "1,2,3", a, "");
5694 \begin_layout Plain Layout
5696 if (a[1] != "1") e++;
5699 \begin_layout Plain Layout
5701 if (a[2] != "2") e++;
5704 \begin_layout Plain Layout
5706 if (a[3] != "3") e++;
5709 \begin_layout Plain Layout
5711 if (length(a) != 3) e++;
5714 \begin_layout Plain Layout
5718 chunkref{pca-test.awk:summary}>
5721 \begin_layout Plain Layout
5725 \begin_layout Plain Layout
5727 parse_chunk_args("c-like", "joe, red", a, "");
5730 \begin_layout Plain Layout
5732 if (a[1] != "joe") e++;
5735 \begin_layout Plain Layout
5737 if (a[2] != "red") e++;
5740 \begin_layout Plain Layout
5742 if (length(a) != 2) e++;
5745 \begin_layout Plain Layout
5749 chunkref{pca-test.awk:summary}>
5752 \begin_layout Plain Layout
5756 \begin_layout Plain Layout
5758 parse_chunk_args("c-like", "${colour}", a, "");
5761 \begin_layout Plain Layout
5763 if (a[1] != "${colour}") e++;
5766 \begin_layout Plain Layout
5768 if (length(a) != 1) e++;
5771 \begin_layout Plain Layout
5775 chunkref{pca-test.awk:summary}>
5783 \begin_layout Standard
5784 Nested modes are identified by a backslash, a double or single quote, various
5785 bracket styles or a /* comment.
5788 \begin_layout Standard
5789 For each of these sub-modes modes we must also identify at a mode terminator,
5790 and any sub-modes or delimiters that may be entered
5794 \begin_layout Plain Layout
5795 Because we are using the sub-mode characters as the mode identifier it means
5796 we can't currently have a mode character dependant on it's context; i.e.
5798 \begin_inset Flex CharStyle:Code
5801 \begin_layout Plain Layout
5807 can't behave differently when it is inside
5808 \begin_inset Flex CharStyle:Code
5811 \begin_layout Plain Layout
5825 \begin_layout Subsection
5829 \begin_layout Standard
5830 The backslash mode has no submodes or delimiters, and is terminated by any
5832 Note that we are not so much interested in evaluating or interpolating
5833 content as we are in delineating content.
5834 It is no matter that a double backslash (
5835 \begin_inset Flex CharStyle:Code
5838 \begin_layout Plain Layout
5848 ) may represent a single backslash while a backslash-newline may represent
5849 white space, but it does matter that the newline in a backslash newline
5850 should not be able to terminate a C pre-processor statement; and so the
5851 newline will be consumed by the backslash however it is to be interpreted.
5855 common-mode-definitions
5858 \begin_layout Standard
5859 \begin_inset listings
5863 \begin_layout Plain Layout
5865 modes[${language}, "
5869 ", "terminators"]=".";
5877 \begin_layout Subsection
5881 \begin_layout Standard
5882 Common languages support two kinds of strings quoting, double quotes and
5887 mode:common-string,params=language;quote
5890 \begin_layout Standard
5891 In a string we have one special mode, which is the backslash.
5892 This may escape an embedded quote and prevent us thinking that it should
5893 terminate the string.
5897 \begin_layout Standard
5898 \begin_inset listings
5902 \begin_layout Plain Layout
5904 modes[${language}, ${quote}, "submodes" ]="
5920 \begin_layout Standard
5921 Otherwise, the string will be terminated by the same character that commenced
5925 \begin_layout Standard
5926 \begin_inset listings
5930 \begin_layout Plain Layout
5932 modes[${language}, ${quote}, "terminators"]=${quote};
5940 \begin_layout Standard
5941 In C type languages, certain escape sequences exist in strings.
5942 We need to define mechanism to enclode any chunks included in this mode
5943 using those escape sequences.
5944 These are expressed in two parts, s meaning search, and r meaning replace.
5947 \begin_layout Standard
5948 The first substitution is to replace a backslash with a double backslash.
5949 We do this first as other substitutions may introduce a backslash which
5950 we would not then want to escape again here.
5953 \begin_layout Standard
5954 Note: Backslashes need double-escaping in the search pattern but not in
5955 the replacement string, hence we are replacing a literal
5964 \begin_layout Standard
5965 \begin_inset listings
5969 \begin_layout Plain Layout
5971 escapes[${language}, ${quote}, ++escapes[${language}, ${quote}], "s"]="
5982 \begin_layout Plain Layout
5984 escapes[${language}, ${quote}, escapes[${language}, ${quote}], "r"]="
6000 \begin_layout Standard
6001 If the quote character occurs in the text, it should be preceded by a backslash,
6002 otherwise it would terminate the string unexpectedly.
6005 \begin_layout Standard
6006 \begin_inset listings
6010 \begin_layout Plain Layout
6012 escapes[${language}, ${quote}, ++escapes[${language}, ${quote}], "s"]=${quote};
6015 \begin_layout Plain Layout
6017 escapes[${language}, ${quote}, escapes[${language}, ${quote}], "r"]="
6029 \begin_layout Standard
6030 Any newlines in the string, must be replaced by
6031 \begin_inset Flex CharStyle:Code
6034 \begin_layout Plain Layout
6045 \begin_layout Standard
6046 \begin_inset listings
6050 \begin_layout Plain Layout
6052 escapes[${language}, ${quote}, ++escapes[${language}, ${quote}], "s"]="
6057 \begin_layout Plain Layout
6059 escapes[${language}, ${quote}, escapes[${language}, ${quote}], "r"]="
6071 \begin_layout Standard
6072 For the common modes, we define this string handling for double and single
6077 common-mode-definitions,params=language
6080 \begin_layout Standard
6081 \begin_inset listings
6085 \begin_layout Plain Layout
6089 chunkref{mode:common-string}(${language}, "
6094 \begin_layout Plain Layout
6098 chunkref{mode:common-string}(${language}, "'")>
6106 \begin_layout Standard
6107 Working strings should pass this test:
6111 test:mode-definitions
6114 \begin_layout Standard
6115 \begin_inset listings
6119 \begin_layout Plain Layout
6121 parse_chunk_args("c-like", "say
6140 \begin_layout Plain Layout
6161 \begin_layout Plain Layout
6163 if (a[2] != "for me") e++;
6166 \begin_layout Plain Layout
6168 if (length(a) != 2) e++;
6171 \begin_layout Plain Layout
6175 chunkref{pca-test.awk:summary}>
6183 \begin_layout Subsection
6184 Parentheses, Braces and Brackets
6187 \begin_layout Standard
6188 Where quotes are closed by the same character, parentheses, brackets and
6189 braces are closed by an alternate character.
6193 mode:common-brackets,params=language;open;close
6196 \begin_layout Standard
6197 \begin_inset listings
6201 \begin_layout Plain Layout
6203 modes[${language}, ${open}, "submodes" ]="
6228 \begin_layout Plain Layout
6230 modes[${language}, ${open}, "delimiters"]=" *, *";
6233 \begin_layout Plain Layout
6235 modes[${language}, ${open}, "terminators"]=${close};
6243 \begin_layout Standard
6244 Note that the open is NOT a regex but the close token IS.
6246 \begin_inset Note Note
6249 \begin_layout Plain Layout
6250 When we can quote regex we won't have to put the slashes in here
6259 common-mode-definitions,params=language
6262 \begin_layout Standard
6263 \begin_inset listings
6267 \begin_layout Plain Layout
6271 chunkref{mode:common-brackets}(${language}, "{", "}")>
6274 \begin_layout Plain Layout
6278 chunkref{mode:common-brackets}(${language}, "[", "
6285 \begin_layout Plain Layout
6289 chunkref{mode:common-brackets}(${language}, "(", "
6301 \begin_layout Subsection
6302 Customizing Standard Modes
6306 mode:add-submode,params=language;mode;submode
6309 \begin_layout Standard
6310 \begin_inset listings
6314 \begin_layout Plain Layout
6316 modes[${language}, ${mode}, "submodes"] = modes[${language}, ${mode}, "submodes"
6326 mode:add-escapes,params=language;mode;search;replace
6329 \begin_layout Standard
6330 \begin_inset listings
6334 \begin_layout Plain Layout
6336 escapes[${language}, ${mode}, ++escapes[${language}, ${mode}], "s"]=${search};
6339 \begin_layout Plain Layout
6341 escapes[${language}, ${mode}, escapes[${language}, ${mode}], "r"]=${replace};
6349 \begin_layout Subsection
6353 \begin_layout Standard
6355 \begin_inset Flex CharStyle:Code
6358 \begin_layout Plain Layout
6365 \begin_inset Flex CharStyle:Code
6368 \begin_layout Plain Layout
6374 style comments to be added to any language:
6378 mode:multi-line-comments,params=language
6381 \begin_layout Standard
6382 \begin_inset listings
6386 \begin_layout Plain Layout
6390 chunkref{mode:add-submode}(${language}, "", "/
6397 \begin_layout Plain Layout
6399 modes[${language}, "/*", "terminators"]="
6412 mode:single-line-slash-comments,params=language
6415 \begin_layout Standard
6416 \begin_inset listings
6420 \begin_layout Plain Layout
6424 chunkref{mode:add-submode}(${language}, "", "//")>
6427 \begin_layout Plain Layout
6429 modes[${language}, "//", "terminators"]="
6434 \begin_layout Plain Layout
6438 chunkref{mode:add-escapes}(${language}, "//", "
6440 textbackslash{}n", "
6442 textbackslash{}n//")>
6450 \begin_layout Standard
6452 \begin_inset Flex CharStyle:Code
6455 \begin_layout Plain Layout
6461 style comments (as used in awk and shell scripts) in a similar manner.
6465 mode:add-hash-comments,params=language
6466 \begin_inset Note Note
6469 \begin_layout Plain Layout
6476 and have hacky work-arounds in the parser for now
6484 \begin_layout Standard
6485 \begin_inset listings
6489 \begin_layout Plain Layout
6493 chunkref{mode:add-submode}(${language}, "", "
6498 \begin_layout Plain Layout
6500 modes[${language}, "#", "terminators"]="
6505 \begin_layout Plain Layout
6509 chunkref{mode:add-escapes}(${language}, "
6513 textbackslash{}n", "
6525 \begin_layout Standard
6527 \begin_inset Flex CharStyle:Code
6530 \begin_layout Plain Layout
6536 denotes pre-processor directives which can be multi-line
6540 mode:add-hash-defines,params=language
6543 \begin_layout Standard
6544 \begin_inset listings
6548 \begin_layout Plain Layout
6552 chunkref{mode:add-submode}(${language}, "", "
6557 \begin_layout Plain Layout
6559 modes[${language}, "#", "submodes" ]="
6570 \begin_layout Plain Layout
6572 modes[${language}, "#", "terminators"]="
6577 \begin_layout Plain Layout
6581 chunkref{mode:add-escapes}(${language}, "
6585 textbackslash{}n", "
6604 mode:quote-dollar-escape,params=language;quote
6607 \begin_layout Standard
6608 \begin_inset listings
6612 \begin_layout Plain Layout
6614 escapes[${language}, ${quote}, ++escapes[${language}, ${quote}], "s"]="
6621 \begin_layout Plain Layout
6623 escapes[${language}, ${quote}, escapes[${language}, ${quote}], "r"]="
6635 \begin_layout Standard
6636 We can add these definitions to various languages
6643 \begin_layout Standard
6644 \begin_inset listings
6648 \begin_layout Plain Layout
6652 chunkref{common-mode-definitions}("c-like")>
6655 \begin_layout Plain Layout
6659 \begin_layout Plain Layout
6663 chunkref{common-mode-definitions}("c")>
6666 \begin_layout Plain Layout
6670 chunkref{mode:multi-line-comments}("c")>
6673 \begin_layout Plain Layout
6677 chunkref{mode:single-line-slash-comments}("c")>
6680 \begin_layout Plain Layout
6684 chunkref{mode:add-hash-defines}("c")>
6687 \begin_layout Plain Layout
6691 \begin_layout Plain Layout
6695 chunkref{common-mode-definitions}("awk")>
6698 \begin_layout Plain Layout
6702 chunkref{mode:add-hash-comments}("awk")>
6705 \begin_layout Plain Layout
6709 chunkref{mode:add-naked-regex}("awk")>
6717 \begin_layout Standard
6718 The awk definitions should allow a comment block like this:
6722 test:comment-quote,language=awk
6725 \begin_layout Standard
6726 \begin_inset listings
6730 \begin_layout Plain Layout
6734 chunkref{test:comment-text}>
6743 test:comment-text,language=
6746 \begin_layout Standard
6747 \begin_inset listings
6751 \begin_layout Plain Layout
6756 \begin_layout Plain Layout
6758 the quick brown fox to bring lemonade
6761 \begin_layout Plain Layout
6771 \begin_layout Standard
6772 to come out like this:
6776 test:comment-quote:result
6779 \begin_layout Standard
6780 \begin_inset listings
6784 \begin_layout Plain Layout
6786 # Comment: Now is the time for
6789 \begin_layout Plain Layout
6791 #the quick brown fox to bring lemonade
6794 \begin_layout Plain Layout
6804 \begin_layout Standard
6805 The C definition for such a block should have it come out like this:
6809 test:comment-quote:C-result
6812 \begin_layout Standard
6813 \begin_inset listings
6817 \begin_layout Plain Layout
6819 # Comment: Now is the time for
6824 \begin_layout Plain Layout
6826 the quick brown fox to bring lemonade
6831 \begin_layout Plain Layout
6841 \begin_layout Subsection
6845 \begin_layout Standard
6846 This pattern is in-complete, but meant to detect naked regular expressions
6847 in awk and perl; e.g.
6849 \begin_inset Flex CharStyle:Code
6852 \begin_layout Plain Layout
6858 , however required capabilities are not present.
6861 \begin_layout Standard
6862 Current it only detects regexes anchored with
6863 \begin_inset Flex CharStyle:Code
6866 \begin_layout Plain Layout
6872 as used in newfangle.
6875 \begin_layout Standard
6876 For full regex support, modes need to be named not after their starting
6877 character, but some other more fully qualified name.
6881 mode:add-naked-regex,params=language
6884 \begin_layout Standard
6885 \begin_inset listings
6889 \begin_layout Plain Layout
6893 chunkref{mode:add-submode}(${language}, "", "/
6902 \begin_layout Plain Layout
6904 modes[${language}, "/^", "terminators"]="/";
6912 \begin_layout Subsection
6920 \begin_layout Standard
6921 \begin_inset listings
6925 \begin_layout Plain Layout
6929 chunkref{common-mode-definitions}("perl")>
6932 \begin_layout Plain Layout
6936 chunkref{mode:multi-line-comments}("perl")>
6939 \begin_layout Plain Layout
6943 chunkref{mode:add-hash-comments}("perl")>
6951 \begin_layout Standard
6952 Still need to add add s/, submod /, terminate both with //
6955 \begin_layout Subsection
6963 \begin_layout Standard
6964 \begin_inset listings
6968 \begin_layout Plain Layout
6972 chunkref{common-mode-definitions}("sh")>
6975 \begin_layout Plain Layout
6979 chunkref{mode:common-string}("sh", "
6984 \begin_layout Plain Layout
6988 chunkref{mode:common-string}("sh", "'")>
6991 \begin_layout Plain Layout
6995 chunkref{mode:add-hash-comments}("sh")>
6998 \begin_layout Plain Layout
7002 chunkref{mode:quote-dollar-escape}("sh", "
7012 \begin_layout Section
7016 \begin_layout Standard
7017 Also, the parser must return any spare text at the end that has not been
7018 processed due to a mode terminator being found.
7022 test:mode-definitions
7025 \begin_layout Standard
7026 \begin_inset listings
7030 \begin_layout Plain Layout
7032 rest = parse_chunk_args("c-like", "1, 2, 3) spare", a, "(");
7035 \begin_layout Plain Layout
7040 \begin_layout Plain Layout
7045 \begin_layout Plain Layout
7050 \begin_layout Plain Layout
7052 if (length(a) != 3) e++;
7055 \begin_layout Plain Layout
7057 if (rest != " spare") e++;
7060 \begin_layout Plain Layout
7064 chunkref{pca-test.awk:summary}>
7072 \begin_layout Standard
7073 We must also be able to parse the example given earlier.
7077 test:mode-definitions
7080 \begin_layout Standard
7081 \begin_inset listings
7085 \begin_layout Plain Layout
7087 parse_chunk_args("c-like", "things[x, y], get_other_things(a,
7094 \begin_layout Plain Layout
7096 if (a[1] != "things[x, y]") e++;
7099 \begin_layout Plain Layout
7101 if (a[2] != "get_other_things(a,
7108 \begin_layout Plain Layout
7110 if (a[3] != "99") e++;
7113 \begin_layout Plain Layout
7115 if (length(a) != 3) e++;
7118 \begin_layout Plain Layout
7122 chunkref{pca-test.awk:summary}>
7130 \begin_layout Section
7131 A non-recursive mode tracker
7134 \begin_layout Subsection
7138 \begin_layout Standard
7139 The mode tracker holds its state in a stack based on a hash.
7140 This function, when passed an empty hash will intialize it.
7147 \begin_layout Standard
7148 \begin_inset listings
7152 \begin_layout Plain Layout
7154 function new_mode_tracker(context, language, mode) {
7157 \begin_layout Plain Layout
7162 \begin_layout Plain Layout
7164 context[0, "language"] = language;
7167 \begin_layout Plain Layout
7169 context[0, "mode"] = mode;
7172 \begin_layout Plain Layout
7182 \begin_layout Standard
7183 Because awk functions cannot return an array, we must create the array first
7184 and pass it in, so we have a newfangle macro to do this:
7188 new-mode-tracker,language=awk,params=context;language;mode
7191 \begin_layout Standard
7192 \begin_inset listings
7196 \begin_layout Plain Layout
7200 chunkref{awk-delete-array}(${context})>
7203 \begin_layout Plain Layout
7205 new_mode_tracker(${context}, ${language}, ${mode});
7213 \begin_layout Subsection
7217 \begin_layout Standard
7218 And for tracking modes, we dispatch to a mode-tracker action based on the
7223 mode_tracker,language=awk
7226 \begin_layout Standard
7227 \begin_inset listings
7231 \begin_layout Plain Layout
7233 function push_mode_tracker(context, language, mode,
7236 \begin_layout Plain Layout
7241 \begin_layout Plain Layout
7246 \begin_layout Plain Layout
7251 \begin_layout Plain Layout
7253 if (! ("" in context)) {
7256 \begin_layout Plain Layout
7260 chunkref{new-mode-tracker}(context, language, mode)>
7263 \begin_layout Plain Layout
7268 \begin_layout Plain Layout
7273 \begin_layout Plain Layout
7275 if (context[top, "language"] == language && mode=="") mode = context[top,
7279 \begin_layout Plain Layout
7284 \begin_layout Plain Layout
7286 context[top, "language"] = language;
7289 \begin_layout Plain Layout
7291 context[top, "mode"] = mode;
7294 \begin_layout Plain Layout
7299 \begin_layout Plain Layout
7304 \begin_layout Plain Layout
7314 \begin_layout Standard
7315 \begin_inset listings
7319 \begin_layout Plain Layout
7321 function dump_mode_tracker(context,
7324 \begin_layout Plain Layout
7329 \begin_layout Plain Layout
7334 \begin_layout Plain Layout
7336 for(c=0; c <= context[""]; c++) {
7339 \begin_layout Plain Layout
7343 n", c, context[c, "language"], context[c, "mode"]) > "/dev/stderr";
7346 \begin_layout Plain Layout
7348 for(d=1; ( (c, "values", d) in context); d++) {
7351 \begin_layout Plain Layout
7355 n", d, context[c, "values", d]) > "/dev/stderr";
7358 \begin_layout Plain Layout
7363 \begin_layout Plain Layout
7368 \begin_layout Plain Layout
7378 \begin_layout Standard
7379 \begin_inset listings
7383 \begin_layout Plain Layout
7385 function finalize_mode_tracker(context)
7388 \begin_layout Plain Layout
7393 \begin_layout Plain Layout
7395 if ( ("" in context) && context[""] != 0) return 0;
7398 \begin_layout Plain Layout
7403 \begin_layout Plain Layout
7413 \begin_layout Standard
7414 This implies that any chunk must be syntactically whole; for instance, this
7422 \begin_layout Standard
7423 \begin_inset listings
7427 \begin_layout Plain Layout
7432 \begin_layout Plain Layout
7436 chunkref{test:say-hello}>
7439 \begin_layout Plain Layout
7453 \begin_layout Standard
7454 \begin_inset listings
7458 \begin_layout Plain Layout
7468 \begin_layout Standard
7469 But this is not fine; the chunk
7470 \begin_inset Flex Chunkref
7473 \begin_layout Plain Layout
7479 is not properly cromulent.
7486 \begin_layout Standard
7487 \begin_inset listings
7491 \begin_layout Plain Layout
7496 \begin_layout Plain Layout
7500 chunkref{test:hidden-else}>
7503 \begin_layout Plain Layout
7517 \begin_layout Standard
7518 \begin_inset listings
7522 \begin_layout Plain Layout
7527 \begin_layout Plain Layout
7532 \begin_layout Plain Layout
7542 \begin_layout Standard
7543 These tests will check for correct behaviour:
7550 \begin_layout Standard
7551 \begin_inset listings
7555 \begin_layout Plain Layout
7557 echo Cromulence test
7560 \begin_layout Plain Layout
7562 passtest $NEWFANGLE -Rtest:whole-chunk $TEX_SRC &>/dev/null || ( echo "Whole
7563 chunk failed" && exit 1 )
7566 \begin_layout Plain Layout
7568 failtest $NEWFANGLE -Rtest:partial-chunk $TEX_SRC &>/dev/null || ( echo
7569 "Partial chunk failed" && exit 1 )
7577 \begin_layout Subsection
7581 \begin_layout Standard
7582 We must avoid recursion as a language construct because we intend to employ
7583 mode-tracking to track language mode of emitted code, and the code is emitted
7584 from a function which is itself recursive, so instead we implement psuedo-recur
7585 sion using our own stack based on a hash.
7592 \begin_layout Standard
7593 \begin_inset listings
7597 \begin_layout Plain Layout
7599 function mode_tracker(context, text, values,
7602 \begin_layout Plain Layout
7604 # optional parameters
7607 \begin_layout Plain Layout
7612 \begin_layout Plain Layout
7614 mode, submodes, language,
7617 \begin_layout Plain Layout
7619 cindex, c, a, part, item, name, result, new_values, new_mode,
7622 \begin_layout Plain Layout
7624 delimiters, terminators)
7627 \begin_layout Plain Layout
7637 \begin_layout Standard
7638 We could be re-commencing with a valid context, so we need to setup the
7639 state according to the last context.
7642 \begin_layout Standard
7643 \begin_inset listings
7647 \begin_layout Plain Layout
7649 cindex = context[""] + 0;
7652 \begin_layout Plain Layout
7654 mode = context[cindex, "mode"];
7657 \begin_layout Plain Layout
7659 language = context[cindex, "language" ];
7667 \begin_layout Standard
7668 First we construct a single large regex combining the possible sub-modes
7669 for the current mode along with the terminators for the current mode.
7673 parse_chunk_args-reset-modes
7676 \begin_layout Standard
7677 \begin_inset listings
7681 \begin_layout Plain Layout
7683 submodes=modes[language, mode, "submodes"];
7686 \begin_layout Plain Layout
7690 \begin_layout Plain Layout
7692 if ((language, mode, "delimiters") in modes) {
7695 \begin_layout Plain Layout
7697 delimiters = modes[language, mode, "delimiters"];
7700 \begin_layout Plain Layout
7702 if (length(submodes)>0) submodes = submodes "|";
7705 \begin_layout Plain Layout
7707 submodes=submodes delimiters;
7710 \begin_layout Plain Layout
7712 } else delimiters="";
7715 \begin_layout Plain Layout
7717 if ((language, mode, "terminators") in modes) {
7720 \begin_layout Plain Layout
7722 terminators = modes[language, mode, "terminators"];
7725 \begin_layout Plain Layout
7727 if (length(submodes)>0) submodes = submodes "|";
7730 \begin_layout Plain Layout
7732 submodes=submodes terminators;
7735 \begin_layout Plain Layout
7737 } else terminators="";
7745 \begin_layout Standard
7746 If we don't find anything to match on --- probably because the language
7747 is not supported --- then we return the entire text without matching anything.
7750 \begin_layout Standard
7751 \begin_inset listings
7755 \begin_layout Plain Layout
7757 if (! length(submodes)) return text;
7769 \begin_layout Standard
7770 \begin_inset listings
7774 \begin_layout Plain Layout
7778 chunkref{parse_chunk_args-reset-modes}>
7786 \begin_layout Standard
7787 We then iterate the text (until there is none left) looking for sub-modes
7788 or terminators in the regex.
7791 \begin_layout Standard
7792 \begin_inset listings
7796 \begin_layout Plain Layout
7798 while((cindex >= 0) && length(text)) {
7801 \begin_layout Plain Layout
7803 if (match(text, "(" submodes ")", a)) {
7811 \begin_layout Standard
7812 A bug that creeps in regularly during development is bad regexes of zero
7813 length which result in an infinite loop (as no text is consumed), so I
7814 catch that right away with this test.
7817 \begin_layout Standard
7818 \begin_inset listings
7822 \begin_layout Plain Layout
7827 \begin_layout Plain Layout
7829 error(sprintf("Internal error, matched zero length submode, should
7830 be impossible - likely regex computation error
7837 \begin_layout Plain Layout
7845 n", language, mode, submodes));
7848 \begin_layout Plain Layout
7858 \begin_layout Standard
7859 \begin_inset Flex CharStyle:Code
7862 \begin_layout Plain Layout
7868 is defined as the text up to the sub-mode or terminator, and this is appended
7870 \begin_inset Flex CharStyle:Code
7873 \begin_layout Plain Layout
7879 --- which is the current text being gathered.
7880 If a mode has a delimiter, then item is reset each time a delimiter is
7884 \begin_layout Standard
7885 \begin_inset Formula $\mathtt{\overbrace{"\overbrace{hello}^{item},\ \overbrace{there}^{item}"}^{item},\ \overbrace{he\ said.}^{item}}$
7891 \begin_layout Standard
7892 \begin_inset listings
7896 \begin_layout Plain Layout
7898 part = substr(text, 1, RSTART -1);
7901 \begin_layout Plain Layout
7911 \begin_layout Standard
7912 We must now determine what was matched.
7913 If it was a terminator, then we must restore the previous mode.
7916 \begin_layout Standard
7917 \begin_inset listings
7921 \begin_layout Plain Layout
7923 if (match(a[1], "^" terminators "$")) {
7926 \begin_layout Plain Layout
7928 #printf("%2d EXIT MODE [%s] by [%s] [%s]
7930 n", cindex, mode, a[1], text) > "/dev/stderr"
7933 \begin_layout Plain Layout
7935 context[cindex, "values", ++context[cindex, "values"]] = item;
7938 \begin_layout Plain Layout
7940 delete context[cindex];
7943 \begin_layout Plain Layout
7945 context[""] = --cindex;
7948 \begin_layout Plain Layout
7953 \begin_layout Plain Layout
7955 mode = context[cindex, "mode"];
7958 \begin_layout Plain Layout
7960 language = context[cindex, "language"];
7963 \begin_layout Plain Layout
7967 chunkref{parse_chunk_args-reset-modes}>
7970 \begin_layout Plain Layout
7975 \begin_layout Plain Layout
7980 \begin_layout Plain Layout
7982 text = substr(text, 1 + length(part) + length(a[1]));
7985 \begin_layout Plain Layout
7995 \begin_layout Standard
7996 If a delimiter was matched, then we must store the current item in the parsed
7997 values array, and reset the item.
8000 \begin_layout Standard
8001 \begin_inset listings
8005 \begin_layout Plain Layout
8007 else if (match(a[1], "^" delimiters "$")) {
8010 \begin_layout Plain Layout
8015 \begin_layout Plain Layout
8017 context[cindex, "values", ++context[cindex, "values"]] = item;
8020 \begin_layout Plain Layout
8025 \begin_layout Plain Layout
8030 \begin_layout Plain Layout
8035 \begin_layout Plain Layout
8040 \begin_layout Plain Layout
8042 text = substr(text, 1 + length(part) + length(a[1]));
8045 \begin_layout Plain Layout
8055 \begin_layout Standard
8056 otherwise, if a new submode is detected (all submodes have terminators),
8057 we must create a nested parse context until we find the terminator for
8061 \begin_layout Standard
8062 \begin_inset listings
8066 \begin_layout Plain Layout
8068 else if ((language, a[1], "terminators") in modes) {
8071 \begin_layout Plain Layout
8073 #check if new_mode is defined
8076 \begin_layout Plain Layout
8081 \begin_layout Plain Layout
8083 #printf("%2d ENTER MODE [%s] in [%s]
8085 n", cindex, a[1], text) > "/dev/stderr"
8088 \begin_layout Plain Layout
8090 text = substr(text, 1 + length(part) + length(a[1]));
8093 \begin_layout Plain Layout
8095 context[""] = ++cindex;
8098 \begin_layout Plain Layout
8100 context[cindex, "mode"] = a[1];
8103 \begin_layout Plain Layout
8105 context[cindex, "language"] = language;
8108 \begin_layout Plain Layout
8113 \begin_layout Plain Layout
8117 chunkref{parse_chunk_args-reset-modes}>
8120 \begin_layout Plain Layout
8125 \begin_layout Plain Layout
8127 error(sprintf("Submode '%s' set unknown mode in text: %s
8129 nLanguage %s Mode %s
8131 n", a[1], text, language, mode));
8134 \begin_layout Plain Layout
8136 text = substr(text, 1 + length(part) + length(a[1]));
8139 \begin_layout Plain Layout
8144 \begin_layout Plain Layout
8154 \begin_layout Standard
8155 In the final case, we parsed to the end of the string.
8156 If the string was entire, then we should have no nested mode context, but
8157 if the string was just a fragment we may have a mode context which must
8158 be preserved for the next fragment.
8159 Todo: Consideration ought to be given if sub-mode strings are split over
8161 \begin_inset Note Note
8164 \begin_layout Plain Layout
8165 Consideration ought to be given if sub-mode strings are split over two fragments.
8173 \begin_layout Standard
8174 \begin_inset listings
8178 \begin_layout Plain Layout
8183 \begin_layout Plain Layout
8185 context[cindex, "values", ++context[cindex, "values"]] = item text;
8188 \begin_layout Plain Layout
8193 \begin_layout Plain Layout
8198 \begin_layout Plain Layout
8203 \begin_layout Plain Layout
8208 \begin_layout Plain Layout
8212 \begin_layout Plain Layout
8214 context["item"] = item;
8217 \begin_layout Plain Layout
8221 \begin_layout Plain Layout
8223 if (length(item)) context[cindex, "values", ++context[cindex, "values"]]
8227 \begin_layout Plain Layout
8232 \begin_layout Plain Layout
8242 \begin_layout Subsubsection
8246 \begin_layout Standard
8247 All the mode tracker chunks are referred to here:
8254 \begin_layout Standard
8255 \begin_inset listings
8259 \begin_layout Plain Layout
8263 chunkref{new_mode_tracker()}>
8266 \begin_layout Plain Layout
8270 chunkref{mode_tracker()}>
8278 \begin_layout Subsubsection
8282 \begin_layout Standard
8283 We can test this function like this:
8287 pca-test.awk,language=awk
8290 \begin_layout Standard
8291 \begin_inset listings
8295 \begin_layout Plain Layout
8302 \begin_layout Plain Layout
8306 chunkref{mode-tracker}>
8309 \begin_layout Plain Layout
8313 chunkref{parse_chunk_args()}>
8316 \begin_layout Plain Layout
8321 \begin_layout Plain Layout
8326 \begin_layout Plain Layout
8330 chunkref{mode-definitions}>
8333 \begin_layout Plain Layout
8337 \begin_layout Plain Layout
8341 chunkref{test:mode-definitions}>
8344 \begin_layout Plain Layout
8355 pca-test.awk:summary,language=awk
8358 \begin_layout Standard
8359 \begin_inset listings
8363 \begin_layout Plain Layout
8368 \begin_layout Plain Layout
8373 \begin_layout Plain Layout
8378 \begin_layout Plain Layout
8380 print "a[" b "] => " a[b];
8383 \begin_layout Plain Layout
8388 \begin_layout Plain Layout
8393 \begin_layout Plain Layout
8398 \begin_layout Plain Layout
8403 \begin_layout Plain Layout
8408 \begin_layout Plain Layout
8418 \begin_layout Standard
8419 which should give this output:
8423 pca-test.awk-results,language=
8426 \begin_layout Standard
8427 \begin_inset listings
8431 \begin_layout Plain Layout
8433 a[foo.quux.quirk] =>
8436 \begin_layout Plain Layout
8438 a[foo.quux.a] => fleeg
8441 \begin_layout Plain Layout
8446 \begin_layout Plain Layout
8451 \begin_layout Plain Layout
8461 \begin_layout Section
8462 Escaping and Quoting
8465 \begin_layout Standard
8466 Each nested mode can optionally define a set of transforms to be applied
8467 to any text that is included from another language.
8470 \begin_layout Standard
8471 This code can perform transforms
8475 mode_tracker,language=awk
8478 \begin_layout Standard
8479 \begin_inset listings
8483 \begin_layout Plain Layout
8485 function transform_escape(s, r, text,
8488 \begin_layout Plain Layout
8493 \begin_layout Plain Layout
8498 \begin_layout Plain Layout
8503 \begin_layout Plain Layout
8508 \begin_layout Plain Layout
8513 \begin_layout Plain Layout
8515 for(c=1; c <= max && (c in s); c++) {
8518 \begin_layout Plain Layout
8520 gsub(s[c], r[c], text);
8523 \begin_layout Plain Layout
8528 \begin_layout Plain Layout
8533 \begin_layout Plain Layout
8543 \begin_layout Standard
8544 This function must append from index
8545 \begin_inset Flex CharStyle:Code
8548 \begin_layout Plain Layout
8554 onwards, and escape transforms from the supplied context, and return c
8555 + number of new transforms.
8558 \begin_layout Standard
8559 \begin_inset listings
8563 \begin_layout Plain Layout
8565 function mode_escaper(context, s, r, src,
8568 \begin_layout Plain Layout
8573 \begin_layout Plain Layout
8578 \begin_layout Plain Layout
8580 for(c = context[""]; c >= 0; c--) {
8583 \begin_layout Plain Layout
8585 if ( (context[c, "language"], context[c, "mode"]) in escapes) {
8588 \begin_layout Plain Layout
8590 cpl = escapes[context[c, "language"], context[c, "mode"]];
8593 \begin_layout Plain Layout
8595 for (cp = 1; cp <= cpl; cp ++) {
8598 \begin_layout Plain Layout
8603 \begin_layout Plain Layout
8605 s[src] = escapes[context[c, "language"], context[c, "mode"], cp, "s"];
8608 \begin_layout Plain Layout
8610 r[src] = escapes[context[c, "language"], context[c, "mode"], cp, "r"];
8613 \begin_layout Plain Layout
8618 \begin_layout Plain Layout
8623 \begin_layout Plain Layout
8628 \begin_layout Plain Layout
8633 \begin_layout Plain Layout
8638 \begin_layout Plain Layout
8640 function dump_escaper(c, s, r, cc) {
8643 \begin_layout Plain Layout
8645 for(cc=1; cc<=c; cc++) {
8648 \begin_layout Plain Layout
8650 printf("%2d s[%s] r[%s]
8652 n", cc, s[cc], r[cc]) > "/dev/stderr"
8655 \begin_layout Plain Layout
8660 \begin_layout Plain Layout
8671 test:escapes,language=sh
8674 \begin_layout Standard
8675 \begin_inset listings
8679 \begin_layout Plain Layout
8684 \begin_layout Plain Layout
8686 passtest $NEWFANGLE -Rtest:comment-quote $TEX_SRC &>/dev/null || ( echo
8687 "Comment-quote failed" && exit 1 )
8695 \begin_layout Chapter
8699 \begin_layout Standard
8700 Newfangle recognizes noweb chunks, but as we also want better LaTeX integration
8701 we will recognize any of these:
8704 \begin_layout Itemize
8705 notangle chunks matching the pattern
8706 \begin_inset Flex CharStyle:Code
8709 \begin_layout Plain Layout
8711 \begin_inset space \hspace*{}
8716 \begin_inset space \hspace*{}
8728 \begin_layout Itemize
8729 a chunks beginning with
8730 \begin_inset Flex CharStyle:Code
8733 \begin_layout Plain Layout
8743 Chunk{\SpecialChar \ldots{}
8744 } on the previous line
8747 \begin_layout Itemize
8748 an older form I have used, beginning with
8749 \begin_inset Flex CharStyle:Code
8752 \begin_layout Plain Layout
8755 begin{Chunk}[options]
8760 --- also more suitable for plain LaTeX users
8764 \begin_layout Plain Layout
8765 Is there such a thing as plain LaTeX?
8773 \begin_layout Section
8777 \begin_layout Standard
8779 \begin_inset Flex CharStyle:Code
8782 \begin_layout Plain Layout
8788 is used to signify that we are processing a code chunk and not document.
8789 In such a state, input lines will be assigned to the current chunk; otherwise
8793 \begin_layout Subsection
8797 \begin_layout Standard
8798 Our current scheme is to recognize the new lstlisting chunks, but these
8799 may be preceded by a
8800 \begin_inset Flex CharStyle:Code
8803 \begin_layout Plain Layout
8811 command which in LyX is a more convenient way to pass the chunk name to
8813 \begin_inset Flex CharStyle:Code
8816 \begin_layout Plain Layout
8824 command, and a more visible way to specify other
8825 \begin_inset Flex CharStyle:Code
8828 \begin_layout Plain Layout
8837 \begin_layout Standard
8838 The arguments to the
8839 \begin_inset Flex CharStyle:Code
8842 \begin_layout Plain Layout
8850 command are a name, and then a comma-seperated list of key-value pairs
8852 \begin_inset Flex CharStyle:Code
8855 \begin_layout Plain Layout
8864 (In fact within the LaTeX
8865 \begin_inset Flex CharStyle:Code
8868 \begin_layout Plain Layout
8877 \begin_inset CommandInset ref
8879 reference "sub:The-chunk-command"
8884 \begin_inset Flex CharStyle:Code
8887 \begin_layout Plain Layout
8893 is prefixed to the argument which is then literally passed to
8894 \begin_inset Flex CharStyle:Code
8897 \begin_layout Plain Layout
8909 recognize-chunk,language=awk
8912 \begin_layout Standard
8913 \begin_inset listings
8917 \begin_layout Plain Layout
8926 \begin_layout Plain Layout
8936 Chunk{ *([^ ,}]*),?(.*)}", line)) {
8939 \begin_layout Plain Layout
8941 next_chunk_name = line[1];
8944 \begin_layout Plain Layout
8946 get_chunk_args(line[2], next_chunk_args);
8949 \begin_layout Plain Layout
8954 \begin_layout Plain Layout
8959 \begin_layout Plain Layout
8969 \begin_layout Standard
8970 We also make a basic attempt to parse the name out of the
8971 \begin_inset Flex CharStyle:Code
8974 \begin_layout Plain Layout
8978 \begin_inset space \hspace{}
8987 text, otherwise we fall back to the name found in the previous chunk command.
8988 This attempt is very basic and doesn't support commas or spaces or square
8989 brackets as part of the chunkname.
8991 \begin_inset Flex CharStyle:Code
8994 \begin_layout Plain Layout
9002 which is convenient for some users
9006 \begin_layout Plain Layout
9007 but not yet supported in the LaTeX macros
9013 \begin_inset Note Note
9016 \begin_layout Plain Layout
9025 \begin_layout Standard
9026 \begin_inset listings
9030 \begin_layout Plain Layout
9043 \begin_layout Plain Layout
9045 if (match($0, "}.*[[,] *name= *{? *([^], }]*)", line)) {
9048 \begin_layout Plain Layout
9053 \begin_layout Plain Layout
9058 \begin_layout Plain Layout
9060 new_chunk(next_chunk_name, next_chunk_args);
9063 \begin_layout Plain Layout
9068 \begin_layout Plain Layout
9073 \begin_layout Plain Layout
9078 \begin_layout Plain Layout
9088 \begin_layout Subsection
9092 \begin_layout Standard
9093 We recognize notangle style chunks too:
9097 recognize-chunk,language=awk
9100 \begin_layout Standard
9101 \begin_inset listings
9105 \begin_layout Plain Layout
9110 \begin_layout Plain Layout
9112 if (match($0, "^[<]<(.*)[>]>= *$", line)) {
9115 \begin_layout Plain Layout
9120 \begin_layout Plain Layout
9125 \begin_layout Plain Layout
9130 \begin_layout Plain Layout
9135 \begin_layout Plain Layout
9140 \begin_layout Plain Layout
9150 \begin_layout Section
9154 \begin_layout Standard
9155 Likewise, we need to recognize when a chunk ends.
9158 \begin_layout Subsection
9162 \begin_layout Standard
9164 \begin_inset Flex CharStyle:Code
9167 \begin_layout Plain Layout
9174 \begin_inset Flex CharStyle:Code
9177 \begin_layout Plain Layout
9183 is surrounded by square brackets so that when this document is processed,
9184 this chunk doesn't terminate early when the lstlistings package recognizes
9185 it's own end-string!
9186 \begin_inset Note Greyedout
9189 \begin_layout Plain Layout
9190 This doesn't make sense as the regex is anchored with ^, which this line
9191 does not begin with!
9197 \begin_inset Note Note
9200 \begin_layout Plain Layout
9213 \begin_layout Standard
9214 \begin_inset listings
9218 \begin_layout Plain Layout
9231 \begin_layout Plain Layout
9236 \begin_layout Plain Layout
9241 \begin_layout Plain Layout
9246 \begin_layout Plain Layout
9256 \begin_layout Subsection
9264 \begin_layout Standard
9265 \begin_inset listings
9269 \begin_layout Plain Layout
9274 \begin_layout Plain Layout
9279 \begin_layout Plain Layout
9284 \begin_layout Plain Layout
9294 \begin_layout Standard
9295 All other recognizers are only of effect if we are chunking; there's no
9296 point in looking at lines if they aren't part of a chunk, so we just ignore
9297 them as efficiently as we can.
9304 \begin_layout Standard
9305 \begin_inset listings
9309 \begin_layout Plain Layout
9311 ! chunking { next; }
9319 \begin_layout Section
9323 \begin_layout Standard
9324 Chunk contents are any lines read while
9325 \begin_inset Flex CharStyle:Code
9328 \begin_layout Plain Layout
9335 Some chunk contents are special in that they refer to other chunks, and
9336 will be replaced by the contents of these chunks when the file is generated.
9339 \begin_layout Standard
9340 \begin_inset CommandInset label
9342 name "sub:ORS-chunk-text"
9346 We add the output record separator
9347 \begin_inset Flex CharStyle:Code
9350 \begin_layout Plain Layout
9356 to the line now, because we will set
9357 \begin_inset Flex CharStyle:Code
9360 \begin_layout Plain Layout
9366 to the empty string when we generate the output
9370 \begin_layout Plain Layout
9371 So that we can print partial lines using
9372 \begin_inset Flex CharStyle:Code
9375 \begin_layout Plain Layout
9382 \begin_inset Flex CharStyle:Code
9385 \begin_layout Plain Layout
9403 \begin_layout Standard
9404 \begin_inset listings
9408 \begin_layout Plain Layout
9410 length(active_chunk) {
9413 \begin_layout Plain Layout
9417 chunkref{process-chunk-tabs}>
9420 \begin_layout Plain Layout
9424 chunkref{process-chunk}>
9427 \begin_layout Plain Layout
9437 \begin_layout Standard
9438 If a chunk just consisted of plain text, we could handle the chunk like
9443 process-chunk-simple
9446 \begin_layout Standard
9447 \begin_inset listings
9451 \begin_layout Plain Layout
9453 chunk_line(active_chunk, $0 ORS);
9461 \begin_layout Standard
9462 but in fact a chunk can include references to other chunks.
9463 Chunk includes are traditionally written as
9464 \begin_inset Flex CharStyle:Code
9467 \begin_layout Plain Layout
9473 , but we support other variations.
9476 \begin_layout Standard
9477 However, we also process tabs at this point, a tab at input can be replaced
9478 by a number of spaces defined by the
9479 \begin_inset Flex CharStyle:Code
9482 \begin_layout Plain Layout
9488 variable, set by the
9489 \begin_inset Flex CharStyle:Code
9492 \begin_layout Plain Layout
9499 Of course this is poor tab behaviour, we should probably have the option
9500 to use proper counted tab-stops and process this on output.
9507 \begin_layout Standard
9508 \begin_inset listings
9512 \begin_layout Plain Layout
9517 \begin_layout Plain Layout
9524 \begin_layout Plain Layout
9534 \begin_layout Subsection
9535 \begin_inset CommandInset label
9537 name "sub:lstlistings-includes"
9544 \begin_layout Standard
9546 \begin_inset Flex CharStyle:Code
9549 \begin_layout Plain Layout
9552 lstset{escapeinside={=<}{>}}
9557 is set, then we can use
9558 \begin_inset Flex CharStyle:Code
9561 \begin_layout Plain Layout
9565 \begin_inset space \hspace{}
9576 \begin_inset Flex CharStyle:Code
9579 \begin_layout Plain Layout
9588 \begin_layout Enumerate
9589 it is a better mnemonic than
9590 \begin_inset Flex CharStyle:Code
9593 \begin_layout Plain Layout
9599 in that the = sign signifies equivalent or substitutability,
9602 \begin_layout Enumerate
9603 and because =< is not valid in C or in any language I can think of
9606 \begin_layout Enumerate
9607 and also because lstlistings doesn't like
9608 \begin_inset Flex CharStyle:Code
9611 \begin_layout Plain Layout
9617 as an end delimiter for the
9621 escape, so we must make do with a single
9622 \begin_inset Flex CharStyle:Code
9625 \begin_layout Plain Layout
9631 , which is better matched by
9632 \begin_inset Flex CharStyle:Code
9635 \begin_layout Plain Layout
9642 \begin_inset Flex CharStyle:Code
9645 \begin_layout Plain Layout
9654 \begin_layout Standard
9656 \begin_inset Note Note
9659 \begin_layout Plain Layout
9666 \begin_inset Flex CharStyle:Code
9669 \begin_layout Plain Layout
9670 =<\SpecialChar \ldots{}
9676 that we use re-enters a LaTeX parsing mode in which some characters are
9679 \begin_inset Flex CharStyle:Code
9682 \begin_layout Plain Layout
9690 , and so these cause trouble if used in arguments to
9691 \begin_inset Flex CharStyle:Code
9694 \begin_layout Plain Layout
9703 At some point I must fix the LaTeX command
9704 \begin_inset Flex CharStyle:Code
9707 \begin_layout Plain Layout
9715 so that it can accept these literally, but until then, when writing chunkref
9716 argumemts that need these characters, I must use the forms
9717 \begin_inset Flex CharStyle:Code
9720 \begin_layout Plain Layout
9729 \begin_inset Flex CharStyle:Code
9732 \begin_layout Plain Layout
9740 ; so I also define a hacky chunk
9741 \begin_inset Flex CharStyle:Code
9744 \begin_layout Plain Layout
9750 whose purpose it is to remove these from any arguments parsed by newfangle,
9751 and used further on.
9758 \begin_layout Standard
9759 \begin_inset listings
9763 \begin_layout Plain Layout
9768 \begin_layout Plain Layout
9781 \begin_layout Plain Layout
9798 \begin_layout Plain Layout
9820 \begin_layout Standard
9821 As each chunk line may contain more than one chunk include, we will split
9822 out chunk includes in an iterative fashion
9826 \begin_layout Plain Layout
9827 Contrary to our use of
9828 \begin_inset Flex CharStyle:Code
9831 \begin_layout Plain Layout
9837 when substituting parameters in chapter
9838 \begin_inset CommandInset ref
9840 reference "Here-we-split"
9852 \begin_layout Standard
9853 First, as long as the chunk contains a
9854 \begin_inset Flex CharStyle:Code
9857 \begin_layout Plain Layout
9865 command we take as much as we can up to the first
9866 \begin_inset Flex CharStyle:Code
9869 \begin_layout Plain Layout
9884 \begin_layout Standard
9885 \begin_inset listings
9889 \begin_layout Plain Layout
9894 \begin_layout Plain Layout
9899 \begin_layout Plain Layout
9904 \begin_layout Plain Layout
9922 )|)>|<<([a-zA-Z_][-a-zA-Z0-9_]*)>>)",
9925 \begin_layout Plain Layout
9932 \begin_layout Plain Layout
9937 \begin_layout Plain Layout
9939 chunklet = substr(chunk, 1, RSTART - 1);
9947 \begin_layout Standard
9948 We keep track of the indent count, by counting the number of literal characters
9950 We can then preserve this indent on each output line when multi-line chunks
9954 \begin_layout Standard
9955 We then process this first part literal text, and set the chunk which is
9956 still to be processed to be the text after the
9957 \begin_inset Flex CharStyle:Code
9960 \begin_layout Plain Layout
9968 command, which we will process next as we continue around the loop.
9971 \begin_layout Standard
9972 \begin_inset listings
9976 \begin_layout Plain Layout
9978 indent += length(chunklet);
9981 \begin_layout Plain Layout
9983 chunk_line(active_chunk, chunklet);
9986 \begin_layout Plain Layout
9988 chunk = substr(chunk, RSTART + RLENGTH);
9996 \begin_layout Standard
9997 We then consider the type of chunk command we have found, whether it is
9998 the newfangle style command beginning with
9999 \begin_inset Flex CharStyle:Code
10002 \begin_layout Plain Layout
10008 or the older notangle style beginning with
10009 \begin_inset Flex CharStyle:Code
10012 \begin_layout Plain Layout
10022 \begin_layout Standard
10023 Newfangle chunks may have parameters contained within square brackets.
10024 These will be matched in
10025 \begin_inset Flex CharStyle:Code
10028 \begin_layout Plain Layout
10034 and are considered at this stage of processing to be part of the name of
10035 the chunk to be included.
10038 \begin_layout Standard
10039 \begin_inset listings
10043 \begin_layout Plain Layout
10045 if (substr(line[1], 1, 1) == "=") {
10048 \begin_layout Plain Layout
10050 # chunk name up to }
10053 \begin_layout Plain Layout
10057 chunkref{delatex}(line[3])>
10060 \begin_layout Plain Layout
10062 chunk_include(active_chunk, line[2] line[3], indent);
10065 \begin_layout Plain Layout
10067 } else if (substr(line[1], 1, 1) == "<") {
10070 \begin_layout Plain Layout
10072 chunk_include(active_chunk, line[4], indent);
10075 \begin_layout Plain Layout
10080 \begin_layout Plain Layout
10082 error("Unknown chunk fragment: " line[1]);
10085 \begin_layout Plain Layout
10095 \begin_layout Standard
10096 The loop will continue until there are no more chunkref statements in the
10097 text, at which point we process the final part of the chunk.
10100 \begin_layout Standard
10101 \begin_inset listings
10105 \begin_layout Plain Layout
10110 \begin_layout Plain Layout
10112 chunk_line(active_chunk, chunk);
10120 \begin_layout Standard
10121 \begin_inset CommandInset label
10123 name "lone-newline"
10127 We add the newline character as a chunklet on it's own, to make it easier
10128 to detect new lines and thus manage indentation when processing the output.
10131 \begin_layout Standard
10132 \begin_inset listings
10136 \begin_layout Plain Layout
10138 chunk_line(active_chunk, "
10148 \begin_layout Standard
10149 We will also permit a chunk-part number to follow in square brackets, so
10151 \begin_inset Flex CharStyle:Code
10154 \begin_layout Plain Layout
10157 chunkref{chunk-name[1]}>
10162 will refer to the first part only.
10163 This can make it easy to include a C function prototype in a header file,
10164 if the first part of the chunk is just the function prototype without the
10165 trailing semi-colon.
10166 The header file would include the prototype with the trailing semi-colon,
10170 \begin_layout LyX-Code
10173 chunkref{chunk-name[1]}>;
10176 \begin_layout Standard
10177 This is handled in section
10178 \begin_inset CommandInset ref
10180 reference "sub:Chunk-parts"
10187 \begin_layout Standard
10188 We should perhaps introduce a notion of language specific chunk options;
10189 so that perhaps we could specify:
10192 \begin_layout LyX-Code
10195 chunkref{chunk-name[function-declaration]}>;
10198 \begin_layout Standard
10199 which applies a transform
10200 \begin_inset Flex CharStyle:Code
10203 \begin_layout Plain Layout
10204 function-declaration
10209 to the chunk --- which in this case would extract a function prototype
10211 \begin_inset Note Note
10214 \begin_layout Plain Layout
10223 \begin_layout Chapter
10227 \begin_layout Standard
10228 At the start, first we set the default options.
10231 \begin_layout Chunk
10235 \begin_layout Standard
10236 \begin_inset listings
10240 \begin_layout Plain Layout
10245 \begin_layout Plain Layout
10250 \begin_layout Plain Layout
10255 \begin_layout Plain Layout
10260 \begin_layout Plain Layout
10270 \begin_layout Standard
10271 Then we use getopt the standard way, and null out ARGV afterwards in the
10272 normal AWK fashion.
10275 \begin_layout Chunk
10279 \begin_layout Standard
10280 \begin_inset listings
10284 \begin_layout Plain Layout
10286 Optind = 1 # skip ARGV[0]
10289 \begin_layout Plain Layout
10291 while(getopt(ARGC, ARGV, "R:LdT:hr")!=-1) {
10294 \begin_layout Plain Layout
10298 chunkref{handle-options}>
10301 \begin_layout Plain Layout
10306 \begin_layout Plain Layout
10308 for (i=1; i<Optind; i++) { ARGV[i]=""; }
10316 \begin_layout Standard
10317 This is how we handle our options:
10320 \begin_layout Chunk
10324 \begin_layout Standard
10325 \begin_inset listings
10329 \begin_layout Plain Layout
10331 if (Optopt == "R") root = Optarg;
10334 \begin_layout Plain Layout
10336 else if (Optopt == "r") root="";
10339 \begin_layout Plain Layout
10341 else if (Optopt == "L") linenos = 1;
10344 \begin_layout Plain Layout
10346 else if (Optopt == "d") debug = 1;
10349 \begin_layout Plain Layout
10351 else if (Optopt == "T") tabs = indent_string(Optarg+0);
10354 \begin_layout Plain Layout
10356 else if (Optopt == "h") help();
10359 \begin_layout Plain Layout
10361 else if (Optopt == "?") help();
10369 \begin_layout Standard
10370 We do all of this at the beginning of the program
10373 \begin_layout Chunk
10377 \begin_layout Standard
10378 \begin_inset listings
10382 \begin_layout Plain Layout
10387 \begin_layout Plain Layout
10391 chunkref{constants}>
10394 \begin_layout Plain Layout
10398 chunkref{mode-definitions}>
10401 \begin_layout Plain Layout
10405 chunkref{default-options}>
10408 \begin_layout Plain Layout
10412 \begin_layout Plain Layout
10416 chunkref{read-options}>
10419 \begin_layout Plain Layout
10429 \begin_layout Standard
10430 And have a simple help function
10433 \begin_layout Chunk
10437 \begin_layout Standard
10438 \begin_inset listings
10442 \begin_layout Plain Layout
10447 \begin_layout Plain Layout
10452 \begin_layout Plain Layout
10454 print " newfangle [-L] -R<rootname> [source.tex ...]"
10457 \begin_layout Plain Layout
10459 print " newfangle -r [source.tex ...]"
10462 \begin_layout Plain Layout
10464 print " If the filename, source.tex is not specified then stdin is used"
10467 \begin_layout Plain Layout
10472 \begin_layout Plain Layout
10474 print "-L causes the C statement: #line <lineno>
10481 \begin_layout Plain Layout
10483 print "-R causes the named root to be written to stdout"
10486 \begin_layout Plain Layout
10488 print "-r lists all roots in the file (even those used elsewhere)"
10491 \begin_layout Plain Layout
10496 \begin_layout Plain Layout
10506 \begin_layout Chapter
10507 Generating the output
10510 \begin_layout Standard
10511 We generate output by calling output_chunk, or listing the chunk names.
10514 \begin_layout Chunk
10518 \begin_layout Standard
10519 \begin_inset listings
10523 \begin_layout Plain Layout
10525 if (length(root)) output_chunk(root);
10528 \begin_layout Plain Layout
10530 else output_chunk_names();
10538 \begin_layout Standard
10539 We also have some other output debugging:
10542 \begin_layout Chunk
10546 \begin_layout Standard
10547 \begin_inset listings
10551 \begin_layout Plain Layout
10556 \begin_layout Plain Layout
10558 print "------ chunk names "
10561 \begin_layout Plain Layout
10563 output_chunk_names();
10566 \begin_layout Plain Layout
10568 print "====== chunks"
10571 \begin_layout Plain Layout
10576 \begin_layout Plain Layout
10578 print "++++++ debug"
10581 \begin_layout Plain Layout
10583 for (a in chunks) {
10586 \begin_layout Plain Layout
10588 print a "=" chunks[a];
10591 \begin_layout Plain Layout
10596 \begin_layout Plain Layout
10606 \begin_layout Standard
10607 We do both of these at the end.
10609 \begin_inset Flex CharStyle:Code
10612 \begin_layout Plain Layout
10618 because each chunklet is not necessarily a complete line, and we already
10620 \begin_inset Flex CharStyle:Code
10623 \begin_layout Plain Layout
10629 to each input line in section
10630 \begin_inset CommandInset ref
10632 reference "sub:ORS-chunk-text"
10639 \begin_layout Chunk
10643 \begin_layout Standard
10644 \begin_inset listings
10648 \begin_layout Plain Layout
10653 \begin_layout Plain Layout
10657 chunkref{debug-output}>
10660 \begin_layout Plain Layout
10665 \begin_layout Plain Layout
10669 chunkref{generate-output}>
10672 \begin_layout Plain Layout
10682 \begin_layout Standard
10683 We write chunk names like this.
10684 If we seem to be running in notangle compatibility mode, then we enclose
10686 \begin_inset Flex CharStyle:Code
10689 \begin_layout Plain Layout
10695 the same way notangle does:
10698 \begin_layout Chunk
10699 output_chunk_names()
10702 \begin_layout Standard
10703 \begin_inset listings
10707 \begin_layout Plain Layout
10709 function output_chunk_names( c, prefix, suffix)
10712 \begin_layout Plain Layout
10717 \begin_layout Plain Layout
10719 if (notangle_mode) {
10722 \begin_layout Plain Layout
10727 \begin_layout Plain Layout
10732 \begin_layout Plain Layout
10737 \begin_layout Plain Layout
10739 for (c in chunk_names) {
10742 \begin_layout Plain Layout
10744 print prefix c suffix "
10749 \begin_layout Plain Layout
10754 \begin_layout Plain Layout
10764 \begin_layout Standard
10765 This function would write out all chunks
10768 \begin_layout Chunk
10772 \begin_layout Standard
10773 \begin_inset listings
10777 \begin_layout Plain Layout
10779 function output_chunks( a)
10782 \begin_layout Plain Layout
10787 \begin_layout Plain Layout
10789 for (a in chunk_names) {
10792 \begin_layout Plain Layout
10794 output_chunk(chunk_names[a]);
10797 \begin_layout Plain Layout
10802 \begin_layout Plain Layout
10807 \begin_layout Plain Layout
10811 \begin_layout Plain Layout
10813 function output_chunk(chunk) {
10816 \begin_layout Plain Layout
10821 \begin_layout Plain Layout
10823 lineno_needed = linenos;
10826 \begin_layout Plain Layout
10830 \begin_layout Plain Layout
10832 write_chunk(chunk);
10835 \begin_layout Plain Layout
10840 \begin_layout Plain Layout
10849 \begin_layout Section
10850 Assembling the chunks
10853 \begin_layout Standard
10854 \begin_inset Flex CharStyle:Code
10857 \begin_layout Plain Layout
10863 holds a string consisting of the names of all the chunks that resulted
10864 in this chunk being output.
10866 \begin_inset Note Note
10869 \begin_layout Plain Layout
10870 Make sure it includes the line numbers too...
10876 It should probably also contain the source line numbers at which each inclusion
10880 \begin_layout Chunk
10884 \begin_layout Standard
10885 We first initialize the mode tracker for this chunk.
10888 \begin_layout Standard
10889 \begin_inset listings
10893 \begin_layout Plain Layout
10895 function write_chunk(chunk_name) {
10898 \begin_layout Plain Layout
10902 chunkref{awk-delete-array}(context)>
10905 \begin_layout Plain Layout
10907 return write_chunk_r(chunk_name, context);
10910 \begin_layout Plain Layout
10920 \begin_layout Chunk
10921 write_chunk(),emph={chunk_path}
10924 \begin_layout Standard
10925 \begin_inset listings
10929 \begin_layout Plain Layout
10931 function write_chunk_r(chunk_name, context, indent, tail,
10934 \begin_layout Plain Layout
10939 \begin_layout Plain Layout
10941 chunk_path, chunk_args,
10944 \begin_layout Plain Layout
10946 s, r, src, new_src,
10949 \begin_layout Plain Layout
10954 \begin_layout Plain Layout
10956 chunk_params, part, max_part, part_line, frag, max_frag, text,
10959 \begin_layout Plain Layout
10961 chunklet, only_part, call_chunk_args, new_context)
10964 \begin_layout Plain Layout
10974 \begin_layout Subsection
10975 \begin_inset CommandInset label
10977 name "sub:Chunk-parts"
10984 \begin_layout Standard
10985 As mentioned in section
10986 \begin_inset CommandInset ref
10988 reference "sub:lstlistings-includes"
10992 , a chunk name may contain a part specifier in square brackets, limiting
10993 the parts that should be emitted.
10996 \begin_layout Standard
10997 \begin_inset listings
11001 \begin_layout Plain Layout
11003 if (match(chunk_name, "^(.*)
11011 ]$", chunk_name_parts)) {
11014 \begin_layout Plain Layout
11016 chunk_name = chunk_name_parts[1];
11019 \begin_layout Plain Layout
11021 only_part = chunk_name_parts[2];
11024 \begin_layout Plain Layout
11034 \begin_layout Standard
11035 We then create a mode tracker
11038 \begin_layout Standard
11039 \begin_inset listings
11043 \begin_layout Plain Layout
11047 chunkref{new-mode-tracker}(context, chunks[chunk_name, "language"], "")>
11055 \begin_layout Standard
11057 \begin_inset Flex CharStyle:Code
11060 \begin_layout Plain Layout
11066 the names of the parameters that this chunk accepts, whose values were
11067 (optionally) passed in
11068 \begin_inset Flex CharStyle:Code
11071 \begin_layout Plain Layout
11080 \begin_layout Standard
11081 \begin_inset listings
11085 \begin_layout Plain Layout
11087 split(chunks[chunk_name, "params"], chunk_params, " *; *");
11095 \begin_layout Standard
11096 To assemble a chunk, we write out each part.
11099 \begin_layout Chunk
11103 \begin_layout Standard
11104 \begin_inset listings
11108 \begin_layout Plain Layout
11110 if (! (chunk_name in chunk_names)) {
11113 \begin_layout Plain Layout
11115 error(sprintf(_"The root module <<%s>> was not defined.
11122 \begin_layout Plain Layout
11124 chunk_name, chunk_path));
11127 \begin_layout Plain Layout
11132 \begin_layout Plain Layout
11136 \begin_layout Plain Layout
11138 max_part = chunks[chunk_name, "part"];
11141 \begin_layout Plain Layout
11143 for(part = 1; part <= max_part; part++) {
11146 \begin_layout Plain Layout
11148 if (! only_part || part == only_part) {
11151 \begin_layout Plain Layout
11155 chunkref{write-part}>
11158 \begin_layout Plain Layout
11163 \begin_layout Plain Layout
11168 \begin_layout Plain Layout
11170 if (! finalize_mode_tracker(context)) {
11173 \begin_layout Plain Layout
11175 dump_mode_tracker(context);
11178 \begin_layout Plain Layout
11180 error(sprintf(_"Module %s did not close context properly.
11184 n", chunk_name, chunk_path));
11187 \begin_layout Plain Layout
11192 \begin_layout Plain Layout
11202 \begin_layout Standard
11203 A part can either be a chunklet of lines, or an include of another chunk.
11206 \begin_layout Standard
11207 Chunks may also have parameters, specified in LaTeX style with braces after
11208 the chunk name --- looking like this in the document:
11209 \begin_inset Flex CharStyle:Code
11212 \begin_layout Plain Layout
11213 chunkname{param1, param2}
11219 Arguments are passed in square brackets:
11220 \begin_inset Flex CharStyle:Code
11223 \begin_layout Plain Layout
11226 chunkref{chunkname}[arg1, arg2]
11234 \begin_layout Standard
11235 Before we process each part, we check that the source position hasn't changed
11236 unexpectedly, so that we can know if we need to output a new file-line
11240 \begin_layout Chunk
11244 \begin_layout Standard
11245 \begin_inset listings
11249 \begin_layout Plain Layout
11253 chunkref{check-source-jump}>
11256 \begin_layout Plain Layout
11260 \begin_layout Plain Layout
11262 chunklet = chunks[chunk_name, "part", part];
11265 \begin_layout Plain Layout
11267 if (chunks[chunk_name, "part", part, "type"] == part_type_chunk) {
11270 \begin_layout Plain Layout
11274 chunkref{write-included-chunk}>
11277 \begin_layout Plain Layout
11279 } else if (chunklet SUBSEP "line" in chunks) {
11282 \begin_layout Plain Layout
11286 chunkref{write-chunklets}>
11289 \begin_layout Plain Layout
11294 \begin_layout Plain Layout
11296 # empty last chunklet
11299 \begin_layout Plain Layout
11309 \begin_layout Standard
11310 To write an included chunk, we must detect any optional chunk arguments
11312 Then we recurse calling
11313 \begin_inset Flex Chunkref
11316 \begin_layout Plain Layout
11325 \begin_layout Chunk
11326 write-included-chunk
11329 \begin_layout Standard
11330 \begin_inset listings
11334 \begin_layout Plain Layout
11336 if (match(chunklet, "^([^
11352 )$", chunklet_parts)) {
11355 \begin_layout Plain Layout
11357 chunklet = chunklet_parts[1];
11360 \begin_layout Plain Layout
11362 parse_chunk_args("c-like", chunklet_parts[2], call_chunk_args, "(");
11365 \begin_layout Plain Layout
11367 for (c in call_chunk_args) {
11370 \begin_layout Plain Layout
11372 call_chunk_args[c] = expand_chunk_args(call_chunk_args[c], chunk_params,
11376 \begin_layout Plain Layout
11381 \begin_layout Plain Layout
11386 \begin_layout Plain Layout
11388 split("", call_chunk_args);
11391 \begin_layout Plain Layout
11396 \begin_layout Plain Layout
11398 # update the transforms arrays
11401 \begin_layout Plain Layout
11403 new_src = mode_escaper(context, s, r, src);
11406 \begin_layout Plain Layout
11410 chunkref{awk-delete-array}(new_context)>
11413 \begin_layout Plain Layout
11415 write_chunk_r(chunklet, new_context,
11418 \begin_layout Plain Layout
11420 chunks[chunk_name, "part", part, "indent"] indent,
11423 \begin_layout Plain Layout
11425 chunks[chunk_name, "part", part, "tail"],
11428 \begin_layout Plain Layout
11435 \begin_layout Plain Layout
11440 \begin_layout Plain Layout
11450 \begin_layout Standard
11451 Before we output a chunklet of lines, we first emit the file and line number
11452 if we have one, and if it is safe to do so.
11456 \begin_layout Standard
11457 Chunklets are generally broken up by includes, so the start of a chunklet
11458 is a good place to do this.
11459 Then we output each line of the chunklet.
11462 \begin_layout Standard
11463 When it is not safe, such as in the middle of a multi-line macro definition,
11465 \begin_inset Flex CharStyle:Code
11468 \begin_layout Plain Layout
11474 is set to true, and in such a case we note that we want to emit the line
11475 statement when it is next safe.
11478 \begin_layout Chunk
11482 \begin_layout Standard
11483 \begin_inset listings
11487 \begin_layout Plain Layout
11489 max_frag = chunks[chunklet, "line"];
11492 \begin_layout Plain Layout
11494 for(frag = 1; frag <= max_frag; frag++) {
11497 \begin_layout Plain Layout
11501 chunkref{write-file-line}>
11509 \begin_layout Standard
11510 We then extract the chunklet text and expand any arguments.
11513 \begin_layout Standard
11514 \begin_inset listings
11518 \begin_layout Plain Layout
11522 \begin_layout Plain Layout
11524 text = chunks[chunklet, frag];
11527 \begin_layout Plain Layout
11532 \begin_layout Plain Layout
11537 \begin_layout Plain Layout
11539 text = expand_chunk_args(text, chunk_params, chunk_args);
11547 \begin_layout Standard
11548 If the text is a single newline (which we keep separate - see
11549 \begin_inset CommandInset ref
11551 reference "lone-newline"
11555 ) then we increment the line number.
11556 In the case where this is the last line of a chunk and it is not a top-level
11557 chunk we replace the newline with an empty string --- because the chunk
11558 that included this chunk will have the newline at the end of the line that
11559 included this chunk.
11562 \begin_layout Standard
11564 \begin_inset Flex CharStyle:Code
11567 \begin_layout Plain Layout
11573 that we have started a new line, so that indentation can be managed with
11574 the following piece of text.
11577 \begin_layout Standard
11578 \begin_inset listings
11582 \begin_layout Plain Layout
11586 \begin_layout Plain Layout
11593 \begin_layout Plain Layout
11598 \begin_layout Plain Layout
11600 if (part == max_part && frag == max_frag && length(chunk_path)) {
11603 \begin_layout Plain Layout
11608 \begin_layout Plain Layout
11613 \begin_layout Plain Layout
11618 \begin_layout Plain Layout
11623 \begin_layout Plain Layout
11633 \begin_layout Standard
11634 If this text does not represent a newline, but we see that we are the first
11635 piece of text on a newline, then we prefix our text with the current indent.
11637 \begin_inset Flex CharStyle:Code
11640 \begin_layout Plain Layout
11646 is a global output-state variable, but the
11647 \begin_inset Flex CharStyle:Code
11650 \begin_layout Plain Layout
11660 \begin_layout Standard
11661 \begin_inset listings
11665 \begin_layout Plain Layout
11667 } else if (length(text) || length(tail)) {
11670 \begin_layout Plain Layout
11672 if (newline) text = indent text;
11675 \begin_layout Plain Layout
11680 \begin_layout Plain Layout
11685 \begin_layout Plain Layout
11694 \begin_layout Standard
11695 Tail will soon no longer be relevant once mode-detection is in place.
11698 \begin_layout Standard
11699 \begin_inset listings
11703 \begin_layout Plain Layout
11708 \begin_layout Plain Layout
11710 mode_tracker(context, text);
11713 \begin_layout Plain Layout
11715 print transform_escape(s, r, text, src);
11723 \begin_layout Standard
11724 If a line ends in a backslash --- suggesting continuation --- then we supress
11725 outputting file-line as it would probably break the continued lines.
11729 \begin_layout Standard
11730 \begin_inset listings
11734 \begin_layout Plain Layout
11739 \begin_layout Plain Layout
11741 lineno_suppressed = substr(lastline, length(lastline)) == "
11748 \begin_layout Plain Layout
11753 \begin_layout Plain Layout
11763 \begin_layout Standard
11764 Of course there is no point in actually outputting the source filename and
11765 line number (file-line) if they don't say anything new! We only need to
11766 emit them if they aren't what is expected, or if we we not able to emit
11767 one when they had changed.
11770 \begin_layout Chunk
11774 \begin_layout Standard
11775 \begin_inset listings
11779 \begin_layout Plain Layout
11781 if (newline && lineno_needed && ! lineno_suppressed) {
11784 \begin_layout Plain Layout
11786 filename = a_filename;
11789 \begin_layout Plain Layout
11794 \begin_layout Plain Layout
11796 print "#line " lineno "
11805 \begin_layout Plain Layout
11810 \begin_layout Plain Layout
11820 \begin_layout Standard
11821 We check if a new file-line is needed by checking if the source line matches
11822 what we (or a compiler) would expect.
11826 \begin_layout Chunk
11830 \begin_layout Standard
11831 \begin_inset listings
11835 \begin_layout Plain Layout
11837 if (linenos && (chunk_name SUBSEP "part" SUBSEP part SUBSEP "FILENAME" in
11841 \begin_layout Plain Layout
11843 a_filename = chunks[chunk_name, "part", part, "FILENAME"];
11846 \begin_layout Plain Layout
11848 a_lineno = chunks[chunk_name, "part", part, "LINENO"];
11851 \begin_layout Plain Layout
11853 if (a_filename != filename || a_lineno != lineno) {
11856 \begin_layout Plain Layout
11861 \begin_layout Plain Layout
11866 \begin_layout Plain Layout
11876 \begin_layout Chapter
11880 \begin_layout Standard
11881 Awk has pretty limited data structures, so we will use two main hashes.
11882 Uninterrupted sequences of a chunk will be stored in
11883 \begin_inset Flex CharStyle:Code
11886 \begin_layout Plain Layout
11892 and the chunklets used in a chunk will be stored in
11893 \begin_inset Flex CharStyle:Code
11896 \begin_layout Plain Layout
11905 \begin_layout Chunk
11909 \begin_layout Standard
11910 \begin_inset listings
11914 \begin_layout Plain Layout
11919 \begin_layout Plain Layout
11929 \begin_layout Standard
11931 \begin_inset Flex CharStyle:Code
11934 \begin_layout Plain Layout
11940 mentioned are not chunk parameters for parameterized chunks, as mentioned
11942 \begin_inset CommandInset ref
11944 reference "cha:Chunk Arguments"
11948 , but the lstlistings style parameters used in the
11949 \begin_inset Flex CharStyle:Code
11952 \begin_layout Plain Layout
11964 \begin_layout Plain Layout
11966 \begin_inset Flex CharStyle:Code
11969 \begin_layout Plain Layout
11975 parameter is used to hold the parameters for parameterized chunks
11983 \begin_layout Chunk
11984 chunk-storage-functions
11987 \begin_layout Standard
11988 \begin_inset listings
11992 \begin_layout Plain Layout
11994 function new_chunk(chunk_name, params,
11997 \begin_layout Plain Layout
12002 \begin_layout Plain Layout
12007 \begin_layout Plain Layout
12012 \begin_layout Plain Layout
12014 # HACK WHILE WE CHANGE TO ( ) for PARAM CHUNKS
12017 \begin_layout Plain Layout
12027 )$", "", chunk_name);
12030 \begin_layout Plain Layout
12032 if (! (chunk_name in chunk_names)) {
12035 \begin_layout Plain Layout
12037 if (debug) print "New chunk " chunk_name;
12040 \begin_layout Plain Layout
12042 chunk_names[chunk_name];
12045 \begin_layout Plain Layout
12047 for (p in params) {
12050 \begin_layout Plain Layout
12052 chunks[chunk_name, p] = params[p];
12055 \begin_layout Plain Layout
12060 \begin_layout Plain Layout
12062 if ("append" in params) {
12065 \begin_layout Plain Layout
12067 append=params["append"];
12070 \begin_layout Plain Layout
12072 if (! (append in chunk_names)) {
12075 \begin_layout Plain Layout
12077 warning("Chunk " chunk_name " is appended to chunk " append " which
12078 is not defined yet");
12081 \begin_layout Plain Layout
12086 \begin_layout Plain Layout
12091 \begin_layout Plain Layout
12093 chunk_include(append, chunk_name);
12096 \begin_layout Plain Layout
12098 chunk_line(append, ORS);
12101 \begin_layout Plain Layout
12106 \begin_layout Plain Layout
12111 \begin_layout Plain Layout
12113 active_chunk = chunk_name;
12116 \begin_layout Plain Layout
12118 prime_chunk(chunk_name);
12121 \begin_layout Plain Layout
12131 \begin_layout Standard
12132 \begin_inset listings
12136 \begin_layout Plain Layout
12140 \begin_layout Plain Layout
12142 function prime_chunk(chunk_name)
12145 \begin_layout Plain Layout
12150 \begin_layout Plain Layout
12152 chunks[chunk_name, "part", ++chunks[chunk_name, "part"] ] =
12157 \begin_layout Plain Layout
12159 chunk_name SUBSEP "chunklet" SUBSEP "" ++chunks[chunk_name, "chunklet"]
12163 \begin_layout Plain Layout
12165 chunks[chunk_name, "part", chunks[chunk_name, "part"], "FILENAME"] = FILENAME;
12168 \begin_layout Plain Layout
12170 chunks[chunk_name, "part", chunks[chunk_name, "part"], "LINENO"] = FNR
12174 \begin_layout Plain Layout
12179 \begin_layout Plain Layout
12183 \begin_layout Plain Layout
12185 function chunk_line(chunk_name, line){
12188 \begin_layout Plain Layout
12190 chunks[chunk_name, "chunklet", chunks[chunk_name, "chunklet"],
12193 \begin_layout Plain Layout
12195 ++chunks[chunk_name, "chunklet", chunks[chunk_name, "chunklet"],
12199 \begin_layout Plain Layout
12204 \begin_layout Plain Layout
12213 \begin_layout Standard
12214 Chunk include represents a
12218 statement, and stores the requirement to include another chunk.
12219 The parameter indent represents the quanity of literal text characters
12224 statement and therefore by how much additional lines of the included chunk
12225 should be indented.
12228 \begin_layout Standard
12229 \begin_inset listings
12233 \begin_layout Plain Layout
12235 function chunk_include(chunk_name, chunk_ref, indent, tail)
12238 \begin_layout Plain Layout
12243 \begin_layout Plain Layout
12245 chunks[chunk_name, "part", ++chunks[chunk_name, "part"] ] = chunk_ref;
12248 \begin_layout Plain Layout
12250 chunks[chunk_name, "part", chunks[chunk_name, "part"], "type" ] = part_type_ch
12254 \begin_layout Plain Layout
12256 chunks[chunk_name, "part", chunks[chunk_name, "part"], "indent" ] = indent_str
12260 \begin_layout Plain Layout
12262 chunks[chunk_name, "part", chunks[chunk_name, "part"], "tail" ] = tail;
12265 \begin_layout Plain Layout
12267 prime_chunk(chunk_name);
12270 \begin_layout Plain Layout
12275 \begin_layout Plain Layout
12284 \begin_layout Standard
12285 The indent is calculated by indent_string, which may in future convert some
12286 spaces into tab characters.
12287 This function works by generating a printf padded format string, like
12288 \begin_inset Flex CharStyle:Code
12291 \begin_layout Plain Layout
12297 for an indent of 22, and then printing an empty string using that format.
12300 \begin_layout Standard
12301 \begin_inset listings
12305 \begin_layout Plain Layout
12307 function indent_string(indent) {
12310 \begin_layout Plain Layout
12312 return sprintf("%" indent "s", "");
12315 \begin_layout Plain Layout
12325 \begin_layout Chapter
12326 \begin_inset CommandInset label
12335 \begin_layout Standard
12336 I use Arnold Robbins public domain getopt (1993 revision).
12337 This is probably the same one that is covered in chapter 12 of
12338 \begin_inset Quotes eld
12341 Edition 3 of GAWK: Effective AWK Programming: A User's Guide for GNU Awk
12342 \begin_inset Quotes erd
12345 but as that is licensed under the GNU Free Documentation License, Version
12346 1.3, which conflicts with the GPL3, I can't use it from there (or it's accompany
12347 ing explanations), so I do my best to explain how it works here.
12350 \begin_layout Standard
12351 The getopt.awk header is:
12354 \begin_layout Chunk
12355 getopt.awk-header,language=awk,morestring=[b]{/},morekeywords=else
12358 \begin_layout Standard
12359 \begin_inset listings
12363 \begin_layout Plain Layout
12365 # getopt.awk --- do C library getopt(3) function in awk
12368 \begin_layout Plain Layout
12373 \begin_layout Plain Layout
12375 # Arnold Robbins, arnold@skeeve.com, Public Domain
12378 \begin_layout Plain Layout
12383 \begin_layout Plain Layout
12385 # Initial version: March, 1991
12388 \begin_layout Plain Layout
12390 # Revised: May, 1993
12393 \begin_layout Plain Layout
12402 \begin_layout Standard
12403 The provided explanation is:
12406 \begin_layout Chunk
12410 \begin_layout Standard
12411 \begin_inset listings
12415 \begin_layout Plain Layout
12417 # External variables:
12420 \begin_layout Plain Layout
12422 # Optind -- index in ARGV of first nonoption argument
12425 \begin_layout Plain Layout
12427 # Optarg -- string value of argument to current option
12430 \begin_layout Plain Layout
12432 # Opterr -- if nonzero, print our own diagnostic
12435 \begin_layout Plain Layout
12437 # Optopt -- current option letter
12440 \begin_layout Plain Layout
12444 \begin_layout Plain Layout
12449 \begin_layout Plain Layout
12451 # -1 at end of options
12454 \begin_layout Plain Layout
12456 # ? for unrecognized option
12459 \begin_layout Plain Layout
12461 # <c> a character representing the current option
12464 \begin_layout Plain Layout
12468 \begin_layout Plain Layout
12473 \begin_layout Plain Layout
12475 # _opti -- index in multi-flag option, e.g., -abc
12478 \begin_layout Plain Layout
12487 \begin_layout Standard
12488 The function follows.
12489 The final two parameters,
12490 \begin_inset Flex CharStyle:Code
12493 \begin_layout Plain Layout
12500 \begin_inset Flex CharStyle:Code
12503 \begin_layout Plain Layout
12509 are local variables and not parameters --- as indicated by the multiple
12510 spaces preceding them.
12511 Awk doesn't care, the multiple spaces are a convention to help us humans.
12514 \begin_layout Chunk
12515 getopt.awk-getopt()
12518 \begin_layout Standard
12519 \begin_inset listings
12523 \begin_layout Plain Layout
12525 function getopt(argc, argv, options, thisopt, i)
12528 \begin_layout Plain Layout
12533 \begin_layout Plain Layout
12535 if (length(options) == 0) # no options given
12538 \begin_layout Plain Layout
12543 \begin_layout Plain Layout
12545 if (argv[Optind] == "--") { # all done
12548 \begin_layout Plain Layout
12553 \begin_layout Plain Layout
12558 \begin_layout Plain Layout
12563 \begin_layout Plain Layout
12565 } else if (argv[Optind] !~ /^-[^:
12580 \begin_layout Plain Layout
12585 \begin_layout Plain Layout
12590 \begin_layout Plain Layout
12595 \begin_layout Plain Layout
12600 \begin_layout Plain Layout
12605 \begin_layout Plain Layout
12607 thisopt = substr(argv[Optind], _opti, 1)
12610 \begin_layout Plain Layout
12615 \begin_layout Plain Layout
12617 i = index(options, thisopt)
12620 \begin_layout Plain Layout
12625 \begin_layout Plain Layout
12630 \begin_layout Plain Layout
12632 printf("%c -- invalid option
12637 \begin_layout Plain Layout
12639 thisopt) > "/dev/stderr"
12642 \begin_layout Plain Layout
12644 if (_opti >= length(argv[Optind])) {
12647 \begin_layout Plain Layout
12652 \begin_layout Plain Layout
12657 \begin_layout Plain Layout
12662 \begin_layout Plain Layout
12667 \begin_layout Plain Layout
12672 \begin_layout Plain Layout
12682 \begin_layout Standard
12683 At this point, the option has been found and we need to know if it takes
12687 \begin_layout Standard
12688 \begin_inset listings
12692 \begin_layout Plain Layout
12694 if (substr(options, i + 1, 1) == ":") {
12697 \begin_layout Plain Layout
12699 # get option argument
12702 \begin_layout Plain Layout
12704 if (length(substr(argv[Optind], _opti + 1)) > 0)
12707 \begin_layout Plain Layout
12709 Optarg = substr(argv[Optind], _opti + 1)
12712 \begin_layout Plain Layout
12717 \begin_layout Plain Layout
12719 Optarg = argv[++Optind]
12722 \begin_layout Plain Layout
12727 \begin_layout Plain Layout
12732 \begin_layout Plain Layout
12737 \begin_layout Plain Layout
12739 if (_opti == 0 || _opti >= length(argv[Optind])) {
12742 \begin_layout Plain Layout
12747 \begin_layout Plain Layout
12752 \begin_layout Plain Layout
12757 \begin_layout Plain Layout
12762 \begin_layout Plain Layout
12767 \begin_layout Plain Layout
12774 A test program is built in, too
12777 \begin_layout Chunk
12781 \begin_layout Standard
12782 \begin_inset listings
12786 \begin_layout Plain Layout
12791 \begin_layout Plain Layout
12793 Opterr = 1 # default is to diagnose
12796 \begin_layout Plain Layout
12798 Optind = 1 # skip ARGV[0]
12801 \begin_layout Plain Layout
12806 \begin_layout Plain Layout
12808 if (_getopt_test) {
12811 \begin_layout Plain Layout
12813 while ((_go_c = getopt(ARGC, ARGV, "ab:cd")) != -1)
12816 \begin_layout Plain Layout
12818 printf("c = <%c>, optarg = <%s>
12823 \begin_layout Plain Layout
12828 \begin_layout Plain Layout
12830 printf("non-option arguments:
12835 \begin_layout Plain Layout
12837 for (; Optind < ARGC; Optind++)
12840 \begin_layout Plain Layout
12849 \begin_layout Plain Layout
12851 Optind, ARGV[Optind])
12854 \begin_layout Plain Layout
12859 \begin_layout Plain Layout
12869 \begin_layout Standard
12870 The entire getopt.awk is made out of these chunks in order
12873 \begin_layout Chunk
12877 \begin_layout Standard
12878 \begin_inset listings
12882 \begin_layout Plain Layout
12886 chunkref{getopt.awk-header}>
12889 \begin_layout Plain Layout
12893 \begin_layout Plain Layout
12897 chunkref{getopt.awk-notes}>
12900 \begin_layout Plain Layout
12904 chunkref{getopt.awk-getopt()}>
12907 \begin_layout Plain Layout
12911 chunkref{getopt.awk-begin}>
12919 \begin_layout Standard
12920 Although we only want the header and function:
12923 \begin_layout Chunk
12927 \begin_layout Standard
12928 \begin_inset listings
12932 \begin_layout Plain Layout
12934 # try: locate getopt.awk for the full original file
12937 \begin_layout Plain Layout
12939 # as part of your standard awk installation
12942 \begin_layout Plain Layout
12946 chunkref{getopt.awk-header}>
12949 \begin_layout Plain Layout
12953 \begin_layout Plain Layout
12957 chunkref{getopt.awk-getopt()}>
12965 \begin_layout Chapter
12966 Newfangle LaTeX source code
12969 \begin_layout Section
12973 \begin_layout Standard
12974 Here we define a Lyx .module file that makes it convenient to use LyX for
12975 writing such literate programs.
12978 \begin_layout Standard
12980 \begin_inset Flex CharStyle:Code
12983 \begin_layout Plain Layout
12989 can be installed in your personal
12990 \begin_inset Flex CharStyle:Code
12993 \begin_layout Plain Layout
12994 .lyx/layouts folder
13000 You will need to Tools Reconfigure so that LyX notices it.
13001 It adds a new format Chunk, which should precede every listing and contain
13006 \begin_layout Chunk
13007 ./newfangle.module,language=
13010 \begin_layout Standard
13011 \begin_inset listings
13015 \begin_layout Plain Layout
13019 DeclareLyXModule{Newfangle Literate Listings}
13022 \begin_layout Plain Layout
13027 \begin_layout Plain Layout
13029 # Newfangle literate listings allow one to write
13032 \begin_layout Plain Layout
13034 # literate programs after the fashion of noweb, but without having
13037 \begin_layout Plain Layout
13039 # to use noweave to generate the documentation.
13040 Instead the listings
13043 \begin_layout Plain Layout
13045 # package is extended in conjunction with the noweb package to implement
13048 \begin_layout Plain Layout
13050 # to code formating directly as latex.
13053 \begin_layout Plain Layout
13055 # The newfangle awk script
13058 \begin_layout Plain Layout
13063 \begin_layout Plain Layout
13067 \begin_layout Plain Layout
13072 \begin_layout Plain Layout
13076 \begin_layout Plain Layout
13081 \begin_layout Plain Layout
13085 chunkref{./newfangle.sty}>
13088 \begin_layout Plain Layout
13093 \begin_layout Plain Layout
13097 \begin_layout Plain Layout
13101 chunkref{chunkstyle}>
13104 \begin_layout Plain Layout
13108 \begin_layout Plain Layout
13112 chunkref{chunkref}>
13120 \begin_layout Subsection
13124 \begin_layout Standard
13129 style is to make it easier for LyX users to provide the name to
13130 \begin_inset Flex CharStyle:Code
13133 \begin_layout Plain Layout
13142 Normally this requires right-clicking on the listing, choosing settings,
13143 advanced, and then typing
13144 \begin_inset Flex CharStyle:Code
13147 \begin_layout Plain Layout
13154 This has the further disadvantage that the name (and other options) are
13155 not generally visible during document editing.
13158 \begin_layout Standard
13159 The chunk style is defined as a LaTeX command, so that all text on the same
13160 line is passed to the LaTeX command
13161 \begin_inset Flex CharStyle:Code
13164 \begin_layout Plain Layout
13171 This makes it easy to parse using
13172 \begin_inset Flex CharStyle:Code
13175 \begin_layout Plain Layout
13181 , and easy to pass these options on to the listings package.
13182 The first word in a chunk section should be the chunk name, and will have
13184 \begin_inset Flex CharStyle:Code
13187 \begin_layout Plain Layout
13194 Any other words are accepted arguments to
13195 \begin_inset Flex CharStyle:Code
13198 \begin_layout Plain Layout
13209 \begin_layout Standard
13210 We set PassThru to 1 because the user is actually entering raw latex.
13213 \begin_layout Chunk
13217 \begin_layout Standard
13218 \begin_inset listings
13222 \begin_layout Plain Layout
13227 \begin_layout Plain Layout
13232 \begin_layout Plain Layout
13237 \begin_layout Plain Layout
13239 Margin First_Dynamic
13242 \begin_layout Plain Layout
13244 LeftMargin Chunk:xxx
13247 \begin_layout Plain Layout
13252 \begin_layout Plain Layout
13257 \begin_layout Plain Layout
13259 LabelString "Chunk:"
13262 \begin_layout Plain Layout
13267 \begin_layout Plain Layout
13272 \begin_layout Plain Layout
13281 \begin_layout Standard
13282 To make the label very visible we choose a larger font coloured red.
13285 \begin_layout Standard
13286 \begin_inset listings
13290 \begin_layout Plain Layout
13295 \begin_layout Plain Layout
13300 \begin_layout Plain Layout
13305 \begin_layout Plain Layout
13310 \begin_layout Plain Layout
13315 \begin_layout Plain Layout
13320 \begin_layout Plain Layout
13325 \begin_layout Plain Layout
13335 \begin_layout Subsection
13339 \begin_layout Standard
13340 We also define the Chunkref style which can be used to express cross references
13344 \begin_layout Chunk
13348 \begin_layout Standard
13349 \begin_inset listings
13353 \begin_layout Plain Layout
13355 InsetLayout Chunkref
13358 \begin_layout Plain Layout
13363 \begin_layout Plain Layout
13368 \begin_layout Plain Layout
13373 \begin_layout Plain Layout
13378 \begin_layout Plain Layout
13383 \begin_layout Plain Layout
13388 \begin_layout Plain Layout
13393 \begin_layout Plain Layout
13398 \begin_layout Plain Layout
13408 \begin_layout Section
13409 \begin_inset CommandInset label
13411 name "sec:Latex-Macros"
13418 \begin_layout Standard
13432 As noweb defines it's own
13433 \begin_inset Flex CharStyle:Code
13436 \begin_layout Plain Layout
13444 environment, we re-define the one that LyX logical markup module expects
13448 \begin_layout Chunk
13449 ./newfangle.sty,language=tex,basicstyle=
13454 \begin_layout Standard
13455 \begin_inset listings
13459 \begin_layout Plain Layout
13463 usepackage{listings}%
13466 \begin_layout Plain Layout
13473 \begin_layout Plain Layout
13480 \begin_layout Plain Layout
13496 \begin_layout Standard
13498 \begin_inset Flex CharStyle:Code
13501 \begin_layout Plain Layout
13508 \begin_inset Flex CharStyle:Code
13511 \begin_layout Plain Layout
13519 which will need renaming to
13520 \begin_inset Flex CharStyle:Code
13523 \begin_layout Plain Layout
13531 when I can do this without clashing with
13532 \begin_inset Flex CharStyle:Code
13535 \begin_layout Plain Layout
13546 \begin_layout Standard
13547 \begin_inset listings
13551 \begin_layout Plain Layout
13555 lstnewenvironment{Chunk}{
13567 \begin_layout Standard
13568 We also define a suitable
13569 \begin_inset Flex CharStyle:Code
13572 \begin_layout Plain Layout
13580 of parameters that suit the literate programming style after the fashion
13588 \begin_layout Standard
13589 \begin_inset listings
13593 \begin_layout Plain Layout
13597 lstset{numbers=left, stepnumber=5, numbersep=5pt,
13600 \begin_layout Plain Layout
13602 breaklines=false,basicstyle=
13607 \begin_layout Plain Layout
13619 \begin_layout Standard
13620 We also define a notangle-like mechanism for
13624 to LaTeX from the listing, and by which we can refer to other listings.
13626 \begin_inset Flex CharStyle:Code
13629 \begin_layout Plain Layout
13630 =<\SpecialChar \ldots{}
13636 sequence to contain LaTeX code, and include another like this chunk:
13637 \begin_inset Flex CharStyle:Code
13640 \begin_layout Plain Layout
13643 chunkref{chunkname}>
13650 \begin_inset Flex CharStyle:Code
13653 \begin_layout Plain Layout
13654 =<\SpecialChar \ldots{}
13660 is already defined to contain LaTeX code for this document --- this is
13665 document after all --- the code fragment below effectively contains the
13667 \begin_inset Flex CharStyle:Code
13670 \begin_layout Plain Layout
13677 To avoid problems with document generation, I had to declare an lstlistings
13679 \begin_inset Flex CharStyle:Code
13682 \begin_layout Plain Layout
13688 for this listing only; which in LyX was done by right-clicking the listings
13690 \begin_inset Flex CharStyle:Code
13693 \begin_layout Plain Layout
13699 \SpecialChar \menuseparator
13701 \begin_inset Flex CharStyle:Code
13704 \begin_layout Plain Layout
13713 \begin_layout Standard
13714 \begin_inset Note Note
13717 \begin_layout Plain Layout
13718 =< isn't enjoyed literally here, in a listing when the escape sequence is
13719 already defined as shown...
13720 we need to somehow escape this representation...
13728 \begin_layout Standard
13729 \begin_inset listings
13730 lstparams "escapeinside={}"
13734 \begin_layout Plain Layout
13738 lstset{escapeinside={=<}{>}}%
13746 \begin_layout Standard
13747 Although our macros will contain the @ symbol, they will be included in
13749 \begin_inset Flex CharStyle:Code
13752 \begin_layout Plain Layout
13760 section by LyX; however we keep the commented out
13761 \begin_inset Flex CharStyle:Code
13764 \begin_layout Plain Layout
13773 The listings package likes to centre the titles, but noweb titles are specially
13774 formatted and must be left aligned.
13775 The simplest way to do this turned out to be by removing the definition
13777 \begin_inset Flex CharStyle:Code
13780 \begin_layout Plain Layout
13789 This may interact badly if other listings want a regular title or caption.
13790 We remember the old maketitle in case we need it.
13793 \begin_layout Standard
13794 \begin_inset listings
13798 \begin_layout Plain Layout
13805 \begin_layout Plain Layout
13807 %somehow re-defining maketitle gives us a left-aligned title
13810 \begin_layout Plain Layout
13812 %which is extactly what our specially formatted title needs!
13815 \begin_layout Plain Layout
13823 newfangle@lst@maketitle
13828 \begin_layout Plain Layout
13844 \begin_layout Subsection
13845 \begin_inset CommandInset label
13847 name "sub:The-chunk-command"
13854 \begin_layout Standard
13855 Our chunk command accepts one argument, and calls
13856 \begin_inset Flex CharStyle:Code
13859 \begin_layout Plain Layout
13869 \begin_inset Flex CharStyle:Code
13872 \begin_layout Plain Layout
13880 will note the name, this is erased when the next
13881 \begin_inset Flex CharStyle:Code
13884 \begin_layout Plain Layout
13892 starts, so we make a note of this in
13893 \begin_inset Flex CharStyle:Code
13896 \begin_layout Plain Layout
13904 and restore in in lstlistings Init hook.
13907 \begin_layout Standard
13908 \begin_inset listings
13912 \begin_layout Plain Layout
13921 \begin_layout Plain Layout
13927 newfanglecaption},name=#1}%
13930 \begin_layout Plain Layout
13943 \begin_layout Plain Layout
13948 \begin_layout Plain Layout
13964 \begin_layout Subsubsection
13968 \begin_layout Standard
13969 Newfangle permits parameterized chunks, and requires the paramters to be
13970 specified as listings options.
13971 The newfangle script uses this, and although we don't do anything with
13972 these in the LaTeX code right now, we need to stop the listings package
13976 \begin_layout Standard
13977 \begin_inset listings
13981 \begin_layout Plain Layout
13991 newfangle@chunk@params{#1}}%
13999 \begin_layout Standard
14000 As it is common to define a chunk which then needs appending to another
14001 chunk, and annoying to have to declare a single line chunk to manage the
14002 include, we support an
14003 \begin_inset Flex CharStyle:Code
14006 \begin_layout Plain Layout
14016 \begin_layout Standard
14017 \begin_inset listings
14021 \begin_layout Plain Layout
14031 newfangle@chunk@append{#1}}%
14039 \begin_layout Subsection
14040 The noweb styled caption
14043 \begin_layout Standard
14044 We define a public macro
14045 \begin_inset Flex CharStyle:Code
14048 \begin_layout Plain Layout
14056 which can be set as a regular title.
14058 \begin_inset Flex CharStyle:Code
14061 \begin_layout Plain Layout
14070 \begin_inset Flex CharStyle:Code
14073 \begin_layout Plain Layout
14081 at the appriate time when the caption is emitted.
14084 \begin_layout Standard
14085 \begin_inset listings
14089 \begin_layout Plain Layout
14099 newfangle@caption}%
14107 \begin_layout Standard
14108 \begin_inset Float figure
14114 \begin_layout Plain Layout
14115 \begin_inset Box Boxed
14124 height_special "totalheight"
14127 \begin_layout Plain Layout
14129 \begin_inset space \qquad{}
14137 \begin_inset Formula $\equiv+$
14141 \begin_inset space \qquad{}
14145 \begin_inset space \qquad{}
14149 \begin_inset space \qquad{}
14153 \begin_inset Formula $\triangleleft$
14157 \begin_inset space \quad{}
14161 \begin_inset Formula $\triangleright$
14167 \begin_layout Plain Layout
14170 In this example, the current chunk is 22c, and therefore the third chunk
14174 \begin_layout Plain Layout
14185 \begin_layout Plain Layout
14188 The first chunk with this name (19b) occurs as the second chunk on page
14192 \begin_layout Plain Layout
14195 The previous chunk (22d) with the same name is the second chunk on page
14199 \begin_layout Plain Layout
14202 The next chunk (24d) is the fourth chunk on page 24.
14205 \begin_layout Plain Layout
14206 \begin_inset Caption
14208 \begin_layout Plain Layout
14224 The general noweb output format compactly identifies the current chunk,
14225 and references to the first chunk, and the previous and next chunks that
14226 have the same name.
14230 \begin_layout Standard
14231 This means that we need to keep a counter for each chunk-name, that we use
14232 to count chunks of the same name.
14236 \begin_layout Subsection
14240 \begin_layout Standard
14241 It would be natural to have a counter for each chunk name, but TeX would
14242 soon run out of counters
14246 \begin_layout Plain Layout
14247 \SpecialChar \ldots{}
14252 run out of counters and so I had to re-write the LaTeX macros to share
14253 a counter as described here
14258 , so we have one counter which we save at the end of a chunk and restore
14259 at the beginning of a chunk.
14262 \begin_layout Standard
14263 \begin_inset listings
14267 \begin_layout Plain Layout
14271 newcounter{newfangle@chunkcounter}%
14279 \begin_layout Standard
14280 We construct the name of this variable to store the counter to be the text
14282 \begin_inset Flex CharStyle:Code
14285 \begin_layout Plain Layout
14291 prefixed onto the chunks own name, and store it in
14292 \begin_inset Flex CharStyle:Code
14295 \begin_layout Plain Layout
14307 \begin_layout Standard
14308 We save the counter like this:
14311 \begin_layout Chunk
14315 \begin_layout Standard
14316 \begin_inset listings
14320 \begin_layout Plain Layout
14336 arabic{newfangle@chunkcounter}}%
14344 \begin_layout Standard
14345 and restore the counter like this:
14348 \begin_layout Chunk
14352 \begin_layout Standard
14353 \begin_inset listings
14357 \begin_layout Plain Layout
14361 setcounter{newfangle@chunkcounter}{
14375 \begin_layout Chunk
14379 \begin_layout Standard
14380 If there does not already exist a variable whose name is stored in
14381 \begin_inset Flex CharStyle:Code
14384 \begin_layout Plain Layout
14392 , then we know we are the first chunk with this name, and then define a
14397 \begin_layout Standard
14398 Although chunks of the same name share a common counter, they must still
14400 We use is the internal name of the listing, suffixed by the counter value.
14401 So the first chunk might be
14402 \begin_inset Flex CharStyle:Code
14405 \begin_layout Plain Layout
14411 and the second chunk be
14412 \begin_inset Flex CharStyle:Code
14415 \begin_layout Plain Layout
14424 \begin_layout Standard
14425 We also calculate the name of the previous chunk if we can (before we increment
14426 the chunk counter).
14427 If this is the first chunk of that name, then
14428 \begin_inset Flex CharStyle:Code
14431 \begin_layout Plain Layout
14440 \begin_inset Flex CharStyle:Code
14443 \begin_layout Plain Layout
14451 which the noweb package will interpret as not existing.
14454 \begin_layout Standard
14455 \begin_inset listings
14459 \begin_layout Plain Layout
14465 newfangle@caption{%
14468 \begin_layout Plain Layout
14474 chunkcount{lst-chunk-
14479 \begin_layout Plain Layout
14488 \begin_layout Plain Layout
14503 \begin_layout Plain Layout
14507 setcounter{newfangle@chunkcounter}{
14516 \begin_layout Plain Layout
14527 \begin_layout Plain Layout
14532 \begin_layout Plain Layout
14536 setcounter{newfangle@chunkcounter}{
14545 \begin_layout Plain Layout
14555 arabic{newfangle@chunkcounter}}%
14558 \begin_layout Plain Layout
14568 \begin_layout Standard
14569 After incrementing the chunk counter, we then define the name of this chunk,
14570 as well as the name of the first chunk.
14573 \begin_layout Standard
14574 \begin_inset listings
14578 \begin_layout Plain Layout
14582 addtocounter{newfangle@chunkcounter}{1}%
14585 \begin_layout Plain Layout
14601 arabic{newfangle@chunkcounter}}%
14604 \begin_layout Plain Layout
14614 arabic{newfangle@chunkcounter}}%
14617 \begin_layout Plain Layout
14633 \begin_layout Standard
14634 We now need to calculate the name of the next chunk.
14635 We do this by temporarily skipping the counter on by one; however there
14636 may not actually be another chunk with this name! We detect this by also
14637 defining a label for each chunk based on the chunkname.
14638 If there is a next chunkname then it will define a label with that name.
14639 As labels are persistent, we can at least tell the second time LaTeX is
14641 If we don't find such a defined label then we define
14642 \begin_inset Flex CharStyle:Code
14645 \begin_layout Plain Layout
14654 \begin_inset Flex CharStyle:Code
14657 \begin_layout Plain Layout
14668 \begin_layout Standard
14669 \begin_inset listings
14673 \begin_layout Plain Layout
14677 addtocounter{newfangle@chunkcounter}{1}%
14680 \begin_layout Plain Layout
14690 arabic{newfangle@chunkcounter}}%
14693 \begin_layout Plain Layout
14697 @ifundefined{r@label-
14713 \begin_layout Standard
14714 The noweb package requires that we define a
14715 \begin_inset Flex CharStyle:Code
14718 \begin_layout Plain Layout
14726 for every chunk, with a unique name, which is then used to print out it's
14730 \begin_layout Standard
14731 We also define a regular label for this chunk, as was mentioned above when
14733 \begin_inset Flex CharStyle:Code
14736 \begin_layout Plain Layout
14745 This requires LaTeX to be run at least twice after new chunk sections are
14746 added --- but noweb requried that anyway.
14749 \begin_layout Standard
14750 \begin_inset listings
14754 \begin_layout Plain Layout
14763 \begin_layout Plain Layout
14765 % define this label for every chunk instance, so we
14768 \begin_layout Plain Layout
14770 % can tell when we are the last chunk of this name
14773 \begin_layout Plain Layout
14787 \begin_layout Standard
14788 We also try and add the chunk to the list of listings, but I'm afraid we
14789 don't do very well.
14790 We want each chunk name listing once, with all of it's references.
14793 \begin_layout Standard
14794 \begin_inset listings
14798 \begin_layout Plain Layout
14802 addcontentsline{lol}{lstlisting}{
14818 \begin_layout Standard
14819 We then call the noweb output macros in the same way that noweave generates
14820 them, except that we don't need to call
14821 \begin_inset Flex CharStyle:Code
14824 \begin_layout Plain Layout
14827 nwstartdeflinemarkup
14833 \begin_inset Flex CharStyle:Code
14836 \begin_layout Plain Layout
14844 -- and if we do it messes up the output somewhat.
14847 \begin_layout Standard
14848 \begin_inset listings
14852 \begin_layout Plain Layout
14859 \begin_layout Plain Layout
14864 \begin_layout Plain Layout
14871 \begin_layout Plain Layout
14880 \begin_layout Plain Layout
14885 \begin_layout Plain Layout
14890 \begin_layout Plain Layout
14895 \begin_layout Plain Layout
14902 \begin_layout Plain Layout
14909 \begin_layout Plain Layout
14914 \begin_layout Plain Layout
14923 \begin_layout Plain Layout
14927 @ifundefined{newfangle@chunk@params}{}{%
14930 \begin_layout Plain Layout
14934 newfangle@chunk@params)%
14937 \begin_layout Plain Layout
14942 \begin_layout Plain Layout
14953 \begin_layout Plain Layout
14962 \begin_layout Plain Layout
14967 \begin_layout Plain Layout
14971 @ifundefined{newfangle@chunk@append}{}{%
14974 \begin_layout Plain Layout
14980 newfangle@chunk@append{x}
14985 \begin_layout Plain Layout
14989 newfangle@chunk@append%
14992 \begin_layout Plain Layout
14999 \begin_layout Plain Layout
15004 \begin_layout Plain Layout
15012 newfangle@chunk@append{}%
15015 \begin_layout Plain Layout
15022 \begin_layout Plain Layout
15027 \begin_layout Plain Layout
15032 \begin_layout Plain Layout
15051 \begin_layout Plain Layout
15055 nwstartdeflinemarkup%
15058 \begin_layout Plain Layout
15069 \begin_layout Plain Layout
15073 nwenddeflinemarkup%
15076 \begin_layout Plain Layout
15086 \begin_layout Standard
15087 Originally this was developed as a
15088 \begin_inset Flex CharStyle:Code
15091 \begin_layout Plain Layout
15097 aspect, in the Init hook, but it was found easier to affect the title without
15099 \begin_inset Flex CharStyle:Code
15102 \begin_layout Plain Layout
15105 lst@AddToHookExe{PreSet}
15110 is still required to set the listings name to the name passed to the
15111 \begin_inset Flex CharStyle:Code
15114 \begin_layout Plain Layout
15125 \begin_layout Standard
15126 \begin_inset listings
15130 \begin_layout Plain Layout
15134 lst@BeginAspect{newfangle}
15137 \begin_layout Plain Layout
15141 lst@Key{newfangle}{true}[t]{
15143 lstKV@SetIf{#1}{true}}
15146 \begin_layout Plain Layout
15150 lst@AddToHookExe{PreSet}{
15161 \begin_layout Plain Layout
15165 lst@AddToHook{Init}{}%
15170 \begin_layout Plain Layout
15182 \begin_layout Subsection
15186 \begin_layout Standard
15189 chunkref command which makes it easy to generate visual references to different
15193 \begin_layout Standard
15194 \begin_inset Tabular
15195 <lyxtabular version="3" rows="4" columns="2">
15197 <column alignment="center" valignment="top" width="0">
15198 <column alignment="center" valignment="top" width="0">
15200 <cell alignment="center" valignment="top" topline="true" bottomline="true" leftline="true" usebox="none">
15203 \begin_layout Plain Layout
15209 <cell alignment="center" valignment="top" topline="true" bottomline="true" leftline="true" rightline="true" usebox="none">
15212 \begin_layout Plain Layout
15220 <cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
15223 \begin_layout Plain Layout
15231 <cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
15234 \begin_layout Plain Layout
15238 \begin_layout Plain Layout
15254 <cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
15257 \begin_layout Plain Layout
15260 chunkref[3]{preamble}
15265 <cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
15268 \begin_layout Plain Layout
15272 \begin_layout Plain Layout
15276 chunkref[3]{preamble}
15288 <cell alignment="center" valignment="top" topline="true" bottomline="true" leftline="true" usebox="none">
15291 \begin_layout Plain Layout
15294 chunkref{preamble}[arg1, arg2]
15299 <cell alignment="center" valignment="top" topline="true" bottomline="true" leftline="true" rightline="true" usebox="none">
15302 \begin_layout Plain Layout
15306 \begin_layout Plain Layout
15310 chunkref{preamble}[arg1, arg2]
15328 \begin_layout Standard
15329 Chunkref can also be used within a code chunk to include another code chunk.
15330 The third optional parameter to chunkref is a comma sepatarated list of
15331 arguments, which will replace defined parameters in the chunkref.
15332 \begin_inset Note Note
15335 \begin_layout Plain Layout
15336 Darn it, if I have: =<
15338 chunkref{new-mode-tracker}[{chunks[chunk_name, "language"]},{mode}]> the
15339 inner braces (inside [ ]) cause _ to signify subscript even though we have
15348 \begin_layout Standard
15349 \begin_inset listings
15353 \begin_layout Plain Layout
15362 \begin_layout Plain Layout
15371 \begin_layout Plain Layout
15382 \begin_layout Plain Layout
15389 \begin_layout Plain Layout
15400 \begin_layout Plain Layout
15405 \begin_layout Plain Layout
15414 \begin_layout Plain Layout
15420 chunkref@i{#1}{#2}}{
15422 chunkref@i{#1}{#2}()}%
15425 \begin_layout Plain Layout
15430 \begin_layout Plain Layout
15436 chunkref@i#1#2(#3){%
15439 \begin_layout Plain Layout
15448 \begin_layout Plain Layout
15457 \begin_layout Plain Layout
15466 \begin_layout Plain Layout
15475 \begin_layout Plain Layout
15486 \begin_layout Plain Layout
15495 \begin_layout Plain Layout
15502 \begin_layout Plain Layout
15513 \begin_layout Plain Layout
15520 \begin_layout Plain Layout
15531 \begin_layout Plain Layout
15542 \begin_layout Plain Layout
15551 \begin_layout Plain Layout
15558 \begin_layout Plain Layout
15563 \begin_layout Plain Layout
15572 \begin_layout Plain Layout
15583 \begin_layout Plain Layout
15590 \begin_layout Plain Layout
15597 \begin_layout Plain Layout
15604 \begin_layout Plain Layout
15615 \begin_layout Plain Layout
15622 \begin_layout Plain Layout
15626 chunkref@args #3,)%
15629 \begin_layout Plain Layout
15636 \begin_layout Plain Layout
15645 \begin_layout Plain Layout
15650 \begin_layout Plain Layout
15655 \begin_layout Plain Layout
15664 \begin_layout Plain Layout
15674 \begin_layout Subsection
15678 \begin_layout Standard
15679 \begin_inset listings
15683 \begin_layout Plain Layout
15688 \begin_layout Plain Layout
15700 \begin_layout Chapter
15701 Extracting newfangle
15704 \begin_layout Section
15705 Extracting from Lyx
15708 \begin_layout Standard
15709 To extract from LyX, you will need to configure LyX as explained in section
15711 \begin_inset CommandInset ref
15713 reference "sub:Configuring-the-build"
15720 \begin_layout Standard
15721 \begin_inset CommandInset label
15723 name "lyx-build-script"
15727 And this lyx-build scrap will extract newfangle for me.
15730 \begin_layout Chunk
15731 lyx-build,language=sh
15734 \begin_layout Standard
15735 \begin_inset listings
15739 \begin_layout Plain Layout
15744 \begin_layout Plain Layout
15749 \begin_layout Plain Layout
15753 \begin_layout Plain Layout
15757 chunkref{lyx-build-helper}>
15760 \begin_layout Plain Layout
15762 cd $PROJECT_DIR || exit 1
15765 \begin_layout Plain Layout
15769 \begin_layout Plain Layout
15771 /usr/local/bin/newfangle -R./newfangle $TEX_SRC > ./newfangle
15774 \begin_layout Plain Layout
15776 /usr/local/bin/newfangle -R./newfangle.module $TEX_SRC > ./newfangle.module
15779 \begin_layout Plain Layout
15783 \begin_layout Plain Layout
15787 chunkref{test:helpers}>
15790 \begin_layout Plain Layout
15792 export NEWFANGLE=./newfangle
15795 \begin_layout Plain Layout
15797 export TMP=${TMP:-/tmp}
15800 \begin_layout Plain Layout
15804 chunkref{test:run-tests}>
15807 \begin_layout Plain Layout
15809 # Now check that we can extract a newfangle that also passes the tests!
15812 \begin_layout Plain Layout
15814 $NEWFANGLE -R./newfangle $TEX_SRC > ./new-newfangle
15817 \begin_layout Plain Layout
15819 export NEWFANGLE=./new-newfangle
15822 \begin_layout Plain Layout
15826 chunkref{test:run-tests}>
15834 \begin_layout Chunk
15838 \begin_layout Standard
15839 \begin_inset listings
15843 \begin_layout Plain Layout
15848 \begin_layout Plain Layout
15850 $NEWFANGLE -Rpca-test.awk $TEX_SRC | awk -f - || exit 1
15853 \begin_layout Plain Layout
15857 chunkref{test:cromulence}>
15860 \begin_layout Plain Layout
15864 chunkref{test:escapes}>
15867 \begin_layout Plain Layout
15871 chunkref{test:chunk-params}>
15879 \begin_layout Standard
15880 With a lyx-build-helper
15883 \begin_layout Chunk
15884 lyx-build-helper,language=sh
15887 \begin_layout Standard
15888 \begin_inset listings
15892 \begin_layout Plain Layout
15894 PROJECT_DIR="$LYX_r"
15897 \begin_layout Plain Layout
15899 LYX_SRC="$PROJECT_DIR/${LYX_i%.tex}.lyx"
15902 \begin_layout Plain Layout
15907 \begin_layout Plain Layout
15909 TEX_SRC="$TEX_DIR/$LYX_i"
15917 \begin_layout Section
15918 Extracting documentation
15921 \begin_layout Chunk
15925 \begin_layout Standard
15926 \begin_inset listings
15930 \begin_layout Plain Layout
15932 #python -m elyxer --css lyx.css $LYX_SRC |
15937 \begin_layout Plain Layout
15939 # iconv -c -f utf-8 -t ISO-8859-1//TRANSLIT |
15944 \begin_layout Plain Layout
15952 1>/' > www/docs/newfangle.html
15955 \begin_layout Plain Layout
15959 \begin_layout Plain Layout
15961 ( mkdir -p www/docs/newfangle && cd www/docs/newfangle &&
15966 \begin_layout Plain Layout
15968 lyx -e latex ../../../newfangle.lyx &&
15973 \begin_layout Plain Layout
15975 htlatex ../../../newfangle.tex "xhtml,fn-in" &&
15980 \begin_layout Plain Layout
15985 [0-9][0-9]* *-->//g' newfangle.html
15988 \begin_layout Plain Layout
15993 \begin_layout Plain Layout
15997 \begin_layout Plain Layout
15999 ( mkdir -p www/docs/literate && cd www/docs/literate &&
16004 \begin_layout Plain Layout
16006 lyx -e latex ../../../literate.lyx &&
16011 \begin_layout Plain Layout
16013 htlatex ../../../literate.tex "xhtml,fn-in" &&
16018 \begin_layout Plain Layout
16023 [0-9][0-9]* *-->$//g' literate.html
16026 \begin_layout Plain Layout
16036 \begin_layout Section
16037 Extracting from the command line
16040 \begin_layout Standard
16041 First you will need the tex output, then you can extract:
16044 \begin_layout Chunk
16045 lyx-build-manual,language=sh
16048 \begin_layout Standard
16049 \begin_inset listings
16053 \begin_layout Plain Layout
16055 lyx -e latex newfangle.lyx
16058 \begin_layout Plain Layout
16060 newfangle -R./newfangle newfangle.tex > ./newfangle
16063 \begin_layout Plain Layout
16065 newfangle -R./newfangle.module newfangle.tex > ./newfangle.module
16073 \begin_layout Section
16077 \begin_layout Chunk
16081 \begin_layout Standard
16082 \begin_inset listings
16086 \begin_layout Plain Layout
16091 \begin_layout Plain Layout
16096 \begin_layout Plain Layout
16101 \begin_layout Plain Layout
16106 \begin_layout Plain Layout
16111 \begin_layout Plain Layout
16116 \begin_layout Plain Layout
16121 \begin_layout Plain Layout
16125 \begin_layout Plain Layout
16130 \begin_layout Plain Layout
16135 \begin_layout Plain Layout
16140 \begin_layout Plain Layout
16145 \begin_layout Plain Layout
16150 \begin_layout Plain Layout
16155 \begin_layout Plain Layout
16169 \begin_layout Chapter
16173 \begin_layout Chunk
16174 test:chunk-params:sub,language=,params=THING;colour
16177 \begin_layout Standard
16178 \begin_inset listings
16182 \begin_layout Plain Layout
16187 \begin_layout Plain Layout
16189 a ${THING} of colour ${colour},
16192 \begin_layout Plain Layout
16194 and looking closer =<
16196 chunkref{test:chunk-params:sub:sub}(${colour})>
16204 \begin_layout Chunk
16205 test:chunk-params:sub:sub,params=colour,language=
16208 \begin_layout Standard
16209 \begin_inset listings
16213 \begin_layout Plain Layout
16215 a funny shade of ${colour}
16223 \begin_layout Chunk
16224 test:chunk-params:text,language=
16227 \begin_layout Standard
16228 \begin_inset listings
16232 \begin_layout Plain Layout
16234 What do you see? "=<
16236 chunkref{test:chunk-params:sub}(joe, red)>"
16239 \begin_layout Plain Layout
16249 \begin_layout Standard
16250 Should generate output:
16253 \begin_layout Chunk
16254 test:chunk-params:result
16257 \begin_layout Standard
16258 \begin_inset listings
16262 \begin_layout Plain Layout
16264 What do you see? "I see a joe,
16267 \begin_layout Plain Layout
16269 a joe of colour red,
16272 \begin_layout Plain Layout
16274 and looking closer a funny shade of red"
16277 \begin_layout Plain Layout
16287 \begin_layout Standard
16288 And this chunk will perform the test:
16291 \begin_layout Chunk
16295 \begin_layout Standard
16296 \begin_inset listings
16300 \begin_layout Plain Layout
16302 $NEWFANGLE -Rtest:chunk-params:result $TEX_SRC > $TMP/answer || exit 1
16305 \begin_layout Plain Layout
16307 $NEWFANGLE -Rtest:chunk-params:text $TEX_SRC > $TMP/result || exit 1
16310 \begin_layout Plain Layout
16312 passtest diff $TMP/answer $TMP/result || (echo test:chunk-params:text failed