ftml/parsing/collect/
text.rs

1/*
2 * parsing/collect/text.rs
3 *
4 * ftml - Library to parse Wikidot text
5 * Copyright (C) 2019-2025 Wikijump Team
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Affero General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Affero General Public License for more details.
16 *
17 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21use super::prelude::*;
22
23/// Generic function to consume all tokens into a single string slice.
24///
25/// This is a subset of the functionality provided by `collect()`,
26/// as it specifically gathers all the extracted tokens into a string slice,
27/// rather than considering them as special elements.
28#[inline]
29pub fn collect_text<'p, 'r, 't>(
30    parser: &'p mut Parser<'r, 't>,
31    rule: Rule,
32    close_conditions: &[ParseCondition],
33    invalid_conditions: &[ParseCondition],
34    error_kind: Option<ParseErrorKind>,
35) -> Result<&'t str, ParseError>
36where
37    'r: 't,
38{
39    collect_text_keep(
40        parser,
41        rule,
42        close_conditions,
43        invalid_conditions,
44        error_kind,
45    )
46    .map(|(slice, _)| slice)
47}
48
49/// Modified form of `collect_text()` that also returns the last token.
50///
51/// The last token terminating the collection is kept, and returned
52/// to the caller alongside the string slice.
53///
54/// Compare with `collect_consume_keep()`.
55pub fn collect_text_keep<'p, 'r, 't>(
56    parser: &'p mut Parser<'r, 't>,
57    rule: Rule,
58    close_conditions: &[ParseCondition],
59    invalid_conditions: &[ParseCondition],
60    error_kind: Option<ParseErrorKind>,
61) -> Result<(&'t str, &'r ExtractedToken<'t>), ParseError>
62where
63    'r: 't,
64{
65    // Log collect_text() call
66    debug!("Trying to consume tokens to merge into a single string");
67
68    let (start, mut end) = (parser.current(), None);
69
70    // Iterate and collect the tokens to merge.
71    //
72    // We know text is always paragraph safe, so we ignore that value.
73    let (last, errors, _) = collect(
74        parser,
75        rule,
76        close_conditions,
77        invalid_conditions,
78        error_kind,
79        |parser| {
80            trace!("Ingesting token in string span");
81
82            end = Some(parser.current());
83            ok!(true; ())
84        },
85    )?
86    .into();
87
88    assert!(
89        errors.is_empty(),
90        "Exceptions were returned during text token collection",
91    );
92
93    let slice = match (start, end) {
94        // We have a token span, use to get string slice
95        (start, Some(end)) => parser.full_text().slice(start, end),
96
97        // Empty list of tokens, resultant slice must be empty
98        (_, None) => "",
99    };
100
101    Ok((slice, last))
102}