From bed1d5b38b5466e57592aa23734311f6a025ae14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Fri, 3 Apr 2026 15:56:52 +0200 Subject: [PATCH] ensure .. and . parse as atoms --- logparse/src/parse.rs | 167 ++++++++++++++++++++++++++++++++++++++++-- src/tui/mod.rs | 24 ------ 2 files changed, 161 insertions(+), 30 deletions(-) diff --git a/logparse/src/parse.rs b/logparse/src/parse.rs index fd24dd9..3ea782d 100644 --- a/logparse/src/parse.rs +++ b/logparse/src/parse.rs @@ -130,12 +130,14 @@ impl<'a> FileName<'a> { } } - let (new_segment, ext_excluding_dot) = - if let Some((segment, ext_excluding_dot)) = rsplit(segment.segment.clone(), '.') { - (segment, Some(ext_excluding_dot)) - } else { - (segment.segment, None) - }; + let (new_segment, ext_excluding_dot) = if let Some((segment, ext_excluding_dot)) = + rsplit(segment.segment.clone(), '.') + && !ext_excluding_dot.is_empty() + { + (segment, Some(ext_excluding_dot)) + } else { + (segment.segment, None) + }; Self { leading_separator: segment.leading_separator, @@ -219,6 +221,13 @@ impl<'a> Path<'a> { } }) .verify(|i| { + // just ".." isn't valid + if i.segments.is_empty() + && (i.filename.segment == ".." || i.filename.segment == ".") + { + return false; + } + !i.segments.is_empty() || i.filename.ext_excluding_dot.is_some() || !matches!(i.filename.leading_separator, PathSep::None) @@ -418,6 +427,152 @@ mod tests { parse_input(input).unwrap() } + #[test] + fn parse_twodots() { + assert_debug_snapshot!(parse(r#".."#), @r#" + Segments { + segments: [ + Segment { + leading_space: Space( + "", + ), + token: Atom( + Text( + "..", + ), + ), + }, + ], + trailing_space: Space( + "", + ), + } + "#); + } + + #[test] + fn parse_dot() { + assert_debug_snapshot!(parse(r#"."#), @r#" + Segments { + segments: [ + Segment { + leading_space: Space( + "", + ), + token: Atom( + Text( + ".", + ), + ), + }, + ], + trailing_space: Space( + "", + ), + } + "#); + } + + #[test] + fn parse_parent() { + assert_debug_snapshot!(parse_path_only(r#"../foo.rs"#), @r#" + Path { + drive_excluding_colon: None, + segments: [ + PathSegment { + leading_separator: None, + segment: "..", + }, + ], + filename: FileName { + leading_separator: Slash, + segment: "foo", + ext_excluding_dot: Some( + "rs", + ), + location: None, + }, + } + "#); + } + + #[test] + fn parse_cwd() { + assert_debug_snapshot!(parse_path_only(r#"./foo.rs"#), @r#" + Path { + drive_excluding_colon: None, + segments: [ + PathSegment { + leading_separator: None, + segment: ".", + }, + ], + filename: FileName { + leading_separator: Slash, + segment: "foo", + ext_excluding_dot: Some( + "rs", + ), + location: None, + }, + } + "#); + } + + #[test] + fn parse_cwd_in_path() { + assert_debug_snapshot!(parse_path_only(r#"foo/./foo.rs"#), @r#" + Path { + drive_excluding_colon: None, + segments: [ + PathSegment { + leading_separator: None, + segment: "foo", + }, + PathSegment { + leading_separator: Slash, + segment: ".", + }, + ], + filename: FileName { + leading_separator: Slash, + segment: "foo", + ext_excluding_dot: Some( + "rs", + ), + location: None, + }, + } + "#); + } + + #[test] + fn parse_parent_in_path() { + assert_debug_snapshot!(parse_path_only(r#"foo/../foo.rs"#), @r#" + Path { + drive_excluding_colon: None, + segments: [ + PathSegment { + leading_separator: None, + segment: "foo", + }, + PathSegment { + leading_separator: Slash, + segment: "..", + }, + ], + filename: FileName { + leading_separator: Slash, + segment: "foo", + ext_excluding_dot: Some( + "rs", + ), + location: None, + }, + } + "#); + } + #[test] fn parse_path() { assert_debug_snapshot!(parse_path_only(r#"tests/ui/impl-trait/unsized_coercion.rs"#), @r#" diff --git a/src/tui/mod.rs b/src/tui/mod.rs index f0e8779..cd2eaf2 100644 --- a/src/tui/mod.rs +++ b/src/tui/mod.rs @@ -699,30 +699,6 @@ impl Widget for &mut App { FieldTree::new(lv, footer_focused) .styled_mut(&styles) .render(footer_area, buf); - - // let items = lv.footer_fields(); - // lv.last_fields_offset = footer_area.y as usize; - // lv.last_fields_height = items.len(); - // - // let width = 20; - // let builder = ListBuilder::new(|cx| { - // let Some((k, v)) = &items.get(cx.index) else { - // return (Paragraph::new(""), 1); - // }; - // - // let mut res = - // Paragraph::new(format!("{k:width$} {v}")).wrap(Wrap { trim: false }); - // - // if cx.is_selected { - // res = res.style(styles.highlighted); - // } - // - // let height = res.line_count(footer_area.width) as u16; - // (res, height) - // }); - // - // let list = ListView::new(builder, items.len()).style(styles.default); - // StatefulWidget::render(list, footer_area, buf, &mut lv.footer_list); } Tab::Empty => {} Tab::Help => {