inweb-bootstrap/Chapter_5/Format_Methods.nw

175 lines
6 KiB
Text

[Formats::] Format Methods.
To characterise the relevant differences in behaviour between the
various weaving formats offered, such as HTML, ePub, or TeX.
@ \section{Formats.}
Exactly as in the previous chapter, each format expresses its behaviour
through optional method calls.
<<*>>=
typedef struct weave_format {
struct text_stream *format_name;
struct text_stream *woven_extension;
struct method_set *methods;
CLASS_DEFINITION
} weave_format;
weave_format *Formats::create_weave_format(text_stream *name, text_stream *ext) {
weave_format *wf = CREATE(weave_format);
wf->format_name = Str::duplicate(name);
wf->woven_extension = Str::duplicate(ext);
wf->methods = Methods::new_set();
return wf;
}
weave_format *Formats::find_by_name(text_stream *name) {
weave_format *wf;
LOOP_OVER(wf, weave_format)
if (Str::eq_insensitive(name, wf->format_name))
return wf;
return NULL;
}
@ Note that this is the file extension before any post-processing. For
example, PDFs are made by weaving a TeX file and then running this through
[[pdftex]]. The extension here will be [[.tex]] because that's what the weave
stage produces, even though we will later end up with a [[.pdf]].
<<*>>=
text_stream *Formats::file_extension(weave_format *wf) {
return wf->woven_extension;
}
@ \section{Creation.}
This must be performed very early in Inweb's run.
<<*>>=
void Formats::create_weave_formats(void) {
Debugging::create();
TeX::create();
PlainText::create();
HTMLFormat::create();
}
@ \section{Methods.}
These two don't allow output to be produced: they're for any setting up and
putting away that needs tp be done.
[[BEGIN_WEAVING_FOR_MTID]] is called before any output is generated, indeed,
before even the filename(s) for the output are worked out. Note that it
can return a [[*_SWM]] code to change the swarm behaviour of the weave to come;
this is helpful for EPUB weaving.
More simply, [[END_WEAVING_FOR_MTID]] is called when all weaving is done.
<<*>>=
enum BEGIN_WEAVING_FOR_MTID
enum END_WEAVING_FOR_MTID
<<*>>=
INT_METHOD_TYPE(BEGIN_WEAVING_FOR_MTID, weave_format *wf, web *W, weave_pattern *pattern)
VOID_METHOD_TYPE(END_WEAVING_FOR_MTID, weave_format *wf, web *W, weave_pattern *pattern)
int Formats::begin_weaving(web *W, weave_pattern *pattern) {
int rv = FALSE;
INT_METHOD_CALL(rv, pattern->pattern_format, BEGIN_WEAVING_FOR_MTID, W, pattern);
if (rv) return rv;
return SWARM_OFF_SWM;
}
void Formats::end_weaving(web *W, weave_pattern *pattern) {
VOID_METHOD_CALL(pattern->pattern_format, END_WEAVING_FOR_MTID, W, pattern);
}
@ [[RENDER_FOR_MTID]] renders the weave tree in the given format: a format must
provide this.
Note the use of an optional "body template" to provide material before and
after the usage of [[[[Weave Content]]]]; but note also that this content is
generated first, and the fore and aft matter second, so that the fore matter
can include plugin links whose need was only realised when rendering the
actual content.
<<*>>=
enum RENDER_FOR_MTID
<<*>>=
VOID_METHOD_TYPE(RENDER_FOR_MTID, weave_format *wf, text_stream *OUT, heterogeneous_tree *tree)
void Formats::render(text_stream *OUT, heterogeneous_tree *tree, filename *into) {
weave_document_node *C = RETRIEVE_POINTER_weave_document_node(tree->root->content);
weave_format *wf = C->wv->format;
TEMPORARY_TEXT(template)
WRITE_TO(template, "template-body%S", wf->woven_extension);
filename *F = Patterns::find_template(C->wv->pattern, template);
TEMPORARY_TEXT(interior)
VOID_METHOD_CALL(wf, RENDER_FOR_MTID, interior, tree);
Bibliographic::set_datum(C->wv->weave_web->md, I"Weave Content", interior);
if (F) Collater::for_order(OUT, C->wv, F, into);
else WRITE("%S", interior);
DISCARD_TEXT(interior)
DISCARD_TEXT(template)
}
@ The weaver has special typographical support for the stand-alone Inform
document of Preform grammar, and this is the hook for it. Most formats
should ignore it.
<<*>>=
enum PREFORM_DOCUMENT_FOR_MTID
<<*>>=
INT_METHOD_TYPE(PREFORM_DOCUMENT_FOR_MTID, weave_format *wf, text_stream *OUT,
weave_order *wv, web *W, chapter *C, section *S, source_line *L,
text_stream *matter, text_stream *concluding_comment)
int Formats::preform_document(OUTPUT_STREAM, weave_order *wv, web *W,
chapter *C, section *S, source_line *L, text_stream *matter,
text_stream *concluding_comment) {
weave_format *wf = wv->format;
int rv = FALSE;
INT_METHOD_CALL(rv, wf, PREFORM_DOCUMENT_FOR_MTID, OUT, wv, W, C, S, L, matter,
concluding_comment);
return rv;
}
@ \section{Post-processing.}
Post-processing is now largely done by commands in the pattern file, rather
than here, but we retain method calls to enable formats to do some idiosyncratic
post-processing.
<<*>>=
enum POST_PROCESS_POS_MTID
<<*>>=
VOID_METHOD_TYPE(POST_PROCESS_POS_MTID, weave_format *wf, weave_order *wv, int open_afterwards)
void Formats::post_process_weave(weave_order *wv, int open_afterwards) {
VOID_METHOD_CALL(wv->format, POST_PROCESS_POS_MTID, wv, open_afterwards);
}
@ Optionally, a fancy report can be printed out, to describe what has been
done. Support for TeX console reporting is hard-wired here because it's
handled by //Patterns::post_process// directly.
<<*>>=
enum POST_PROCESS_REPORT_POS_MTID
<<*>>=
VOID_METHOD_TYPE(POST_PROCESS_REPORT_POS_MTID, weave_format *wf, weave_order *wv)
void Formats::report_on_post_processing(weave_order *wv) {
TeXUtilities::report_on_post_processing(wv);
VOID_METHOD_CALL(wv->format, POST_PROCESS_REPORT_POS_MTID, wv);
}
@ For the sake of index files, we may want to substitute in values for
placeholder text in the template file.
<<*>>=
enum POST_PROCESS_SUBSTITUTE_POS_MTID
<<*>>=
INT_METHOD_TYPE(POST_PROCESS_SUBSTITUTE_POS_MTID, weave_format *wf, text_stream *OUT,
weave_order *wv, text_stream *detail, weave_pattern *pattern)
int Formats::substitute_post_processing_data(OUTPUT_STREAM, weave_order *wv,
text_stream *detail, weave_pattern *pattern) {
int rv = TeXUtilities::substitute_post_processing_data(OUT, wv, detail);
INT_METHOD_CALL(rv, wv->format, POST_PROCESS_SUBSTITUTE_POS_MTID, OUT, wv, detail, pattern);
return rv;
}