[SourceLinks::] Source Links. To provide HTML links to an Inform source text, using the non-standard "source" protocol. @ Index and Problem pages generated by //inform7//, via the //index// and //problems// modules, frequently need to have clickable icons linking to positions in the source text; when these are clicked in the Inform UI applications, the Source panel opens at the appropriate line. This is done with a non-standard HTML protocol called |source:|, one of two which the Inform UI apps must provide special handling for. For instance, line 21 of file |Bits and Pieces/marbles.txt| has URL: = (text) source:Bits and Pieces/marbles.txt#line14 = When an Inform app is viewing an extension project, there can also be references to individual examples in that extension, and these are referred to as "cases" since they are test cases when the app is testing the extension. For example, = (text) source:Locksmith.i7x?case=B#line7 = refers to line 7 of Example B of |Locksmith.i7x|. @ Locations are given relative to the current project bundle. However, if only a leafname is supplied, then this is read as a file within the |Source| subfolder of the project bundle. (Thus it is not possible to have a source link to a source file at the root of the project bundle: but this is no loss, since source is not allowed to be kept there.) For instance, line 14 of file |Source/story.ni| has URL = (text) source:story.ni#line14 = The following routine writes the clickable source-reference icon, and is the only place in Inform where |source:| URLs are generated. = inchar32_t source_link_case = 0; void SourceLinks::set_case(text_stream *p) { source_link_case = Characters::toupper(Str::get_first_char(p)); } void SourceLinks::link(OUTPUT_STREAM, source_location sl, int nonbreaking_space) { if (sl.file_of_origin) { TEMPORARY_TEXT(fn) WRITE_TO(fn, "%f", TextFromFiles::get_filename(sl.file_of_origin)); @; @; if (nonbreaking_space) WRITE(" "); else WRITE(" "); if (source_link_case) HTML_OPEN_WITH("a", "href=\"source:%S?case=%c#line%d\"", fn, source_link_case, sl.line_number) else HTML_OPEN_WITH("a", "href=\"source:%S#line%d\"", fn, sl.line_number); HTML_TAG_WITH("img", "border=0 src=inform:/doc_images/Reveal.png"); HTML_CLOSE("a"); DISCARD_TEXT(fn) } } @ This rather clumsily simplifies links to make them relative. @ = pathname *abbrev = HTML::get_link_abbreviation_path(); if (abbrev) { TEMPORARY_TEXT(pp) WRITE_TO(pp, "%p", abbrev); int N = Str::len(pp); if (Str::prefix_eq(fn, pp, N)) Str::delete_n_characters(fn, N+1); DISCARD_TEXT(pp) } @ = if ((Str::begins_with_wide_string(fn, U"Source")) && (Platform::is_folder_separator(Str::get_at(fn, 6)))) Str::delete_n_characters(fn, 7);