- Proposal: IE-0032
- Discussion PR link: #32
- Authors: Graham Nelson
- Status: Draft
- Related proposals: IE-0001
- Implementation: All kit changes made, MacOS app changes made, other apps pending
Kits (other than the built-in ones), and directory-format extensions, gain the ability to issue run-time problems of their own for the first time. Each RTP now has its own explanation file, written in Markdown format, which dynamically generates HTML for the apps to show when a user runs into an RTP.
The process for issuing RTPs in v10 is very inflexible. Only BasicInformKit
and WorldModelKit
are able to issue them, and even that division into two
piles is awkwardly done at present with linker tricks. New kits, such as
DialogueKit
, also need to issue RTPs, but currently can't. It's also long
overdue to be able to issue RTPs from Inform source text, rather than leaving
this an ability only of kit code.
- No change to the natural-language syntax.
- Major changes to inbuild.
- Minor changes to inform7.
- No change to inter.
- No change to the Inter specification.
- Minor changes to runtime kits.
- No change to the Standard Rules. Phrase added to Basic Inform.
- No change to documentation.
- Minor changes to the GUI apps.
None.
At present, when the app runs a story file it is continuously monitoring the output to look for lines in the shape:
*** Run-time problem TOKEN: ...
For example,
*** Run-time problem P17: You can't divide by zero
In Inform v10, the TOKEN
always takes the form P1
, P2
, ..., i.e., is always a P followed by a decimal number, but that is not actually required.
The app responds to seeing such a line by opening the Results pane opposite the Story, and showing a pre-made web page:
HTMLDIRECTORY/RTP_TOKEN.html
where HTMLDIRECTORY is its directory of web pages. The files - currently RTP_P1.html
, RTP_P2.html
, ... and so on - are stored inside the app as static HTML pages. These are created in the make transferoutcomepages
target, which is part of make integration
. The work is done by a tool called inrtps
using a single big text file of idiosyncratically formatted chunks of writing about the various RTPs.
The app should now detect the following pattern instead:
*** Run-time problem TOKEN: PATH
For example, the first line here should trigger the app:
*** Run-time problem DividedByZero: INTERNAL/Inter/BasicInformKit/RTPs
*** You can't divide by zero.
(The second and any subsequent lines are purely informational, and the app should not require them to be present.)
The following source will trigger it, for testing purposes:
Lab is a room.
Instead of jumping:
showme 2 / 0.
Test me with "jump".
The TOKEN
is a run of one or more non-whitespace characters: in practice it will always be alphanumeric and begin with a letter, and contain in particular no punctuation or spaces. TOKEN
will not be in the form P
followed by a decimal number, so that apps (if they wish to support old-style RTP detection for working with retrospective builds of Inform) can tell the difference between an old-style RTP and a new one. (Alternatively, such apps can know of course which version of Inform they are running.)
The PATH
tells the app where to find the explanation of this message. It identifies a directory in which a whole pile of RTP explanation pages can be found: the one we want is then PATH/TOKEN.html
. Note that PATH
may contain internal white space (though it may not end with white space): it continues to the end of the line it is printed on. For example:
*** Run-time problem BadKeyholder: MATERIALS/Extensions/Emily Short/Locksmith-v7.i7xd/RTPs
*** This is not a key which makes sense
In interpreting the path, the prefixes INTERNAL/
and MATERIALS/
should be expanded to the paths to the internal Inform resources and to the Materials folder for the current project, respectively. If these prefixes are not present, the path is an absolute pathname.
The app now locates Markdown source explaining the problem as, say, the file BadKeyholder.md
or DivideByZero.md
in the relevant folder. It then makes a call to inbuild to have an HTML version of the page generated on the fly:
inbuild -internal INTERNAL -markdown-from MARKDOWNFILE -markdown-to HTMLFILE
Here, INTERNAL
is the usual internal directory inside the app, always supplied when it calls inbuild. MARKDOWNFILE
is the filename of the file (e.g. DivideByZero.md
) referred to above. HTMLFILE
is some scratch file whose filename the app can choose: it can be anywhere convenient to the app.
inbuild
then generates the HTMLFILE
. This process cannot fail short of some major system disaster (running out of memory, disc full, etc.), because all Markdown source is legal, and takes no appreciable time to run. The app then displays HTMLFILE
as the web page to show in the Results panel.
Story files will only be set to print the quoted path in debug builds, since they are meaningful only when debugging in the app. A released story file, running outside of the apps, will therefore print something like this if it divides by zero:
*** Run-time problem DividedByZero:
*** You can't divide by zero.
At present only WorldModelKit
and BasicInformKit
can issue RTPs, and they do so by calling a function RunTimeProblem
, e.g.:
RunTimeProblem(RTP_LISTRANGEERROR);
RunTimeProblem(RTP_BADCONTAINMENT, F, T);
The first parameter is always one of an enumerated set of constants, currently listed in Definitions.i6t
inside BasicInformKit
(despite the fact that many of them related to WorldModelKit
).
These enumerated constants will go. Instead, calls will look like:
IssueRTP("ListRangeError", "Attempt to use list item which does not exist.", BasicInformKitRTPs);
IssueRTP("BadContainment", BadContainmentR, WorldModelKitRTPs, F, T);
The first parameter is the TOKEN
. The second is explanatory text, which can be either a string, or a routine, such as this one:
[ BadContainmentR par1 par2 par3;
print "Attempted to put ", (the) par1, " in ", (the) par2, ".^";
];
Or, the second parameter can also be -1
to mean "give no explanatory text on the second line".
The third parameter is the PATH
. Note that for these example calls, the path has been given using the constants BasicInformKitRTPs
and WorldModelKitRTPs
. Inform automatically defines such constants for all kits included in a build. For example, it may define:
Constant Architecture32KitRTPs = "INTERNAL/Inter/Architecture32Kit/RTPs";
Constant BasicInformKitRTPs = "INTERNAL/Inter/BasicInformKit/RTPs";
Constant CommandParserKitRTPs = "INTERNAL/Inter/CommandParserKit/RTPs";
Constant EnglishLanguageKitRTPs = "INTERNAL/Inter/EnglishLanguageKit/RTPs";
Constant WorldModelKitRTPs = "INTERNAL/Inter/WorldModelKit/RTPs";
The net result is that any kit can issue its own RTPs. A kit author need only use a function call like the one above, and put a suitable explanation in Markdown format into the RTPs
subdirectory of the kit.
Extensions have never previously been able to issue RTPs. Given that directory-format extensions can contain kits, and kits can now issue RTPs, it would now be possible to use that ability to trigger custom RTPs from an extension. But there's also a more direct way which need not involve any kit or use of I6-syntax code at all.
A new phrase is now defined in Basic Inform. For example, one could write:
issue the run-time problem "DialogueNestedTooDeep";
say "*** Dialogue scene nesting became too complicated";
This is legal only in the source text of a directory-format extension, and only if the parameter (here "DialogueNestedTooDeep"
) is a literal double-quoted text which contains the leafname of a Markdown file stored in the extension's RTPs
subdirectory. For example, suppose the above source were in the extension Dialogue Trickery by Marvin Queeg
: then the compiler would require the existence of the file:
Whatever.materials/Extensions/Marvin Queeg/Dialogue-v3.i7xd/RTPs/DialogueNestedTooDeep.md
Assuming this is indeed one of the RTPs provided by the extension, the phrase then compiles to a suitable function call to IssueRTP
, giving the correct RTP name-token and path.
As noted above, in v10 the core Inform build process used a small tool called inrtps
to manufacture the RTP and certain other outcome pages, such as the one displayed by the app if inform7 should unexpectedly crash.
This has now gone, and is no longer part of the repository. Its functions, such as they were, have been absorbed into inbuild
. The HTML generated by it has been modernised to remove all use of <font>
tags and layout-by-tables rather than by CSS, and to make all the tags tidily paired. The same CSS is used for these pages as for other index/extension documentation/etc. pages displayed in the app, so issues with needing to render differently on different platforms, and handling dark mode properly, should all be resolved.
Removing inrtps
affects the makefile, though only for the targets make integration
and make transferoutcomepages
(and their variants make forceintegration
and make forcetransferoutcomepages
): this now calls inbuild
not inrtps
.
If you are using these app-integration make targets, you may be setting a variable called INRTPSOPTS
in your make-integration-settings.mk
file to configure them. If so, you now needn't bother to. It is no longer used for anything and is ignored.