You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

226 lines
9.1 KiB

////
== Include Directive
Included in:
- user-manual
////
The include directive provides a way to import content from another file into the current document.
The include directive must be placed on a line by itself with the following syntax, which is covered in detail in the next section.
----
\include::path[<attrlist>]
----
When the document is processed, the include directive is replaced by the contents of the include file.
Think of the include directive like a file expander.
This directive is useful if you want to:
* partition a large document into smaller files (for better organization and to make restructuring simpler),
** (always separate consecutive include directives by a blank line unless your intent is for the included lines to run together)
* insert snippets of source code (so your examples are kept up-to-date with the latest source files),
* populate tables with output from other programs (e.g., CSV data),
* create document variants by combining the include directive with preprocessor conditionals (e.g., `ifdef`), and
* reuse fragments and boilerplate content multiple times within the same document.
You can use the include directive as many times as you want in the same document.
CAUTION: The include directive is _disabled_ when Asciidoctor is run in secure mode.
In this mode, the include directive is converted to a link in the output document.
To learn more about secure mode, refer to the section <<Running Asciidoctor Securely>>.
[#include-anatomy]
=== Anatomy
The include directive has the following anatomy:
[source,subs=+quotes]
----
\include::path[leveloffset=__offset__,lines=__ranges__,tag(s)=__name(s)__,indent=__depth__,opts=optional]
----
The leveloffset, lines, tag(s), indent, and opt attributes are optional, making the simplest case look like:
[source]
----
\include::content.adoc[]
----
The sections that follow go into detail about when the include is processed, how the include file is resolved, and how each attribute is used.
[#include-processing]
=== Processing
Although the include directive looks like a block macro, it's not a macro and therefore not processed like one.
Instead, it's a _preprocessor_ directive, just like `ifdef` and `ifeval`.
It's important to understand the distinction.
A preprocessor directive is processed when the lines are read, but before the document structure is parsed.
Therefore, it's _not_ aware of the surrounding document structure.
A preprocessor directive merely adds lines to the reader or takes lines away.
The include directive is a preprocessor directive that always adds lines.
The best way to think of the include directive is to imagine that it is being replaced by the lines from the include file (i.e., the imported lines).
Only then does the parser read and interpret those lines.
That's also why it's important to surround the include directive by blank lines if it imports in a discrete structure.
You only want to place include files directly adjacent to one another if the imported content should be directly adjacent.
If you don't want the include directive to be processed, you must escape it using a backslash.
\include::just-an-example.ext[]
Escaping the directive is necessary _even if it appears in a verbatim block_ since it's not aware of the surrounding document structure.
[#include-resolution]
=== File resolution
The path used in an include directive may be either relative or absolute.
If the path relative, the processor resolves the path using the following rules:
* If the include directive is used in the main (top-level) document, relative paths are resolved relative to the base directory.
(The base directory defaults to the directory of the main document and can be overridden from the CLI or API).
* If the include directive is used in a file that has itself been included, the path is resolved relative to the including (i.e., current) file.
//TODO show examples to contrast a relative vs an absolute include
These defaults makes it easy to reason about how the path to the include file is resolved.
If the processor cannot locate the file (perhaps because you mistyped the path), you'll still be able to convert the document.
However, you will get the following warning message during conversion:
asciidoctor: WARNING: master.adoc: line 3: include file not found: /.../content.adoc
The following message will also be inserted into the output:
Unresolved directive in master.adoc - include::content.adoc[]
To fix the problem, edit the file path and run the converter again.
TIP: If you want Asciidoctor not to trigger a warning when the target is missing, set the optional option on the include directive (e.g., `opts=optional`).
If you store your AsciiDoc files in nested folders at different levels, relative file paths can quickly become awkward and inflexible.
A common pattern to help here is to define the paths in attributes defined in the header, then prefix all include paths with a reference to one of these attributes:
[listing]
....
:includedir: _includes
:sourcedir: ../src/main/java
\include::{includedir}/fragment1.adoc[]
[source,java]
----
\include::{sourcedir}/org/asciidoctor/Asciidoctor.java[]
----
....
Keep in mind that no matter how Asciidoctor resolves the path to the file, access to that file is limited by the safe mode setting under which Asciidoctor is run.
If a path violates the security restrictions, it may be truncated.
[#include-partitioning]
=== Partitioning large documents and using leveloffset
When your document gets large, you can split it up into subsections for easier editing as follows:
----
= My book
\include::chapter01.adoc[]
\include::chapter02.adoc[]
\include::chapter03.adoc[]
----
IMPORTANT: Take note of the blank lines between the include directives.
The blank line between include directives prevents the first and last lines of the included files from being adjoined.
This practice is *strongly* encouraged when combining document parts.
If you don't include these blank lines, you might find that the AsciiDoc processor swallows section titles.
This happens because the leading section title can get interpreted as the last line of the final paragraph in the preceding include.
Only place include directives on consecutive lines if the intent is for the includes to run together (such as in a listing block).
The leveloffset attribute can help here by pushing all headings in the included document down by the specified number of levels.
This allows you to publish each chapter as a standalone document (complete with a document title), but still be able to include the chapters into a master document (which has its own document title).
You can easily assemble your book so that the chapter document titles become level 1 headings using:
----
= My Book
\include::chapter01.adoc[leveloffset=+1]
\include::chapter02.adoc[leveloffset=+1]
\include::chapter03.adoc[leveloffset=+1]
----
Because the leveloffset is _relative_ (it begins with + or -), this works even if the included document has its own includes and leveloffsets.
If you have lots of chapters to include and want them all to have the same offset, you can save some typing by setting leveloffset around the includes:
----
= My book
:leveloffset: +1
\include::chapter01.adoc[]
\include::chapter02.adoc[]
\include::chapter03.adoc[]
:leveloffset: -1
----
The final line returns the leveloffset to 0.
Alternatively, you could use absolute levels:
----
:leveloffset: 1
//includes
:leveloffset: 0
----
Relative levels are preferred.
Absolute levels become awkward when you have nested includes since they aren't context aware.
[#include-nonasciidoc]
=== AsciiDoc vs non-AsciiDoc files
The include directive performs a simple file merge, so it works with any text file.
// NOTE this point about normalization should probably be moved to an earlier section
The content of all included content is normalized.
This means that the encoding is forced to UTF-8 (or converted from UTF-16 to UTF-8 if the file contains a BOM) and trailing whitespace and endlines are removed from each line and replaced with a Unix line feed.
This normalization is important to how Asciidoctor works.
If the file is recognized as an AsciiDoc file (i.e., it has one of the following extensions: `.asciidoc`, `.adoc`, `.ad`, `.asc`, or `.txt`), Asciidoctor runs the preprocessor on the lines, looking for and interpreting the following directives:
* includes
* preprocessor conditionals (e.g., `ifdef`)
//* front matter (if enabled)
This allows includes to be nested, and provides lot of flexibility in constructing radically different documents with a single master document and a few command line attributes.
Including non-AsciiDoc files is normally done to merge output from other programs or populate table data:
----
.2016 Sales Results
,===
\include::sales/2016/results.csv[]
,===
----
In this case, the include directive does not do any processing of AsciiDoc directives.
The content is inserted as is (after being normalized).
////
CAUTION: You *can* put AsciiDoc content in a non-AsciiDoc file.
Its content will still be processed as AsciiDoc, but any include statements will be ignored, and therefore cause errors later in processing.
It is likely to cause confusion, so best avoided.
////