The sideways keys the results had (h/l, arrows, 0 and $) now scroll a transfer's file name and a query too, each list on its own. The browse tree and the room list take Home/End, PgUp/PgDn and the vim jumps like the main lists, and a chat log, room or private, pages back through its history and holds its place while new messages arrive; what arrives meanwhile counts as unread until the reader returns to the end.
98 lines
3.1 KiB
Rust
98 lines
3.1 KiB
Rust
use super::name_scroll::{column_width, end_offset, scroll_text};
|
|
use crate::models::{SearchEntry, SearchStatus};
|
|
use crate::ui::{
|
|
HIGHLIGHT_SYMBOL, body_style, dimmed_style, header_style, pane_block,
|
|
pane_title, row_highlight_style, success_style, warning_style,
|
|
};
|
|
use ratatui::{
|
|
Frame,
|
|
layout::{Constraint, Rect},
|
|
widgets::{Cell, HighlightSpacing, Row, Table, TableState},
|
|
};
|
|
|
|
// The pane shares a row with two others, so the fixed columns are as
|
|
// narrow as their widest word: the query gets the rest.
|
|
const WIDTHS: [Constraint; 3] = [
|
|
Constraint::Length(6),
|
|
Constraint::Fill(1),
|
|
Constraint::Length(7),
|
|
];
|
|
|
|
/// Query is the second column.
|
|
const QUERY_COLUMN: usize = 1;
|
|
|
|
/// The offset that brings the end of a query into view.
|
|
#[must_use]
|
|
pub fn query_end_offset(query: &str, area: Rect) -> usize {
|
|
end_offset(query, area, &WIDTHS, QUERY_COLUMN)
|
|
}
|
|
|
|
pub fn render_searches_pane(
|
|
frame: &mut Frame,
|
|
area: Rect,
|
|
searches: &[SearchEntry],
|
|
table_state: &mut TableState,
|
|
focused: bool,
|
|
query_offset: usize,
|
|
) {
|
|
let header = Row::new(vec![
|
|
Cell::from("Status").style(header_style()),
|
|
Cell::from("Query").style(header_style()),
|
|
Cell::from("Results").style(header_style()),
|
|
])
|
|
.height(1);
|
|
|
|
let query_width = column_width(area, &WIDTHS, QUERY_COLUMN);
|
|
let rows: Vec<Row> = searches
|
|
.iter()
|
|
.map(|search| {
|
|
let status_cell = match &search.status {
|
|
SearchStatus::Active => {
|
|
Cell::from("Active").style(warning_style())
|
|
}
|
|
SearchStatus::Completed => {
|
|
Cell::from("Done").style(success_style())
|
|
}
|
|
};
|
|
|
|
// What this window has fetched, or what the session says it will
|
|
// find when it does. A search another window ran has a count long
|
|
// before this one has pulled the results across.
|
|
let results_count = if search.results.is_empty() {
|
|
search.known_files
|
|
} else {
|
|
search.results.len()
|
|
};
|
|
// Nothing yet from a search still out: the status column already
|
|
// says it is looking.
|
|
let results_text = if results_count == 0
|
|
&& search.status == SearchStatus::Active
|
|
{
|
|
"…".to_string()
|
|
} else {
|
|
format!("{results_count}")
|
|
};
|
|
|
|
Row::new(vec![
|
|
status_cell,
|
|
Cell::from(scroll_text(
|
|
&search.query,
|
|
query_offset,
|
|
query_width,
|
|
))
|
|
.style(body_style()),
|
|
Cell::from(results_text).style(dimmed_style()),
|
|
])
|
|
})
|
|
.collect();
|
|
|
|
let table = Table::new(rows, WIDTHS)
|
|
.header(header)
|
|
.row_highlight_style(row_highlight_style())
|
|
.highlight_symbol(HIGHLIGHT_SYMBOL)
|
|
.highlight_spacing(HighlightSpacing::Always)
|
|
.block(pane_block(focused).title(pane_title("1", "Searches", focused)));
|
|
|
|
frame.render_stateful_widget(table, area, table_state);
|
|
}
|