| 1228 | } |
| 1229 | |
| 1230 | fn parse_part_in_brackets(text: &Wtf8) -> Result<FormatPart, FormatParseError> { |
| 1231 | let mut chars = text.code_points().peekable(); |
| 1232 | |
| 1233 | let mut left = Wtf8Buf::new(); |
| 1234 | let mut right = Wtf8Buf::new(); |
| 1235 | |
| 1236 | let mut split = false; |
| 1237 | let mut selected = &mut left; |
| 1238 | let mut inside_brackets = false; |
| 1239 | |
| 1240 | while let Some(char) = chars.next() { |
| 1241 | if char == '[' { |
| 1242 | inside_brackets = true; |
| 1243 | |
| 1244 | selected.push(char); |
| 1245 | |
| 1246 | while let Some(next_char) = chars.next() { |
| 1247 | selected.push(next_char); |
| 1248 | |
| 1249 | if next_char == ']' { |
| 1250 | inside_brackets = false; |
| 1251 | break; |
| 1252 | } |
| 1253 | if chars.peek().is_none() { |
| 1254 | return Err(FormatParseError::MissingRightBracket); |
| 1255 | } |
| 1256 | } |
| 1257 | } else if char == ':' && !split && !inside_brackets { |
| 1258 | split = true; |
| 1259 | selected = &mut right; |
| 1260 | } else { |
| 1261 | selected.push(char); |
| 1262 | } |
| 1263 | } |
| 1264 | |
| 1265 | // before the comma is a keyword or arg index, after the comma is maybe a spec. |
| 1266 | let arg_part: &Wtf8 = &left; |
| 1267 | |
| 1268 | let format_spec = if split { right } else { Wtf8Buf::new() }; |
| 1269 | |
| 1270 | // left can still be the conversion (!r, !s, !a) |
| 1271 | let parts: Vec<&Wtf8> = arg_part.splitn(2, "!".as_ref()).collect(); |
| 1272 | // before the bang is a keyword or arg index, after the comma is maybe a conversion spec. |
| 1273 | let arg_part = parts[0]; |
| 1274 | |
| 1275 | let conversion_spec = parts |
| 1276 | .get(1) |
| 1277 | .map(|conversion| { |
| 1278 | // conversions are only every one character |
| 1279 | conversion |
| 1280 | .code_points() |
| 1281 | .exactly_one() |
| 1282 | .map_err(|_| FormatParseError::UnknownConversion) |
| 1283 | }) |
| 1284 | .transpose()?; |
| 1285 | |
| 1286 | Ok(FormatPart::Field { |
| 1287 | field_name: arg_part.to_owned(), |