Implement TUI search and mutation workflows
This commit is contained in:
@@ -170,6 +170,9 @@ fn render_content(frame: &mut Frame, app: &App, area: Rect) {
|
||||
))
|
||||
},
|
||||
),
|
||||
Mode::Browser if app.grep_view().is_some() => Paragraph::new(grep_lines(
|
||||
app.grep_view().expect("checked decrypted search results"),
|
||||
)),
|
||||
_ => Paragraph::new(main_text(app)),
|
||||
};
|
||||
frame.render_widget(
|
||||
@@ -252,10 +255,6 @@ fn main_text(app: &App) -> String {
|
||||
Mode::Dialog if app.discard_confirmation() => {
|
||||
"Discard all unsaved edits? Press y to discard, n or Esc to keep editing.".to_owned()
|
||||
}
|
||||
Mode::Dialog if app.command_confirmation_message().is_some() => app
|
||||
.command_confirmation_message()
|
||||
.unwrap_or_default()
|
||||
.to_owned(),
|
||||
Mode::Dialog => "Complete or cancel the active dialog.".to_owned(),
|
||||
Mode::Command => "Enter a command on the bottom line.".to_owned(),
|
||||
Mode::Help | Mode::Locked => String::new(),
|
||||
@@ -404,6 +403,37 @@ fn editor_lines(editor: &EntryEditor) -> Vec<Line<'_>> {
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn grep_lines(view: &crate::search::GrepView) -> Vec<Line<'_>> {
|
||||
if view.entries().is_empty() {
|
||||
return vec![Line::from("No decrypted entries matched.")];
|
||||
}
|
||||
let mut lines = Vec::new();
|
||||
for (index, entry) in view.entries().iter().enumerate() {
|
||||
let selected = view.selected_index() == Some(index);
|
||||
lines.push(Line::styled(
|
||||
format!("{} {}", if selected { ">" } else { " " }, entry.path()),
|
||||
if selected {
|
||||
Style::default().bg(Color::Blue).fg(Color::White)
|
||||
} else {
|
||||
Style::default()
|
||||
.fg(Color::Cyan)
|
||||
.add_modifier(Modifier::BOLD)
|
||||
},
|
||||
));
|
||||
for matched in entry.lines() {
|
||||
let contents = std::str::from_utf8(matched.contents().expose())
|
||||
.unwrap_or("[non-UTF-8 matched line]");
|
||||
let prefix = if view.includes_line_numbers() {
|
||||
format!("{}: ", matched.number())
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
lines.push(Line::raw(format!(" {prefix}{contents}")));
|
||||
}
|
||||
}
|
||||
lines
|
||||
}
|
||||
|
||||
fn mode_title(mode: Mode) -> &'static str {
|
||||
match mode {
|
||||
Mode::Browser => "Browser",
|
||||
@@ -437,6 +467,9 @@ fn context_line(app: &App) -> Paragraph<'static> {
|
||||
if app.mode() == Mode::Dialog && app.workflow().is_some() {
|
||||
return Paragraph::new("Tab/Shift-Tab focus Space toggle Ctrl-S submit Esc cancel");
|
||||
}
|
||||
if app.grep_view().is_some() {
|
||||
return Paragraph::new("j/k result Enter open entry Esc close decrypted results");
|
||||
}
|
||||
let text = context_actions(app.mode())
|
||||
.map(|spec| format!("{} {}", spec.bindings[0].display, spec.label))
|
||||
.collect::<Vec<_>>()
|
||||
@@ -448,9 +481,6 @@ fn prompt_line(app: &App) -> Paragraph<'static> {
|
||||
match app.mode() {
|
||||
Mode::Command => Paragraph::new(format!(":{}", app.command_line().display()))
|
||||
.style(Style::default().fg(Color::Yellow)),
|
||||
Mode::Dialog if app.command_confirmation_message().is_some() => {
|
||||
Paragraph::new("confirm> y / n / Esc").style(Style::default().fg(Color::Yellow))
|
||||
}
|
||||
Mode::Dialog if app.workflow().is_some() => {
|
||||
Paragraph::new("form> ").style(Style::default().fg(Color::Yellow))
|
||||
}
|
||||
@@ -589,8 +619,9 @@ mod tests {
|
||||
crossterm::event::KeyModifiers::NONE,
|
||||
);
|
||||
let confirmation = render(120, 24, &app);
|
||||
assert!(confirmation.contains("Confirm remove"));
|
||||
assert!(confirmation.contains("confirm> y / n / Esc"));
|
||||
assert!(confirmation.contains("Remove entry or folder"));
|
||||
assert!(confirmation.contains("Confirm permanent removal: no"));
|
||||
assert!(confirmation.contains("Ctrl-S submit"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user