1
0
Fork 0
mirror of https://github.com/ganelson/inform.git synced 2024-07-09 02:24:21 +03:00
inform7/inter/index-module/Chapter 1/Indexing API.w
2021-07-27 00:42:09 +01:00

218 lines
7.5 KiB
OpenEdge ABL

[Indexing::] Indexing API.
How the parent tool can ask for an Inter tree to be indexed.
@h Public API.
This is a large and complex module of code, but it really only does one thing,
and so it is simple to control. Other modules or tools should do this only by
calling the functions below.
To produce one or more index products (see below), first open a session; then
set its localisation -- essentially, choose what language it should be written
in; then call functions to make the actual products; and finally close the session.
Note that:
(1) If you want to index the same tree of code to two different languages, you
will need to do this as two sessions. However, an Index website and an EPS map
which are in the same language can both be made in the same session, and this
is more efficient than using two.
(2) Only one session can be open at a time. In some abstract sense it would be tidy
to make this whole module threadsafe, but in concrete terms, it's hard to see
what problem that would solve for anyone. If a user needs to make multiple
indexes simultaneously, the simplest way would be to start multiple |inter|
processes, each working on one project at a time. However, the API is designed
so that this decision could be reversed if we wanted to.
@ So, then, opening:
=
typedef struct index_session {
struct inter_tree *tree;
struct tree_inventory *inv;
struct inter_lexicon *lexicon;
struct faux_instance_set *set_of_instances;
struct linked_list *list_of_scenes; /* of |simplified_scene| */
struct localisation_dictionary *localisation;
struct linked_list *list_of_EPS_map_levels; /* of |EPS_map_level| */
struct linked_list *list_of_submaps; /* of |connected_submap| */
struct linked_list *list_of_pages; /* of |index_page| */
struct map_parameter_scope global_map_scope;
struct index_page_data page;
int story_dir_to_page_dir[MAX_DIRECTIONS];
int session_closed;
CLASS_DEFINITION
} index_session;
int index_sessions_open = 0;
index_session *Indexing::open_session(inter_tree *I) {
if (I == NULL) internal_error("no tree to index");
if (index_sessions_open++ > 0) internal_error("one indexing session at a time");
index_session *session = CREATE(index_session);
session->tree = I;
session->inv = Synoptic::inv(I);
session->lexicon = NULL;
session->set_of_instances = NULL;
session->list_of_scenes = NULL;
session->list_of_EPS_map_levels = NEW_LINKED_LIST(EPS_map_level);
session->list_of_submaps = NEW_LINKED_LIST(connected_submap);
session->list_of_pages = NEW_LINKED_LIST(index_page);
session->localisation = Localisation::new();
session->global_map_scope = ConfigureIndexMap::global_settings();
session->session_closed = FALSE;
for (int i=0; i<MAX_DIRECTIONS; i++)
session->story_dir_to_page_dir[i] = i;
return session;
}
@ Now localising. You can either set an existing dictionary which you happen
to have to hand, or else ask to read definitions from a file. See //html: Localisation//
for how all of this works.
=
void Indexing::set_localisation_dictionary(index_session *session, localisation_dictionary *LD) {
@<Check this is an open session@>;
session->localisation = LD;
}
void Indexing::localise(index_session *session, filename *F) {
@<Check this is an open session@>;
Localisation::stock_from_file(F, session->localisation);
}
@ Now for the productive part. You can make an entire index mini-website with
the following function, which may generate several hundred HTML files. This is
what is used in the Inform GUI apps on every compilation.
=
void Indexing::generate_index_website(index_session *session, text_stream *structure) {
@<Check this is an open session@>;
InterpretIndex::generate(structure, session);
}
@ This is a one-off function for generating the content of an index element
(without its heading, or any HTML surround): it's used for unit-testing those
elements, but is never used by the Inform GUI app.
=
void Indexing::generate_one_element(index_session *session, text_stream *OUT, wording elt) {
@<Check this is an open session@>;
Elements::test_card(OUT, elt, session);
}
@ This is used by the Inform GUI apps to "release along with an EPS file".
Essentially it makes a print-suitable version of the Map element of the index,
though there are also many bells and whistles for customising the appearance
of this.
=
void Indexing::generate_EPS_map(index_session *session, filename *F) {
@<Check this is an open session@>;
RenderEPSMap::render_map_as_EPS(F, session);
}
@ And lastly closing. The only thing this now does is to enable a new session
to be opened afterwards, in fact, but that might change in future.
=
void Indexing::close_session(index_session *session) {
@<Check this is an open session@>;
session->session_closed = TRUE;
index_sessions_open--;
}
@<Check this is an open session@> =
if (session == NULL) internal_error("no indexing session");
if (session->session_closed) internal_error("closed indexing session");
@h Private API.
The remaining functions in this section are for use only within the //index//
module.
=
inter_tree *Indexing::get_tree(index_session *session) {
@<Check this is an open session@>;
return session->tree;
}
localisation_dictionary *Indexing::get_localisation(index_session *session) {
@<Check this is an open session@>;
return session->localisation;
}
tree_inventory *Indexing::get_inventory(index_session *session) {
@<Check this is an open session@>;
return session->inv;
}
map_parameter_scope *Indexing::get_global_map_scope(index_session *session) {
return &(session->global_map_scope);
}
@ These build up gradually:
=
linked_list *Indexing::get_list_of_EPS_map_levels(index_session *session) {
@<Check this is an open session@>;
return session->list_of_EPS_map_levels;
}
void Indexing::add_EPS_map_levels(index_session *session, EPS_map_level *eml) {
@<Check this is an open session@>;
ADD_TO_LINKED_LIST(eml, EPS_map_level, session->list_of_EPS_map_levels);
}
linked_list *Indexing::get_list_of_submaps(index_session *session) {
@<Check this is an open session@>;
return session->list_of_submaps;
}
void Indexing::add_submap(index_session *session, connected_submap *sub) {
@<Check this is an open session@>;
ADD_TO_LINKED_LIST(sub, connected_submap, session->list_of_submaps);
}
void Indexing::empty_list_of_pages(index_session *session) {
@<Check this is an open session@>;
LinkedLists::empty(session->list_of_pages);
}
linked_list *Indexing::get_list_of_pages(index_session *session) {
@<Check this is an open session@>;
return session->list_of_pages;
}
void Indexing::add_page(index_session *session, index_page *page) {
@<Check this is an open session@>;
ADD_TO_LINKED_LIST(page, index_page, session->list_of_pages);
}
index_page *Indexing::latest_page(index_session *session) {
@<Check this is an open session@>;
if (LinkedLists::len(session->list_of_pages) == 0) return NULL;
return LAST_IN_LINKED_LIST(index_page, session->list_of_pages);
}
@ These more substantial resources are calculated all in one go, but only on demand:
=
inter_lexicon *Indexing::get_lexicon(index_session *session) {
@<Check this is an open session@>;
if (session->lexicon == NULL)
session->lexicon = IndexLexicon::stock(session->tree, session->inv);
return session->lexicon;
}
faux_instance_set *Indexing::get_set_of_instances(index_session *session) {
@<Check this is an open session@>;
if (session->set_of_instances == NULL) FauxInstances::make_faux(session);
return session->set_of_instances;
}
linked_list *Indexing::get_list_of_scenes(index_session *session) {
@<Check this is an open session@>;
if (session->list_of_scenes == NULL) FauxScenes::list_of_faux_scenes(session);
return session->list_of_scenes;
}