inweb-bootstrap/Manual/Advanced Weaving with Patterns.w

443 lines
20 KiB
OpenEdge ABL
Raw Normal View History

2019-02-04 22:26:45 +00:00
Advanced Weaving with Patterns.
2020-04-22 22:57:09 +00:00
Customise your weave by creating a new pattern.
@h Patterns versus formats.
Every weave produces output in a "format". The formats are built in to Inweb,
and adding new ones would mean contributing code to the project: currently
we have HTML, ePub, Plain Text, PDF, DIV, and TeX.
There is no way to specify the format at the command line. That's because
|-weave-as P| tells Inweb to weave with a given "pattern": a weave pattern
combines a choice of format with other settings to produce a customised
weave. Patterns can also be based on other patterns: one can, in effect, say
"I want something like P but with some differences". For example, the Inweb
manual at GitHub is woven with |-weave-as GitHubPages|, which is a pattern
based heavily on a generic website-producing pattern called |HTML|.
The upshot of all this is that if you want a website, but one which looks and
behaves differently from what |-weave-as HTML| would give, you should create
a new pattern based on it, and work from there. But patterns are not just
for websites.
@ A pattern definition is a directory containing various files, which we'll
get to in due course. Inweb looks for patterns in three places in turn:
(a) The location given by the |patterns| command in the current colony file,
if there is one: see //Making Weaves into Websites//.
(b) The |Patterns| subdirectory of the current web, if there is a current web,
and if it has such a subdirectory.
(c) The set of built-in patterns supplied with Inweb, at |inweb/Patterns|
in the usual distribution.
For example, the command
2020-04-07 22:04:32 +00:00
= (text as ConsoleText)
$ inweb/Tangled/inweb inweb/Examples/goldbach -weave-as Tapestry
=
2020-04-22 22:57:09 +00:00
didn't set a colony file, so (a) doesn't apply. Inweb first tries
|inweb/Examples/goldbach/Patterns/Tapestry| and then |inweb/Patterns/Tapestry|.
If it can't find either, Inweb issues an error.
@h Basic settings.
Patterns allow for extensive customisation of the woven output, especially
through the use of plugins (see below). But they can also be extremely minimal.
The one absolute requirement is to include a configuration file called
|pattern.txt|, which consists of a series of simple one-line commands.
In this file, blank lines, leading and trailing white space are all ignored,
as is any file whose first character is |#|.
The first genuine line of the file should always give the pattern's name,
and say what if anything it is based on. For example, this might be:
= (text as Inweb)
name: Tapestry based on HTML
=
That is the only compulsory content; with that one line in one file, the
Tapestry pattern is ready for use. (But of course it behaves identically
to HTML in every respect, so it's not very useful yet.)
Do not get these into loops, with A based on B and B based on A.
For a pattern not based on an existing one, simply omit the "based on X"
part. Thus, for example,
= (text as Inweb)
name: HTML
=
@ There are then a handful of other, optional, settings. The following are
all inherited automatically from the pattern we are based on, unless we
set them ourselves.
= (text as Inweb)
format: F
=
sets the format. At present, this must be |HTML|, |plain| (plain text),
|ePub|, |TeX|, or |TestingInweb|.
2020-04-22 22:57:09 +00:00
= (text as Inweb)
number sections: yes
number sections: no
=
causes the weaver to apply numbers to section headings: the first included will
be number 1, and so on. Default is |no|.
= (text as Inweb)
default range: R
=
tells the weaver to assume the range |R|, if the user tries to weave a
multi-section web with this pattern. (For example, the standard HTML pattern
sets this to |sections|, causing a swarm of individual HTML files to be produced.)
Lastly, there are commands to do with plugins, covered below, which are also
inherited.
@ Bibliographic data can also be set, but this applies only to the current
pattern, and is not inherited from any patterns it is based on.
2020-04-22 22:57:09 +00:00
= (text as Inweb)
bibliographic data: K = V
=
tells the weaver to override the bibliographic data on any web it weaves, setting
the key |K| to the value |V|. For example:
= (text as Inweb)
bibliographic data: Booklet Title = A formal grammar for Inform 7
=
@ It can be useful to do some post-processing after each woven file is made.
For an example, see the |PDFTeX| pattern, which simply uses the |TeX| pattern
to make a TeX file, and then runs it through the |pdftex| command-line tool.
This is done by giving the necessary commands in the pattern file:
= (text as Inweb)
name: PDFTeX based on TeX
initial extension: .tex
command: pdftex -output-directory=WOVENPATH -interaction=scrollmode WOVEN.tex
command: rm WOVEN.tex
command: rm WOVEN.log
=
Here |WOVEN| expands to the filename of the file which has just been woven,
but stripped of its filename extension.
Note also the "initial extension" setting. The point of this is that if the
user calls Inweb setting |-weave-to Whatever.pdf|, this pattern setting causes
Inweb first to weave |Whatever.tex|; the post-processing commands will then
make |Whatever.pdf| as expected.
As soon as any command in the list fails, Inweb halts with an error. To see
the exact shell commands being issued, run Inweb with |-verbose|.
@h Plugins and assets.
2020-04-22 22:57:09 +00:00
Plugins are named bundles of resources which are sometimes added to a weave,
and sometimes not, depending on its needs; they are placed in the pattern's
folder, and Inweb has access to the plugins not only for the current pattern,
but also for any pattern(s) it is based on. Plugins were designed for HTML,
but there's no reason they shouldn't also be useful for other formats.
A plugin is identified by name alone, case-insensitively, and that name should
be a single alphanumeric word. For example, the HTML pattern file says
= (text as Inweb)
plugin: Base
=
and this ensures that every file woven by this pattern, or any pattern based
on it, will use |Base|. There can be multiple such commands, for multiple such
plugins, and the ability isn't restricted to HTML alone.
In addition, the HTML format:
(a) includes |MathJax3| if the woven file needs mathematics notation;
(b) includes |Breadcrumbs| if it has a breadcrumb navigation trail;
(c) includes |Carousel| if it has any image carousels;
(d) includes |Popups| if it has any clickable popups (for example, to show
function usage);
(e) includes |Bigfoot| if it includes footnotes.
Two of these draw on other open-source projects:
(a) |MathJax3| is an excellent rendering system for mathematics on the web: see
https://docs.mathjax.org/en/latest/index.html
(b) |Bigfoot| is adapted from a popularly used piece of web coding: see
https://github.com/lemonmade/bigfoot
But if you would like your pattern to use different plugins to handle
mathematics and footnoting, provide lines like these in your pattern file,
but with your preferred plugin names:
= (text as Inweb)
mathematics plugin: MathJax3
footnotes plugin: Bigfoot
=
|Bigfoot| may eventually need to be simplified and rewritten: its big feet
presently tread on the |MathJax3| plugin, so right now it's not possible to
have mathematics in a footnote when |Bigfoot| is in use.
@ So what's in a plugin? A plugin is simply a set of "assets", which are
individual files stored in the plugin's directory. A typical asset might be
a CSS file to help making web pages, or a file of TeX macros to help
typeset a PDF.
Plugin inclusion happens like this:
(a) for each file Inweb weaves, it includes only the plugins it needs;
(b) if it needs |X|, Inweb includes every asset -- meaning, every file whose
name does not begin with a |.| -- from the |X| subdirectory of the pattern,
or from the |X| subdirectory of any pattern it is based on;
(c) but it never includes the same-named asset twice.
@ This means it's possible to supply your own version of any plugin you would
like to tinker with. If you want |Carousel| to have rather different CSS effects,
2020-04-22 22:57:09 +00:00
for example, make your own copy of |Carousel| (copying it from the one in
the Inweb distribution at |inweb/Patterns/HTML/Carousel|) and place it in your
2020-04-25 10:33:39 +00:00
own pattern. Files in your version will prevail over files in the built-in one.
As a simple example, suppose you want a pattern just like |GitHubPages| but
which uses monospaced fonts throughout, for commentary as well as code. The
pattern file can just be:
= (text as Inweb)
name: MonoGitHub based on GitHubPages
=
Then create just one subdirectory of |MonoGitHub|, called |Base|, and create
a single file in that called |Fonts.css|, reading:
= (text)
.code-font { font-family: monospace; }
.commentary-font { font-family: monospace; }
=
And that should work nicely. What happens here is that when pages are woven
with |MonoGitHub|, they use this custom |Fonts.css| instead of the one in
the |Base| plugin from |HTML|. (|MonoGitHub| is based on |GitHubPages|, but
that in turn is based on |HTML|.) All the other files of |Base| remain as
they were, and there's no need to provide duplicates here.
2020-04-22 22:57:09 +00:00
@ But wait, there's more. How is an asset actually "included"? The pattern
gets to decide this, based on the file-type of the asset, as expressed by
its filename extension. For example, the TeX pattern says:
= (text)
assets: .tex embed
=
This admittedly cryptic line tells Inweb that when it includes plugins for
this pattern, any assets ending |.tex| should be "embedded", rather than
copied. There are four things it can do:
(1) |copy|. This is the default, and means that the file is simply copied
into the weave directory, or into the |assets| directory specified in the
colony file, if the user gave one with |-colony|.
(2) |private copy|. The same, but this is never put into the shared |assets|
directory: it's always copied alongside the woven files for the web.
(3) |embed|. The file is not copied. Instead, its entire contents are
pasted into the woven file itself, when the |[[Plugins]]| placeholder in
the template is expanded (see below). Do not use this for binary files.
(4) |collate|. The file is not copied. Instead, its entire contents are
pasted into the woven file itself, when the |[[Plugins]]| placeholder in
the template is expanded (see below); but this is done as a further collation,
not a simple transcription, so any placeholders found in the file will
themselves be expanded. Do not use this for binary files.
@ In addition, the pattern can specify that some text referring to the
asset file should be put into the woven file. For example, an HTML pattern
might say this:
= (text as Inweb)
assets: .js copy
assets: .js prefix = <script src="URL"></script>
assets: .css copy
assets: .css prefix = <link href="URL" rel="stylesheet" rev="stylesheet" type="text/css">
assets: .css transform names
=
With that done, any Javascript or CSS files in its plugins will be copied over,
but links to them will be placed into the header of the HTML file being woven.
(The text |URL|, in a prefix or suffix, expands to the relative URL from the
path being woven to the asset file.)
The unique command "transform names", which should be used only for CSS,
enables the colour-scheme renaming business described below.
An alternative scheme would be to embed all CSS and Javascript, thus producing
a stand-alone HTML file. This could be achieved by:
= (text as Inweb)
assets: .js embed
assets: .js prefix = <script>
assets: .js suffix = </script>
assets: .css embed
assets: .css prefix = <style type="text/css">
assets: .css suffix = </style>
assets: .css transform names
=
2020-04-22 22:57:09 +00:00
@h Embeddings.
Patterns with the HTML format may also want to provide "embeddings". These
are for embedded video/audio or other gadgets, and each different "service" --
|YouTube|, |SoundCloud|, and such -- is represented by an embedding file.
Inweb looks for these in the pattern's |Embedding| subdirectory, if there is
one; then it tries in the pattern we are based on, and so on until it gives
up and throws an error.
The services in the standard Inweb installation, then, are in
|inweb/Patterns/HTML/Embeddings|. It's easy to add new ones; for example,
by creating a similar fragment in |Tapestry/Embedding/WebTubeo.html| you
would provide for embedding videos from |WebTubeo| when using your pattern.
@h Syntax colouring.
No two people ever agree on the ideal colour scheme for syntax-colouring,
so one prime reason to create a custom pattern is to change Inweb's defaults.
Suppose Inweb wants to weave an extract of code written in, say, C. It will
use the programming language definition for C to make a syntax-colouring,
but then use the weave pattern to decide the colour scheme. For example,
it's up to the C language to say which text is a function name: but it's up
to the pattern to say whether functions are red or green.
A pattern based on HTML may provide a subdirectory called |Colouring|. If it
does, then the contents will be CSS files which provide colour schemes for
different programming languages. The scheme |Colours.css| is the fallback,
and is used for any language not providing a colour scheme; otherwise, a
language called, say, |Anaconda| would be coloured by |Anaconda-Colours.css|.
Inweb looks first in the |Colouring| directory of the current pattern, then
tries the pattern it is based on, and so on.
The practical effect is that if you want a pattern to colour Anaconda programs
in your own preferred way -- let's call this hypothetical pattern |SnakeSkin| --
then you need only write two files: |SnakeSkin/pattern.txt|, consisting of
the single line
= (text as Inweb)
name: SnakeSkin based on HTML
=
(or perhaps based on |GitHubPages|, if you want to host there); and then
a colouring file in |SnakeSkin/Colouring/Anaconda-Colours.css|. You should
make this by copying the default |Colours.css| and tinkering.
@ Note that Inweb supports multiple languages in the same weave, each having
their own colour schemes. To do this, it renames CSS spans on the fly in
order to prevent namespace clashes. But you can forget this, because it's
automatic.
@h Templates.
The final possible ingredient for a pattern is a "template"; this is a file
like a pro-forma letter, into which just the details need to be entered.
2020-04-23 22:23:44 +00:00
Inweb does this in two main circumstances:
(a) For each woven file, for example each HTML page generated in a website,
Inweb looks for |template-body.html| (or |.tex|, or |.txt| -- whatever
file extension is used for files in the current format), and uses that
to top and tail the weaver's output. Not all formats or patterns need that.
(b) If Inweb is weaving a large number of individual files for sections or
chapters, it will try also to make an accompanying contents page, though
it uses the term "index" for this. It does this by looking for the
template |template-index.html| -- this time, it's always HTML: the idea is
that whatever file type you're making, you will want an HTML index page
offering downloads or links to them.
In fact the same process, called "collation", is also used internally to
produce navigation sidebars in HTML, and to inject HTML into headers for
the sake of plugins. But the author of a pattern can't control that, whereas
she can write her own |template-body.html| and/or |template-index.html|.
2020-04-22 22:57:09 +00:00
@ For example, here is a template file for making an HTML page:
= (text as Inweb)
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>[[Booklet Title]]</title>
[[Plugins]]
</head>
<body>
2020-04-23 22:23:44 +00:00
[[Weave Content]]
2020-04-22 22:57:09 +00:00
</body>
</html>
=
The weaver uses this to generate any HTML page of program taken from the
2020-04-23 22:23:44 +00:00
web being woven. What you see is what you get, except for the placeholders in
double square brackets:
(a) |[[Weave Content]]| expands to the body of the web page -- the headings,
2020-04-22 22:57:09 +00:00
paragraphs and so on.
(b) |[[Plugins]]| expands to any links to CSS or Javascript files needed
by the plugins being used -- see above.
(c) Any bibliographic datum for the web expands to its value: thus |[[Title]]|,
|[[Author]]| and so on. Booklet Title is one of these, but the weaver always
sets it to a sensible title for the current file being woven -- typically the
name of a section or chapter, if that's what the file will contain. Another
sometimes useful case to know is |[[Capitalized Title]]|, which is the title
in BLOCK CAPITAL LETTERS.
@ Other placeholders, not used in the example above, include:
2020-05-02 23:22:24 +00:00
(a) |[[Navigation]]| expands to the navigation sidebar in use when weaving
2020-04-22 22:57:09 +00:00
a colony of webs -- see //Making Weaves into Websites// for more, and for
syntaxes to do with links and URLs.
2020-05-02 23:22:24 +00:00
(b) |[[Breadcrumbs]]| expands to the HTML for the breadcrumb trail.
2020-05-06 09:15:34 +00:00
(c) |[[Docs]]| expands to the URL to the home page of a colony.
(d) |[[Assets]]| expands to the URL of the directory into which plugin
assets such as images are placed.
2019-02-04 22:26:45 +00:00
2020-04-23 22:23:44 +00:00
@ The |template-index.html| file has access to additional placeholders
enabling it to generate contents pages:
2019-02-04 22:26:45 +00:00
2020-04-22 22:57:09 +00:00
(a) One of the following details about the entire-web PDF (see below):
2020-04-07 22:04:32 +00:00
= (text as Inweb)
[[Complete Leafname]] [[Complete Extent]] [[Complete PDF Size]]
=
2019-02-04 22:26:45 +00:00
(b) One of the following details about the "current chapter" (again, see below):
2020-04-07 22:04:32 +00:00
= (text as Inweb)
[[Chapter Title]] [[Chapter Purpose]] [[Chapter Leafname]]
[[Chapter Extent]] [[Chapter PDF Size]] [[Chapter Errors]]
=
2019-02-04 22:26:45 +00:00
(...) The leafname is that of the typeset PDF; the extent is a page count;
the errors result is a usually blank report.
(c) One of the following details about the "current section" (again, see below):
2020-04-07 22:04:32 +00:00
= (text as Inweb)
[[Section Title]] [[Section Purpose]] [[Section Leafname]]
[[Section Extent]] [[Section PDF Size]] [[Section Errors]]
[[Section Lines]] [[Section Paragraphs]] [[Section Mean]]
[[Section Source]]
=
2019-02-04 22:26:45 +00:00
(...) Lines and Paragraphs are counts of the number of each; the Source
substitution is the leafname of the original |.w| file. The Mean is the
average number of lines per paragraph: where this is large, the section
is rather raw and literate programming is not being used to the full.
2020-04-23 22:23:44 +00:00
@ |[[Repeat Chapter]]| and |[[Repeat Section]]| begin blocks of lines which
2019-02-04 22:26:45 +00:00
are repeated for each chapter or section: the material to be repeated
2020-05-02 23:22:24 +00:00
continues to the matching |[[End Repeat]| line. The "current chapter or
section" mentioned above is the one selected in the current innermost
2019-02-04 22:26:45 +00:00
loop of that description.
2020-05-02 23:22:24 +00:00
|[[Repeat Module]]|, similarly, begins a repeat through the imported
modules of the current web. (The main module, containing the actual material
of the current web, does not count.) Within such a loop,
= (text as Inweb)
[[Module Title]] [[Module Purpose]] [[Module Page]]
=
can all be used to refer to the current module. |[[Module Page]]| expands
to the relative URL of the module's own woven HTML form, provided that
the module is listed as a member of the current colony file.
2019-02-04 22:26:45 +00:00
|[[Select ...]]| and |[[End Select]| form a block which behaves like
a repetition, but happens just once, for the named chapter or section.
For example, the following pattern:
2020-04-07 22:04:32 +00:00
= (text as Inweb)
To take chapter 3 as an example, for instance, we find -
[[Select 3]]
[[Repeat Section]]
Section [[Section Title]], [[Section Code]], [[Section Lines]] lines.
[[End Repeat]]
[[End Select]]
=
2019-02-04 22:26:45 +00:00
weaves a report somewhat like this:
2020-04-07 22:04:32 +00:00
= (text)
To take chapter 3 as an example, for instance, we find -
Section Lexer, 3/lex, 1011 lines.
Section Read Source Text, 3/read, 394 lines.
Section Lexical Writing Back, 3/lwb, 376 lines.
Section Lexical Services, 3/lexs, 606 lines.
Section Vocabulary, 3/vocab, 338 lines.
Section Built-In Words, 3/words, 1207 lines.
=
2020-05-02 23:22:24 +00:00
@ Finally, there is very limited support for conditionals with
|[[If CONDITION]]|, an optional |Else|, and a compulsory |Endif|.
Very few conditions are in fact allowed:
|[[If Chapters]]| tests whether the current web is divided into chapters,
the alternative being that all the sections are in a notional chapter just
called |Sections|.
|[[If Modules]]| tests whether the current web imports any modules.
|[[If Chapter Purpose]]|, inside a |[[Repeat Chapter]]|, tests whether the
current chapter has a (non-empty) purpose text. Similarly for |[[If Section Purpose]]|
and |[[If Module Purpose]].
|[[If Module Page]]|, inside a |[[Repeat Module]]|, tests whether the module
appears (under its own name, i.e., not by a different name) as a member in
the colony file, if there is one. In effect, this can be used to test whether
it is safe to make a link to the module's own woven pages using |[[Module Page]]|.