1
1
use nom:: {
2
2
bytes:: complete:: { tag, take_until} ,
3
- character:: complete:: { newline, not_line_ending} ,
4
- combinator:: opt,
5
- multi:: many0,
3
+ character:: complete:: { anychar, char, newline, not_line_ending, none_of} ,
4
+ combinator:: { fail, opt} ,
5
+ multi:: { many0, many_till} ,
6
+ sequence:: tuple,
6
7
* ,
7
8
} ;
8
9
@@ -15,13 +16,18 @@ pub struct Todo {
15
16
pub text : String ,
16
17
}
17
18
18
- fn parse_todo < ' a > ( todo_tag : & ' a str , input : & ' a str ) -> IResult < & ' a str , Todo > {
19
+ fn parse_header < ' a > ( todo_tag : & ' a str , input : & ' a str ) -> IResult < & ' a str , ( ) > {
19
20
// remove everything prior to the tag
20
21
let ( input, _) = take_until ( todo_tag) ( input) ?;
21
-
22
+ // detect todo_tag
22
23
let ( input, _) = tag ( todo_tag) ( input) ?;
23
- let ( input, text) = not_line_ending ( input) ?;
24
+ Ok ( ( input, ( ) ) )
25
+ }
26
+
27
+ fn parse_todo < ' a > ( todo_tag : & ' a str , input : & ' a str ) -> IResult < & ' a str , Todo > {
28
+ let ( input, _) = parse_header ( todo_tag, input) ?;
24
29
30
+ let ( input, text) = not_line_ending ( input) ?;
25
31
// discard optional line ending
26
32
let ( input, _) = opt ( newline) ( input) ?;
27
33
@@ -34,6 +40,47 @@ fn parse_todo<'a>(todo_tag: &'a str, input: &'a str) -> IResult<&'a str, Todo> {
34
40
) )
35
41
}
36
42
43
+ fn parse_todo_multiline < ' a > ( todo_tag : & ' a str , input : & ' a str ) -> IResult < & ' a str , Todo > {
44
+ let ( input, _) = parse_header ( todo_tag, input) ?;
45
+
46
+ println ! ( "{:?}" , input) ;
47
+
48
+ //let parse_line = many_till(anychar::<T, E>, tuple((char('\\'), newline)));
49
+
50
+ let ( input, ( vector, _) ) = many_till (
51
+ many_till ( anychar, tuple ( ( char ( '\\' ) , newline) ) ) ,
52
+ many_till ( anychar, tuple ( ( none_of ( "\\ " ) , newline) ) ) ,
53
+ ) ( input) ?;
54
+
55
+ println ! ( "{:?}" , vector) ;
56
+
57
+ let result: String = vector. into_iter ( ) . map ( | ( line, _) | line. iter ( ) . collect :: < String > ( ) ) . collect ( ) ;
58
+
59
+ // for (v, _) in vector {
60
+ // let line:String = v.iter().collect();
61
+
62
+ // }
63
+
64
+ // let (input, text) = not_line_ending(input)?;
65
+
66
+ // match text.chars().last() {
67
+ // Some('\\') => todo!(),
68
+ // _ => fail::<&str, Todo, nom::error::Error<&str>>("")?,
69
+ // };
70
+
71
+ // discard optional line ending
72
+ // let (input, _) = opt(newline)(input)?;
73
+
74
+ Ok ( (
75
+ input,
76
+ Todo {
77
+ tag : todo_tag. to_owned ( ) ,
78
+ text : result,
79
+ } ,
80
+ ) )
81
+ }
82
+
83
+
37
84
fn parse_todos ( file_content : & str ) -> IResult < & str , Vec < Todo > > {
38
85
let line_parser = |file_content| parse_todo ( "TODO:" , file_content) ;
39
86
let ( input, todos) = many0 ( line_parser) ( file_content) ?;
@@ -49,9 +96,27 @@ pub fn parse_file(file_content: &str) -> Vec<Todo> {
49
96
50
97
#[ cfg( test) ]
51
98
mod test {
52
- use crate :: commands:: parser:: { parse_todo, parse_todos, Todo } ;
99
+ use crate :: commands:: parser:: { parse_todo, parse_todos, parse_todo_multiline , Todo } ;
53
100
54
101
#[ test]
102
+ fn multiline_todos ( ) {
103
+ let input =
104
+ "TODO: todo1 \\ n\
105
+ todo2\n \
106
+ line1";
107
+
108
+ assert_eq ! (
109
+ parse_todo_multiline( "TODO:" , input) ,
110
+ Ok ( (
111
+ "line1" ,
112
+ Todo {
113
+ tag: "TODO:" . to_owned( ) ,
114
+ text: " todo1 todo" . to_owned( )
115
+ } ,
116
+ ) )
117
+ ) ;
118
+ }
119
+
55
120
fn todos ( ) {
56
121
let input = "line 1\n \
57
122
TODO: todo1\n \
0 commit comments