From: Fletcher T. Penney
File transclusion works basically the same way – {{file}}
is used to
+indicate a file that needs to be transcluded. {{file.*}}
allows for
+wildcard transclusion. What’s different is that the way search paths are
+handled is more flexible, though it may take a moment to understand.
When you process a file with MMD, it uses that file’s directory as the search +path for included files. For example:
+ +Directory | +Transcluded Filename | +Resolved Path | +
---|---|---|
/foo/bar/ |
+ bat |
+ /foo/bar/bat |
+
/foo/bar/ |
+ baz/bat |
+ /foo/bar/baz/bat |
+
/foo/bar/ |
+ ../bat |
+ /foo/bat |
+
This is the same as MMD v 5. What’s different is that when you transclude a
+file, the search path stays the same as the “parent” file, UNLESS you use
+the transclude base
metadata to override it. The simplest override is:
transclude base: .
+
+
+This means that any transclusions within the file will be calculated relative +to the file, regardless of the original search path.
+ +Alternatively you could specify that any transclusion happens inside a +subfolder:
+ +transclude base: folder/
+
+
+Or you can specify an absolute path:
+ +transclude base: /some/path
+
+
+This flexibility means that you can transclude different files based on +whether a file is being processed by itself or as part of a “parent” file. +This can be useful when a particular file can either be a standalone document, +or a chapter inside a larger document.
+Some features I plan to implement at some point:
diff --git a/QuickStart/QuickStart.pdf b/QuickStart/QuickStart.pdf index 00d00e8..3472980 100644 Binary files a/QuickStart/QuickStart.pdf and b/QuickStart/QuickStart.pdf differ diff --git a/QuickStart/QuickStart.txt b/QuickStart/QuickStart.txt index 0021f60..550f911 100644 --- a/QuickStart/QuickStart.txt +++ b/QuickStart/QuickStart.txt @@ -271,6 +271,47 @@ Table of Contents functionality is used when exporting to LaTeX or OpenDocument formats. +## Transclusion ## + +File transclusion works basically the same way -- `{{file}}` is used to +indicate a file that needs to be transcluded. `{{file.*}}` allows for +wildcard transclusion. What's different is that the way search paths are +handled is more flexible, though it may take a moment to understand. + +When you process a file with MMD, it uses that file's directory as the search +path for included files. For example: + +| Directory | Transcluded Filename | Resolved Path | +| ----------- | -------------------- | ------------------ | +| `/foo/bar/` | `bat` | `/foo/bar/bat` | +| `/foo/bar/` | `baz/bat` | `/foo/bar/baz/bat` | +| `/foo/bar/` | `../bat` | `/foo/bat` | + + +This is the same as MMD v 5. What's different is that when you transclude a +file, the search path stays the same as the "parent" file, **UNLESS** you use +the `transclude base` metadata to override it. The simplest override is: + + transclude base: . + +This means that any transclusions within the file will be calculated relative +to the file, regardless of the original search path. + +Alternatively you could specify that any transclusion happens inside a +subfolder: + + transclude base: folder/ + +Or you can specify an absolute path: + + transclude base: /some/path + +This flexibility means that you can transclude different files based on +whether a file is being processed by itself or as part of a "parent" file. +This can be useful when a particular file can either be a standalone document, +or a chapter inside a larger document. + + # Future Steps # Some features I plan to implement at some point: diff --git a/Sources/libMultiMarkdown/transclude.c b/Sources/libMultiMarkdown/transclude.c index 53f0f5d..e647241 100644 --- a/Sources/libMultiMarkdown/transclude.c +++ b/Sources/libMultiMarkdown/transclude.c @@ -274,12 +274,12 @@ DString * scan_file(const char * fname) { /// Recursively transclude source text, given a search directory. /// Track files to prevent infinite recursive loops -void transclude_source(DString * source, const char * dir, short format, stack * parsed, stack * manifest) { +void transclude_source(DString * source, const char * search_path, const char * source_path, short format, stack * parsed, stack * manifest) { DString * file_path; DString * buffer; - // Ensure folder is tidied up - char * folder = path_from_dir_base(dir, NULL); + // Ensure search_folder is tidied up + char * search_folder = path_from_dir_base(search_path, NULL); char * start, * stop; char text[1100]; @@ -289,22 +289,28 @@ void transclude_source(DString * source, const char * dir, short format, stack * size_t offset; size_t last_match; - // TODO: Does this source have metadata that overrides the search directory? mmd_engine * e = mmd_engine_create_with_dstring(source, EXT_TRANSCLUDE); if (mmd_has_metadata(e, &offset)) { temp = metavalue_for_key(e, "transclude base"); if (temp) { - free(folder); + // The new file overrides the search path + free(search_folder); - folder = path_from_dir_base(dir, temp); + // First, calculate path to this source file + char * temp_path = path_from_dir_base(search_path, source_path); + + // Then, calculate new search path relative to source + search_folder = path_from_dir_base(temp_path, temp); + + free(temp_path); } } mmd_engine_free(e, false); - if (folder == NULL) { + if (search_folder == NULL) { // We don't have anywhere to search, so nothing to do goto exit; } @@ -348,9 +354,9 @@ void transclude_source(DString * source, const char * dir, short format, stack * file_path = d_string_new(text); } else { // Relative path - file_path = d_string_new(folder); + file_path = d_string_new(search_folder); - // Ensure that folder ends in separator + // Ensure that search_folder ends in separator add_trailing_sep(file_path); d_string_append(file_path, text); @@ -419,8 +425,15 @@ void transclude_source(DString * source, const char * dir, short format, stack * d_string_erase(source, start - source->str, 2 + stop - start); // Recursively check this file for transclusions - transclude_source(buffer, folder, format, parse_stack, manifest); + char * new_search_path; + char * source_filename; + split_path_file(&new_search_path, &source_filename, file_path->str); + transclude_source(buffer, search_folder, new_search_path, format, parse_stack, manifest); + + free(new_search_path); + free(source_filename); + // Strip metadata from buffer now that we have parsed it e = mmd_engine_create_with_dstring(buffer, EXT_TRANSCLUDE); @@ -469,7 +482,7 @@ void transclude_source(DString * source, const char * dir, short format, stack * stack_free(parse_stack); } - free(folder); + free(search_folder); } diff --git a/Sources/libMultiMarkdown/transclude.h b/Sources/libMultiMarkdown/transclude.h index 612cb3e..9dda79a 100644 --- a/Sources/libMultiMarkdown/transclude.h +++ b/Sources/libMultiMarkdown/transclude.h @@ -73,7 +73,7 @@ DString * scan_file(const char * fname); /// Recursively transclude source text, given a search directory. /// Track files to prevent infinite recursive loops -void transclude_source(DString * source, const char * dir, short format, stack * parsed, stack * manifest); +void transclude_source(DString * source, const char * search_path, const char * source_path, short format, stack * parsed, stack * manifest); #endif diff --git a/Sources/multimarkdown/main.c b/Sources/multimarkdown/main.c index ec379c9..9eda9ea 100644 --- a/Sources/multimarkdown/main.c +++ b/Sources/multimarkdown/main.c @@ -340,7 +340,7 @@ int main(int argc, char** argv) { if (extensions & EXT_TRANSCLUDE) { - transclude_source(buffer, folder, format, NULL, NULL); + transclude_source(buffer, folder, "", format, NULL, NULL); // Don't free folder -- owned by dirname } @@ -417,7 +417,7 @@ int main(int argc, char** argv) { // Perform transclusion(s) char * folder = dirname((char *) a_file->filename[0]); - transclude_source(buffer, folder, format, NULL, NULL); + transclude_source(buffer, folder, "", format, NULL, NULL); // Don't free folder -- owned by dirname } diff --git a/tests/MMD6Tests/Transclusion.fodt b/tests/MMD6Tests/Transclusion.fodt index 28a5809..ea2ac6b 100644 --- a/tests/MMD6Tests/Transclusion.fodt +++ b/tests/MMD6Tests/Transclusion.fodt @@ -292,7 +292,8 @@This text is included in transclusion/baz.txt
.
This should pull in bar.txt
, if run from the parent directory.
This should pull in bar.txt
, if run from the parent directory, since it
+does not override the transclude base
metadata.
This text is included in bar.txt
.
This is a file with no metadata.
+This text is included in transclusion/baz2.txt
.
This should pull in transclusion/bar.txt
, even if run from the parent
+directory, since it overrides the transclude base
metadata.
This text is included in transclusion\bar.txt
.
foo can no longer be found – {{foo.txt}}
+