Skip to content

Commit 32d603d

Browse files
committed
feat(tui): highlight search results
1 parent f3167c9 commit 32d603d

File tree

3 files changed

+59
-30
lines changed

3 files changed

+59
-30
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ bytesize = "1.3.0"
3535
sysinfo = { version = "0.31.2", default-features = false, features = ["user"] }
3636
webbrowser = "1.0.1"
3737
lddtree = "0.3.5"
38+
itertools = "0.13.0"
3839

3940
[dev-dependencies]
4041
pretty_assertions = "1.4.0"

src/tui/ui.rs

Lines changed: 57 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -553,12 +553,14 @@ pub fn render_static_analysis(state: &mut State, frame: &mut Frame, rect: Rect)
553553
Row::new(items.iter().enumerate().map(|(i, value)| {
554554
Cell::from(Line::from(
555555
if value.width() > max_row_width && i == items.len() - 1 {
556-
vec![
556+
let mut spans = highlight_search_result(
557557
value.chars().take(max_row_width).collect::<String>().into(),
558-
"…".fg(Color::Rgb(100, 100, 100)),
559-
]
558+
state,
559+
);
560+
spans.push("…".fg(Color::Rgb(100, 100, 100)));
561+
spans
560562
} else {
561-
vec![value.to_string().into()]
563+
highlight_search_result(value.to_string().into(), state)
562564
},
563565
))
564566
}))
@@ -676,24 +678,25 @@ pub fn render_strings(state: &mut State, frame: &mut Frame, rect: Rect) {
676678
frame.render_stateful_widget(
677679
Table::new(
678680
items.map(|items| {
679-
Row::new(vec![Cell::from(Line::from({
681+
Row::new(vec![Cell::from({
680682
let index = format!("{:>p$}", items[0], p = left_padding);
681683
let value = items[1].to_string();
682-
let mut line = vec![index.clone().cyan(), " ".into()];
684+
let mut spans = vec![index.clone().cyan(), " ".into()];
683685
if index.width() + value.width() > max_row_width {
684-
line.push(
686+
spans.extend(highlight_search_result(
685687
value
686688
.chars()
687689
.take(max_row_width.saturating_sub(index.width()))
688690
.collect::<String>()
689691
.into(),
690-
);
691-
line.push("…".fg(Color::Rgb(100, 100, 100)));
692+
state,
693+
));
694+
spans.push("…".fg(Color::Rgb(100, 100, 100)));
692695
} else {
693-
line.push(value.into());
696+
spans.extend(highlight_search_result(value.into(), state))
694697
}
695-
line
696-
}))])
698+
Line::from(spans)
699+
})])
697700
}),
698701
&[Constraint::Percentage(100)],
699702
)
@@ -728,7 +731,7 @@ pub fn render_strings(state: &mut State, frame: &mut Frame, rect: Rect) {
728731
)
729732
.title_bottom(get_input_line(state)),
730733
)
731-
.highlight_style(Style::default().add_modifier(Modifier::BOLD)),
734+
.highlight_style(Style::default().fg(Color::Green).bold()),
732735
rect,
733736
&mut list_state,
734737
);
@@ -856,26 +859,34 @@ pub fn render_dynamic_analysis(state: &mut State, frame: &mut Frame, rect: Rect)
856859
}
857860

858861
frame.render_widget(
859-
Paragraph::new(state.analyzer.system_calls.clone())
860-
.block(
861-
Block::bordered()
862-
.title(vec![
862+
Paragraph::new(
863+
state
864+
.analyzer
865+
.system_calls
866+
.clone()
867+
.into_iter()
868+
.map(|line| highlight_search_result(line, state).into())
869+
.collect::<Vec<Line>>(),
870+
)
871+
.block(
872+
Block::bordered()
873+
.title(vec![
874+
"|".fg(Color::Rgb(100, 100, 100)),
875+
"System Calls".white().bold(),
876+
"|".fg(Color::Rgb(100, 100, 100)),
877+
])
878+
.title_bottom(
879+
Line::from(vec![
863880
"|".fg(Color::Rgb(100, 100, 100)),
864-
"System Calls".white().bold(),
881+
"Total: ".into(),
882+
state.analyzer.system_calls.len().to_string().white().bold(),
865883
"|".fg(Color::Rgb(100, 100, 100)),
866884
])
867-
.title_bottom(
868-
Line::from(vec![
869-
"|".fg(Color::Rgb(100, 100, 100)),
870-
"Total: ".into(),
871-
state.analyzer.system_calls.len().to_string().white().bold(),
872-
"|".fg(Color::Rgb(100, 100, 100)),
873-
])
874-
.right_aligned(),
875-
)
876-
.title_bottom(get_input_line(state)),
877-
)
878-
.scroll((state.scroll_index as u16, 0)),
885+
.right_aligned(),
886+
)
887+
.title_bottom(get_input_line(state)),
888+
)
889+
.scroll((state.scroll_index as u16, 0)),
879890
rect,
880891
);
881892

@@ -925,3 +936,19 @@ fn get_input_line<'a>(state: &'a State) -> Line<'a> {
925936
Line::default()
926937
}
927938
}
939+
940+
/// Returns the line with the search result highlighted.
941+
fn highlight_search_result<'a>(line: Line<'a>, state: &'a State) -> Vec<Span<'a>> {
942+
let line_str = line.to_string();
943+
if line_str.contains(state.input.value()) && !state.input.value().is_empty() {
944+
let splits = line_str.split(state.input.value());
945+
let chunks = splits.into_iter().map(|c| Span::from(c.to_owned()));
946+
let pattern = Span::styled(
947+
state.input.value(),
948+
Style::new().bg(Color::Yellow).fg(Color::Black),
949+
);
950+
itertools::intersperse(chunks, pattern).collect::<Vec<Span>>()
951+
} else {
952+
line.spans.clone()
953+
}
954+
}

0 commit comments

Comments
 (0)