asciidoc-parser 0.19.0

Parser for AsciiDoc format
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
use crate::tests::prelude::*;

track_file!("ref/asciidoc-lang/docs/modules/tables/pages/align-by-cell.adoc");

non_normative!(
    r#"
= Align Content by Cell

The alignment operators are applied to a xref:add-cells-and-rows.adoc#specifiers[cell's specifier] and allow you to horizontally and vertically align a cell's content.

"#
);

/// Parse `source` as a single block and return the [`TableBlock`] it produced.
///
/// [`TableBlock`]: crate::blocks::TableBlock
fn parse_table(source: &str) -> crate::blocks::TableBlock<'_> {
    let mut parser = Parser::default();
    let mi = crate::blocks::Block::parse(crate::Span::new(source), &mut parser)
        .unwrap_if_no_warnings()
        .unwrap();

    match mi.item {
        crate::blocks::Block::Table(table) => table,
        other => panic!("expected a table block, got {other:?}"),
    }
}

/// Collect the `(horizontal, vertical)` alignment of each cell in each body
/// row of `table`.
fn body_alignments(
    table: &crate::blocks::TableBlock<'_>,
) -> Vec<Vec<(HorizontalAlignment, VerticalAlignment)>> {
    table
        .body_rows()
        .iter()
        .map(|row| {
            row.cells()
                .iter()
                .map(|cell| (cell.h_align(), cell.v_align()))
                .collect()
        })
        .collect()
}

