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.

311 lines
12 KiB

4 years ago
////
Included in:
- user-manual: Attributes: Setting attributes on a document
////
An [.term]_attribute entry_ is the primary mechanism for defining a document attribute in an AsciiDoc document.
You can think of an attribute entry as a global variable assignment for AsciiDoc.
The document attribute it creates becomes available from that point forward in the document.
Attribute entries are also frequently used to toggle features.
An attribute entry consists of two parts: an attribute name and an attribute value.
The attribute name comes first.
It must be at the start of the line and must be enclosed in colons (e.g., `:name:`).
If present, the attribute value is offset from the name part by at least one space (e.g., `:name: value`).
Be aware that substitutions automatically get applied to the value by default, as described in <<user-manual#attribute-entry-subs,Substitutions in an attribute entry>>.
.Anatomy of an attribute entry
[source]
----
:name: value
----
The attribute value is optional.
A blank value is often used to set (i.e., activate) a boolean attribute (thus making a blank value implicitly true).
.Anatomy of an attribute entry to set a boolean attribute
[source]
----
:name:
----
An exclamation point (`!`) before (or after) the attribute name unsets the attribute.
In this case, the value is ignored.
.Anatomy of an attribue entry to unset an attribute
[source]
----
:!name:
----
Attribute entries have the following characteristics:
Attributes entries can: ::
* be assigned to a document:
** through the CLI or API
** in the document's header
** in the document's body
* be unset (turned off) with a leading (or trailing) `!` added to the name
* have default values (in the case of a built-in attribute)
* have alternate values (in the case of a built-in attribute)
* span multiple, contiguous lines
* include inline AsciiDoc content
Attribute entries can not: ::
* override locked attributes assigned from the command line
* include AsciiDoc block content (such as, bulleted lists or other types of whitespace-dependent markup)
Attributes are typically defined in the document header, though they may also be defined in the body of the document.
Once set, an attribute (and its value) are available for use for the remainder of the document.
Unless locked by the API, attributes may be reassigned at any subsequent point in the document.
==== Attribute entry use cases
Attributes entries serve three main purposes:
. Toggle or configure built-in features
. Set built-in asset locations
. Content reuse
===== Setting built-in attributes
Numerous attribute are reserved for special purposes.
These built-in attributes can be used to toggle behavior, such as the table of contents, or control the generated output, such as selecting or configuring a converter.
Many built-in attributes only take effect when defined in the document header.
For example, to enable the built-in table of contents, you can define (i.e., set) the `toc` attribute using an attribute entry in the document header as follows:
[source]
----
:toc:
----
When the value following an attribute is left empty, as it is in the example above, the default value will be assigned (if any).
The default value for `toc` is `auto`.
Therefore, the table of contents will be placed in the default location (below the document's title) when the document is converted.
If you want the table of contents to be placed on the right side of the document, you must assign the attribute a new value.
[source]
----
:toc: right
----
The `right` value will override the default value of `auto`.
The value assigned to an attribute in the document header replaces the intrinsic value (assuming the attribute is not locked).
===== Setting asset locations
You can also use attributes to set the base path to images (default: _empty_), icons (default: `./images/icons`), and stylesheets (default: `./stylesheets`).
.Base asset path configuration example
[source]
----
:imagesdir: ./images
:iconsdir: ./icons
:stylesdir: ./styles
----
===== Content reuse
If you're familiar with writing in XML, you might recognize a document attribute as a user-defined entity.
When you find yourself typing the same text repeatedly, or text that often needs to be updated, consider assigning it to a document attribute and use that instead.
A prime use case for attribute entries is to promote frequently used URLs and links to the top of the document.
.URL attribute entry
[source]
----
:url-fedpkg: https://apps.fedoraproject.org/packages/rubygem-asciidoctor
----
Now you can refer to this attribute entry anywhere in the document (where attribute substitution is performed) by surrounding its name in curly braces.
Instead of having to type the URL out longhand in the link macro, as follows:
.A case for using an attribute reference
[source]
----
Did you know there's an https://apps.fedoraproject.org/packages/rubygem-asciidoctor[Asciidoctor package for Fedora]?
----
We can replace the target side of the link macro with a reference to our attribute.
.url-fedpkg attribute usage example
[source]
----
Did you know there's an {url-fedpkg}[Asciidoctor package for Fedora]?
----
To save even more typing, you can store the whole link in an attribute value.
.Link attribute entry
[source]
----
:link-fedpkg: https://apps.fedoraproject.org/packages/rubygem-asciidoctor[Asciidoctor package for Fedora]
----
Now you insert this link anywhere in the document using an attribute reference.
.link-fedpkg attribute usage example
[source]
----
Did you know there's an {link-fedpkg}?
----
Note that the link substitution occurs _after_ the attribute reference is resolved.
This works thanks to the default order of substitutions on a paragraph.
If you want the link macro to be resolved eagerly at the time the attribute is assigned, you need to enclose it in a pass macro.
.Link attribute entry resolved eagerly
[source]
----
:link-fedpkg: pass:m[https://apps.fedoraproject.org/packages/rubygem-asciidoctor[Asciidoctor package for Fedora]]
----
Now you can use this link in a section title (where the order of substitutions is different).
Let's dive deeper into which substitutions are applied to an attribute entry and how to alter them.
[#attribute-entry-subs]
==== Substitutions in an attribute entry
The AsciiDoc processor automatically applies substitutions from the header substitution group to the value of an attribute entry prior to the assignment (regardless of where the attribute entry is declared in the document).
The header substitution group replaces <<user-manual#special-characters,special characters>> and <<user-manual#attributes-2,attribute references>>.
This is the same group that gets applied to metadata lines (author and revision information) in the document header.
To learn about how these substitutions work, refer to the <<user-manual#subs,Substitutions>> chapter.
==== Altering attribute entry substitutions
If you want the value of an attribute entry to be used *as is* (not subject to substitutions), or you want to alter the substitutions that are applied, you can enclose the value in the <<user-manual#pass-macros,inline pass macro>> (i.e., `\pass:[]`).
The inline pass macro accepts a list of zero or more substitutions in the target slot, which can be used to control which substitutions are applied to the value.
If no substitutions are specified, no substitutions will be applied.
In order for the inline macro to work in this context, it must completely surround the attribute value.
If it's used anywhere else in the value, it is ignored.
Here's how to prevent substitutions from being applied to the value of an attribute entry:
[source]
----
:cols: pass:[.>2,.>4]
----
This might be useful if you're referencing the attribute in a place that depends on the unaltered text, such as the value of the `cols` attribute on a table.
Here's how to apply the <<user-manual#quotes,quotes substitution>> to the value of an attribute entry:
[source]
----
:app-name: pass:quotes[MyApp^2^]
----
Internally, the value is stored as `MyApp<sup>2</sup>`.
You can inspect the value stored in an attribute using this trick:
[listing]
....
[subs=attributes+]
----
{app-name}
----
....
You can also specify the substitution using the single-character alias, `q`.
[source]
----
:app-name: pass:q[MyApp^2^]
----
The inline pass macro kind of works like an attribute value preprocessor.
If the processor detects that an inline pass macro completely surrounds the attribute value, it:
. reads the list of substitutions from the target slot of the macro
. unwraps the value from the macro
. applies the substitutions to the value
If the macro is absent, the value is processed with the header substitution group.
You can also change the substitutions that are applied to an attribute at the time it is resolved.
This is done by manipulating the substitutions applied to the text where it is referenced.
For example, here's how we could get the processor to apply quote substitutions to the value of an attribute:
[source]
----
:app-name: MyApp^2^
[subs="specialchars,attributes,quotes,replacements,macros,post_replacements"]
The application is called {app-name}.
----
Notice that we've swapped the order of the `attributes` and `quotes` substitutions.
This strategy is akin to postprocessing the attribute value.
==== Splitting attribute values over multiple lines
When an attribute value is very long, it's possible to split it (i.e., soft-wrap) across multiple lines.
Let's assume we are working with the following attribute entry:
.A long, single-line attribute
[source]
----
:long-value: If you have a very long line of text that you need to substitute regularly in a document, you may find it easier to split it neatly in the header so it remains readable to the next person reading your docs code.
----
You can split the value over multiple lines to make it more readable by inserting a space followed by a backslash (i.e., `{sp}\`) at the end of each continuing line.
.A long, multiline attribute (soft wrapped)
[source]
----
:long-value: If you have a very long line of text \
that you need to substitute regularly in a document, \
you may find it easier to split it neatly in the header \
so it remains readable to folks reading your docs code.
----
The backslash and the newline that follows will be removed from the attribute value when the attribute entry is parsed, making this second example effectively the same as the first.
The space before the backslash is preserved, so you have to use this technique at a natural break point in the content.
You can force an attribute value to hard wrap by adding a plus surrounded by spaces before the backslash.
.An attribute value with hard line breaks
[source]
----
:haiku: Write your docs in text, + \
AsciiDoc makes it easy, + \
Now get back to work!
----
This syntax ensures that the newlines are preserved in the output document as hard line breaks.
==== Attribute limitations
Attributes let you do a surprising amount of formatting for what is fundamentally a text replacement tool.
It may be tempting to try and extend attributes to be used for complex replaceable markup.
Supported::
Basic in-line AsciiDoc markup is permitted in attribute values, such as:
+
* attribute references
* text formatting (usually wrapped in a pass macro)
* inline macros (usually wrapped in a pass macro)
Unsupported::
Complex AsciiDoc markup is not permitted in attribute values, such as:
+
* lists
* multiple paragraphs
* other whitespace-dependent markup types
////
TODO: This section actually might make more sense in the header section.
The main focus of the learning for this documentation is how to use inline formatting in an attribute value. Normally, inline formatting in an attribute value is not interpreted because:
a. Inline formatting is not applied when an attribute is set (attribute holds raw value)
b. Inline formatting is not applied when an attribute is referenced since the relevant substitutions come before attributes are resolved
////