nom_kconfig/attribute/
help.rs1use nom::bytes::complete::take_while;
2use nom::multi::fold_many0;
3use nom::Parser;
4use nom::{
5 branch::alt,
6 bytes::complete::{tag, take},
7 character::complete::{line_ending, newline, not_line_ending, space1},
8 combinator::{eof, map, opt, peek},
9 multi::many0,
10 sequence::{delimited, pair, preceded},
11 IResult,
12};
13
14use crate::{util::ws, KconfigInput};
15
16pub fn weirdo_help(input: KconfigInput) -> IResult<KconfigInput, KconfigInput> {
17 map(
20 delimited(
21 ws(opt(many0(tag("-")))),
22 ws(tag("help")),
23 opt(many0(alt((tag("-"), space1)))),
24 ),
25 |d| d,
26 )
27 .parse(input)
28}
29
30pub fn parse_help(input: KconfigInput) -> IResult<KconfigInput, String> {
42 let (input, _) = pair(
44 alt((
45 ws(tag("help")),
46 weirdo_help,
48 )),
49 preceded(many0(space1), newline),
50 )
51 .parse(input)?;
52
53 let (input, text) = parse_help_text(input)?;
55 Ok((input, text))
56}
57
58fn parse_help_text(input: KconfigInput) -> IResult<KconfigInput, String> {
59 let (original, initial_indentation_len) = peek_indentation(input)?;
60 if initial_indentation_len == 0 {
61 return Ok((original, String::new()));
62 }
63
64 let (input, _) = take(initial_indentation_len)(original)?;
66 let (remaining, first_line) = parse_full_help_line(input)?;
67
68 let (remaining, mut help_text) = fold_many0(
70 |i| {
71 let (orig, indent_len) = peek_indentation(i)?;
72
73 if (indent_len != 0) && (indent_len < initial_indentation_len) {
74 return Err(nom::Err::Error(nom::error::Error::new(
75 orig,
76 nom::error::ErrorKind::Fail, )));
78 } else if indent_len == 0 {
79 parse_newline_only(orig)
81 } else {
82 let (remain, _) = take(initial_indentation_len)(orig)?;
84 parse_full_help_line(remain)
86 }
87 },
88 String::new,
89 |mut acc, line| {
90 acc.push_str(&line);
91 acc
92 },
93 )
94 .parse(remaining)?;
95
96 help_text.insert_str(0, &first_line);
97
98 Ok((remaining, help_text.trim().to_string()))
99}
100
101fn parse_line_help(input: KconfigInput) -> IResult<KconfigInput, (KconfigInput, KconfigInput)> {
102 pair(not_line_ending, alt((line_ending, eof))).parse(input)
103}
104
105fn parse_full_help_line(input: KconfigInput) -> IResult<KconfigInput, String> {
106 let (input, (raw_text, line_end)) = parse_line_help(input)?;
107 let mut parsed_line = raw_text.to_string();
108 parsed_line.push_str(line_end.fragment());
109 Ok((input, parsed_line))
110}
111
112fn parse_newline_only(input: KconfigInput) -> IResult<KconfigInput, String> {
113 let (input, newline) = newline(input)?;
114 Ok((input, newline.to_string()))
115}
116fn peek_til_newline(s: KconfigInput) -> IResult<KconfigInput, (KconfigInput, KconfigInput)> {
117 peek(parse_line_help).parse(s)
118}
119
120fn peek_indentation(s: KconfigInput) -> IResult<KconfigInput, usize> {
121 let (original, peeked) = peek_til_newline(s)?;
122 let (_, len) = indentation_level(peeked.0)?;
123 Ok((original, len))
124}
125
126fn indentation_level(input: KconfigInput) -> IResult<KconfigInput, usize> {
127 let (input, indent) = take_while(|c: char| c == ' ' || c == '\t')(input)?;
137 let len = indent.fragment().len();
138
139 Ok((input, (len)))
140}