1use crate::parser::util::unescape;
16use crate::parser::util::{end, is_eol, is_ws, ws};
17use crate::parser::util::{is_printable_no_comma, is_printable_no_control, is_printable_no_pipe};
18use nom::branch::alt;
19use nom::bytes::streaming::{tag, take, take_until, take_while};
20use nom::character::{is_digit, streaming::line_ending as eol};
21use nom::combinator::{complete, map, map_res, opt};
22use nom::error::{make_error, ErrorKind};
23use nom::sequence::terminated;
24use nom::IResult;
25use std::borrow::Cow;
26use std::str;
27
28#[derive(Eq, PartialEq, Clone, Debug)]
29pub enum Item<'a> {
30 Comment(&'a str),
31
32 Definition { name: &'a str, aliases: Vec<&'a str>, description: &'a str },
33
34 True(&'a str),
35 Number(&'a str, i16),
36 String(&'a str, Cow<'a, [u8]>),
37 Disable(&'a str),
38}
39
40pub fn parse(input: &[u8]) -> IResult<&[u8], Item> {
41 alt((comment, definition, disable, entry))(input)
42}
43
44fn comment(input: &[u8]) -> IResult<&[u8], Item> {
45 let (input, _) = tag("#")(input)?;
46 let (input, content) = map_res(terminated(take_until("\n"), tag("\n")), str::from_utf8)(input)?;
47 let (input, _) = opt(complete(take_while(is_eol)))(input)?;
48
49 Ok((input, Item::Comment(content.trim())))
50}
51
52fn definition(input: &[u8]) -> IResult<&[u8], Item> {
53 let (input, name) =
54 map(take_while(is_printable_no_pipe), |n| unsafe { str::from_utf8_unchecked(n) })(input)?;
55
56 let (input, _) = tag("|")(input)?;
57
58 let (input, content) =
59 map(take_while(is_printable_no_comma), |n| unsafe { str::from_utf8_unchecked(n) })(input)?;
60
61 let (input, _) = tag(",")(input)?;
62
63 let (input, _) = take_while(is_ws)(input)?;
64
65 let (input, _) = eol(input)?;
66 let (input, _) = opt(complete(take_while(is_eol)))(input)?;
67
68 Ok((input, {
69 let mut aliases = content.split(|c| c == '|').map(|n| n.trim()).collect::<Vec<_>>();
70
71 Item::Definition { name, description: aliases.pop().unwrap(), aliases }
72 }))
73}
74
75fn disable(input: &[u8]) -> IResult<&[u8], Item> {
76 let (input, _) = ws(input)?;
77 let (input, _) = take_while(is_ws)(input)?;
78 let (input, _) = tag("@")(input)?;
79
80 let (input, name) =
81 map(take_while(is_printable_no_control), |n| unsafe { str::from_utf8_unchecked(n) })(
82 input,
83 )?;
84
85 let (input, _) = tag(",")(input)?;
86 let (input, _) = take_while(is_ws)(input)?;
87 let (input, _) = end(input)?;
88 let (input, _) = opt(complete(take_while(is_eol)))(input)?;
89
90 Ok((input, Item::Disable(name)))
91}
92
93fn entry(input: &[u8]) -> IResult<&[u8], Item> {
94 let (input, _) = ws(input)?;
95 let (input, _) = take_while(is_ws)(input)?;
96
97 let (input, name) =
98 map(take_while(is_printable_no_control), |n| unsafe { str::from_utf8_unchecked(n) })(
99 input,
100 )?;
101
102 let (input, c) = take(1_usize)(input)?;
103 let (input, value) = match c {
104 b"," => (input, Item::True(name)),
105
106 b"#" => {
107 let (input, value) =
108 map(take_while(is_digit), |n| unsafe { str::from_utf8_unchecked(n) })(input)?;
109
110 let (input, _) = tag(",")(input)?;
111
112 (input, Item::Number(name, value.parse().unwrap()))
113 }
114
115 b"=" => {
116 let (input, value) = take_while(is_printable_no_comma)(input)?;
117
118 let (input, _) = tag(",")(input)?;
119
120 (input, Item::String(name, unescape(value)))
121 }
122
123 _ => Err(nom::Err::Error(make_error(input, ErrorKind::Switch)))?,
124 };
125
126 let (input, _) = take_while(is_ws)(input)?;
127 let (input, _) = end(input)?;
128 let (input, _) = opt(complete(take_while(is_eol)))(input)?;
129
130 Ok((input, value))
131}
132
133#[cfg(test)]
134mod test {
135 use super::*;
136
137 use std::fs::File;
138 use std::io::Read;
139
140 #[test]
141 fn parsing() {
142 let mut file = File::open("tests/xterm.terminfo").unwrap();
143 let mut buffer = Vec::new();
144 file.read_to_end(&mut buffer).unwrap();
145
146 let mut input = &buffer[..];
147
148 while !input.is_empty() {
149 match parse(input) {
150 Ok((rest, _)) => input = rest,
151
152 Err(::nom::Err::Incomplete(_)) => panic!("incomplete"),
153
154 Err(err) => panic!("parsing: {:?}", err),
155 }
156 }
157 }
158}