#[test]
fn horizontal_alignment_operators() {
    non_normative!(
        r#"
[#horizontal-operators]
== Horizontal alignment operators

"#
    );

    verifies!(
        r#"
Content can be horizontally aligned to the left or right side of the cell as well as the center of the cell.

Flush left operator (<):: The less-than sign (`<`) aligns the content to the left side of the cell.
This is the default horizontal alignment.
Flush right operator (>):: The greater-than sign (`>`) aligns the content to the right side of the cell.
Center operator (^):: The caret (`+^+`) centers the content horizontally in the cell.

A horizontal alignment operator is entered after a span or duplication operator (if present) and in front a <<vertical-operators,vertical alignment operator>> (if present).

====
<factor><span or duplication operator><**horizontal alignment operator**><vertical alignment operator><style operator>|<cell's content>
====

"#
    );

    // The three horizontal alignment operators on cell specifiers: `<` (left,
    // the default), `>` (right), and `^` (center). Entered directly in front of
    // the cell separator (`|`).
    let table = parse_table("|===\n<|a >|b ^|c\n|===");
    assert_eq!(
        body_alignments(&table),
        vec![vec![
            (HorizontalAlignment::Left, VerticalAlignment::Top),
            (HorizontalAlignment::Right, VerticalAlignment::Top),
            (HorizontalAlignment::Center, VerticalAlignment::Top),
        ]]
    );
}

#[test]
fn center_content_horizontally_in_a_cell() {
    non_normative!(
        r#"
=== Center content horizontally in a cell

"#
    );

    verifies!(
        r#"
To horizontally center the content in a cell, place the `+^+` operator in front of the xref:add-cells-and-rows.adoc#cell-separator[cell's separator] (`|`).
Don't insert any spaces between the `|` and the operator.

.Center the content of a cell horizontally
[source#ex-hcenter]
----
include::example$align-cell.adoc[tag=hcenter]
----

The table from <<ex-hcenter>> is rendered below.

.Result of <<ex-hcenter>>
include::example$align-cell.adoc[tag=hcenter]

"#
    );

    // Expansion of `example$align-cell.adoc[tag=hcenter]`. The first cell is
    // centered (`^|`); the second falls back to the default (left).
    let table = parse_table(
        "|===\n|Column Name |Column Name\n\n^|This content is horizontally centered because the cell specifier includes the `+^+` operator.\n|There isn't a horizontal alignment operator on this cell specifier, so the cell falls back to the default horizontal alignment.\nContent is aligned to the left side of the cell by default.\n|===",
    );
    assert_eq!(
        body_alignments(&table),
        vec![vec![
            (HorizontalAlignment::Center, VerticalAlignment::Top),
            (HorizontalAlignment::Left, VerticalAlignment::Top),
        ]]
    );

    verifies!(
        r#"
If the cell specifier includes a span (`<n>+`) or duplication (`+<n>*+`), place the `+^+` directly after the span or duplication operator.

.Center content horizontally in spanned columns and duplicated cells
[source#ex-factor]
----
include::example$align-cell.adoc[tag=factor]
----

The table from <<ex-factor>> is rendered below.

.Result of <<ex-factor>>
include::example$align-cell.adoc[tag=factor]

"#
    );

    // Expansion of `example$align-cell.adoc[tag=factor]`. The `+^+` operator is
    // placed directly after the span (`2+`) and duplication (`2*`) operators;
    // both cells are centered. The `2+` span fills the two-column row on its own,
    // so it lands in its own row; the `2*^` duplication clones its centered
    // content into the two cells of the next row.
    let table = parse_table(
        "|===\n|Column Name |Column Name\n\n2+^|This cell spans two columns, and its content is horizontally centered because the cell specifier includes the `+^+` operator.\n2*^|This content is duplicated in two adjacent columns.\nIts content is horizontally centered because the cell specifier\nincludes the `+^+` operator.\n|===",
    );
    assert_eq!(
        body_alignments(&table),
        vec![
            vec![(HorizontalAlignment::Center, VerticalAlignment::Top)],
            vec![
                (HorizontalAlignment::Center, VerticalAlignment::Top),
                (HorizontalAlignment::Center, VerticalAlignment::Top),
            ],
        ]
    );
}

#[test]
fn align_the_content_of_a_cell_to_the_right() {
    non_normative!(
        r#"
== Align the content of a cell to the right

"#
    );

    verifies!(
        r#"
To align the content in a cell to its right side, place the `>` operator in front of the xref:add-cells-and-rows.adoc#cell-separator[cell's separator] (`|`), but after a span (`<n>+`) or duplication (`+<n>*+`) operator (if present).
Don't insert any spaces between the `|` and the operators.

.Right align the content of a cell
[source#ex-right]
----
include::example$align-cell.adoc[tag=right]
----

The table from <<ex-right>> is rendered below.

.Result of <<ex-right>>
include::example$align-cell.adoc[tag=right]

"#
    );

    // Expansion of `example$align-cell.adoc[tag=right]`. The `>` operator
    // right-aligns the first cell and the spanned cell (`2+>`); the cell with no
    // operator falls back to the default (left).
    let table = parse_table(
        "|===\n|Column Name |Column Name\n\n>|This content is aligned to the right side of the cell because the cell specifier includes the `>` operator.\n|There isn't a horizontal alignment operator on this cell specifier, so the cell falls back to the default horizontal alignment.\nContent is aligned to the left side of the cell by default.\n\n2+>|This cell spans two columns.\n\nIts content is aligned to the right because the cell specifier includes the `>` operator.\nThe `>` operator must be placed directly after the span operator (`+`).\n|===",
    );
    assert_eq!(
        body_alignments(&table),
        vec![
            vec![
                (HorizontalAlignment::Right, VerticalAlignment::Top),
                (HorizontalAlignment::Left, VerticalAlignment::Top),
            ],
            vec![(HorizontalAlignment::Right, VerticalAlignment::Top)],
        ]
    );
}

#[test]
fn vertical_alignment_operators() {
    non_normative!(
        r#"
[#vertical-operators]
== Vertical alignment operators

"#
    );

    verifies!(
        r#"
Content can be vertically aligned to the top or bottom of a cell as well as the center of a cell.
Vertical alignment operators always begin with a dot (`.`).

Flush top operator (.<):: The dot and less-than sign (`.<`) aligns the content to the top of the cell.
This is the default vertical alignment.
Flush bottom operator (.>):: The dot and greater-than sign (`.>`) aligns the content to the bottom of the cell.
Center operator (.^):: The dot and caret (`+.^+`) centers the content vertically.

A vertical alignment operator is entered after a <<horizontal-operators,horizontal alignment operator>> (if present) and in front of a style operator (if present).

====
<factor><span or duplication operator><horizontal alignment operator><**vertical alignment operator**><style operator>|<cell's content>
====

"#
    );

    // The three vertical alignment operators on cell specifiers: `.<` (top, the
    // default), `.>` (bottom), and `.^` (center).
    let table = parse_table("|===\n.<|a .>|b .^|c\n|===");
    assert_eq!(
        body_alignments(&table),
        vec![vec![
            (HorizontalAlignment::Left, VerticalAlignment::Top),
            (HorizontalAlignment::Left, VerticalAlignment::Bottom),
            (HorizontalAlignment::Left, VerticalAlignment::Middle),
        ]]
    );
}

#[test]
fn align_content_to_the_bottom_of_a_cell() {
    non_normative!(
        r#"
=== Align content to the bottom of a cell

"#
    );

    verifies!(
        r#"
To align the content to the bottom of a cell, place the `+.>+` operator in front of the xref:add-cells-and-rows.adoc#cell-separator[cell's separator] (`|`).
Don't insert any spaces between the `|` and the operator.

.Align content to the bottom of a cell
[source#ex-bottom]
----
include::example$align-cell.adoc[tag=bottom]
----

The table from <<ex-bottom>> is rendered below.

.Result of <<ex-bottom>>
include::example$align-cell.adoc[tag=bottom]

"#
    );

    // Expansion of `example$align-cell.adoc[tag=bottom]`. The first cell is
    // bottom-aligned (`.>|`); the second has no vertical alignment operator and
    // falls back to the column's alignment (the `cols="2,1"` columns are
    // top-aligned by default).
    let table = parse_table(
        "[cols=\"2,1\"]\n|===\n|Column Name |Column Name\n\n.>|This content is aligned to the bottom of the cell because the cell specifier includes the `.>` operator.\n|There isn't a vertical alignment operator on this cell specifier, so the cell falls back to the alignment assigned via the column specifier or the default vertical alignment.\nContent is aligned to the top of the cell by default.\n|===",
    );
    assert_eq!(
        body_alignments(&table),
        vec![vec![
            (HorizontalAlignment::Left, VerticalAlignment::Bottom),
            (HorizontalAlignment::Left, VerticalAlignment::Top),
        ]]
    );

    verifies!(
        r#"
If the cell specifier includes a span (`<n>+`) or duplication (`+<n>*+`), place the `.>` after the span or duplication operator.

.Align content to the bottom of a cell that spans rows
[source#ex-span-vertical]
----
include::example$align-cell.adoc[tag=vspan]
----

The table from <<ex-span-vertical>> is rendered below.

.Result of <<ex-span-vertical>>
include::example$align-cell.adoc[tag=vspan]

"#
    );

    // Expansion of `example$align-cell.adoc[tag=vspan]`. The `.>` is placed
    // after the row-span operator (`.2+`); that cell is bottom-aligned, while
    // the cells with no vertical alignment operator stay top-aligned. The `.2+`
    // cell spans two rows, so it carries its column down into the next row, which
    // then needs only the one remaining cell.
    let table = parse_table(
        "|===\n|Column Name |Column Name\n\n|There isn't a vertical alignment operator on this cell specifier, so the content is aligned to the top of the cell by default.\n\n.2+.>|This cell spans two rows, and its content is aligned to the bottom because the cell specifier includes the `.>` operator.\n\n|This content is aligned to the top of the cell by default.\n|===",
    );
    assert_eq!(
        body_alignments(&table),
        vec![
            vec![
                (HorizontalAlignment::Left, VerticalAlignment::Top),
                (HorizontalAlignment::Left, VerticalAlignment::Bottom),
            ],
            vec![(HorizontalAlignment::Left, VerticalAlignment::Top)],
        ]
    );
}

#[test]
fn center_content_vertically_in_a_cell() {
    non_normative!(
        r#"
=== Center content vertically in a cell

"#
    );

    verifies!(
        r#"
To vertically center the content in a cell, place the `+.^+` operator in front of the xref:add-cells-and-rows.adoc#cell-separator[cell's separator] (`|`).
Don't insert any spaces between the `|` and the operator.

.Center the content of a cell vertically
[source#ex-vcenter]
----
include::example$align-cell.adoc[tag=vcenter]
----

The table from <<ex-vcenter>> is rendered below.

.Result of <<ex-vcenter>>
include::example$align-cell.adoc[tag=vcenter]

"#
    );

    // Expansion of `example$align-cell.adoc[tag=vcenter]`. The first cell is
    // vertically centered (`.^|`); the second falls back to the default (top).
    let table = parse_table(
        "|===\n|Column Name |Column Name\n\n.^|This content is vertically centered because the cell specifier includes the `+.^+` operator.\n|There isn't a vertical alignment operator on this cell specifier, so the cell falls back to the default vertical alignment.\nContent is aligned to the top of the cell by default.\n|===",
    );
    assert_eq!(
        body_alignments(&table),
        vec![vec![
            (HorizontalAlignment::Left, VerticalAlignment::Middle),
            (HorizontalAlignment::Left, VerticalAlignment::Top),
        ]]
    );
}

#[test]
fn apply_horizontal_and_vertical_alignment_operators_to_the_same_cell() {
    non_normative!(
        r#"
== Apply horizontal and vertical alignment operators to the same cell

"#
    );

    verifies!(
        r#"
A cell can have a vertical and horizontal alignment operator included in its cell specifier.
The <<horizontal-operators,horizontal operator>> always precedes the <<vertical-operators,vertical operator>>.

.Align cells horizontally and vertically
[source#ex-combine]
----
include::example$align-cell.adoc[tag=combine]
----

The table from <<ex-combine>> is rendered below.

.Result <<ex-combine>>
include::example$align-cell.adoc[tag=combine]
"#
    );

    // Expansion of `example$align-cell.adoc[tag=combine]`. Each specifier
    // applies both a horizontal and a vertical operator (the horizontal always
    // first): `^.>` (center, bottom), `>.^` (right, middle), `2.3+^.^` (center,
    // middle, after a span), and `3*.>` (bottom, after a duplication; the
    // horizontal alignment falls back to the column default). The cell with no
    // operators falls back to the default alignments (left, top). The `3*.>`
    // duplication clones its bottom-aligned content into three cells: the first
    // fills the row alongside the `2.3+` block span, and the next two each land
    // in a row of their own (alongside the columns the block span carries down).
    let table = parse_table(
        "|===\n|Column 1 |Column 2 |Column 3\n\n^.>|The specifier for this cell is `^.>`.\nThe content is centered horizontally and aligned to the bottom of the cell.\n|There aren't any alignment operators on this cell's specifier, so the cell falls back to the default alignments.\nThe default horizontal alignment is the left side of the cell.\nThe default vertical alignment is the top of the cell.\n>.^|The specifier for this cell is `>.^`.\nThe content is aligned to the right side of the cell and centered vertically.\n\n2.3+^.^|The specifier for this cell is `pass:[2.3+^.^]`.\nIt spans two columns and three rows.\n\nIts content is centered horizontally and vertically.\n3*.>|The specifier for this cell is `3*.>`.\nThe cell is duplicated in three consecutive rows in the same column.\nIt's content is aligned to the bottom of the cell.\n|===",
    );
    assert_eq!(
        body_alignments(&table),
        vec![
            vec![
                (HorizontalAlignment::Center, VerticalAlignment::Bottom),
                (HorizontalAlignment::Left, VerticalAlignment::Top),
                (HorizontalAlignment::Right, VerticalAlignment::Middle),
            ],
            vec![
                (HorizontalAlignment::Center, VerticalAlignment::Middle),
                (HorizontalAlignment::Left, VerticalAlignment::Bottom),
            ],
            vec![(HorizontalAlignment::Left, VerticalAlignment::Bottom)],
            vec![(HorizontalAlignment::Left, VerticalAlignment::Bottom)],
        ]
    );
}