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
use nom::{
    branch::alt,
    bytes::complete::tag,
    character::complete::{line_ending, newline, not_line_ending, space1, tab},
    combinator::{eof, map, opt, peek},
    multi::{many0, many1},
    sequence::{delimited, pair, preceded, terminated},
    IResult,
};

use crate::{util::ws, KconfigInput};

fn indentation_level(input: KconfigInput) -> IResult<KconfigInput, usize> {
    let (input, _) = many0(newline)(input)?;
    // TODO: something is wrong here with the indentation level calculation
    // println!("{:?}", input.chars().next().unwrap());
    map(peek(pair(many0(tab), many0(space1))), |(t, s)| {
        s.len() + t.len()
    })(input)
}

pub fn weirdo_help(input: KconfigInput) -> IResult<KconfigInput, KconfigInput> {
    // TODO linux v-3.2, in file /drivers/net/ethernet/stmicro/stmmac/Kconfig
    // TODO 3.4.110/drivers/net/ethernet/sfc/Kconfig
    map(
        delimited(
            ws(opt(many0(tag("-")))),
            ws(tag("help")),
            opt(many0(alt((tag("-"), space1)))),
        ),
        |d| d,
    )(input)
}

/// This parses a help text. The end of the help text is determined by the indentation level, this means it ends at the first line which has a smaller indentation than the first line of the help text.
///
/// # Example
/// ```
/// use nom_kconfig::{
///     assert_parsing_eq,
///     attribute::parse_help,
/// };
///
/// assert_parsing_eq!(parse_help, "help\n   hello world", Ok(("", "hello world".to_string())))
/// ```
pub fn parse_help(input: KconfigInput) -> IResult<KconfigInput, String> {
    let (input, _) = pair(
        alt((
            ws(tag("help")),
            // TODO linux v-3.2, in file /drivers/net/ethernet/stmicro/stmmac/Kconfig
            weirdo_help,
        )),
        preceded(many0(space1), newline),
    )(input)?;

    let (input, indent) = indentation_level(input)?;
    if indent == 0 {
        return Ok((input, "".to_string()));
    }
    // TODO see function indentation_level
    //let indent = count(space1::<KconfigInput, _>, indent);
    let indent = space1;

    map(
        many1(alt((
            map(newline, |_| ""),
            map(pair(indent, parse_line_help), |(_, line)| {
                line.fragment().to_owned()
            }),
        ))),
        |v| {
            v.into_iter()
                .map(|l| l.trim_end())
                .filter(|e| !e.is_empty())
                .collect::<Vec<&str>>()
                .join("\n")
        },
    )(input)
}

pub fn parse_line_help(input: KconfigInput) -> IResult<KconfigInput, KconfigInput> {
    terminated(not_line_ending, alt((line_ending, eof)))(input)
}