outputting to the status line

This commit is contained in:
filipriec
2025-06-13 13:38:40 +02:00
parent 3c0af05a3c
commit f50887a326
7 changed files with 117 additions and 43 deletions

View File

@@ -20,16 +20,18 @@ pub fn render_status_line(
current_fps: f64,
app_state: &AppState,
) {
// --- START FIX ---
// Ensure debug_text is always a &str, which implements UnicodeWidthStr.
#[cfg(feature = "ui-debug")]
let debug_text = app_state.debug_info.as_str();
#[cfg(not(feature = "ui-debug"))]
let debug_text = "";
// --- END FIX ---
let debug_width = UnicodeWidthStr::width(debug_text);
let debug_separator_width = if !debug_text.is_empty() { UnicodeWidthStr::width(" | ") } else { 0 };
{
// If ui-debug is enabled, we only show the debug info.
let debug_text = &app_state.debug_info;
let debug_span = Span::styled(
debug_text.as_str(),
Style::default().fg(theme.accent).bg(theme.bg),
);
let paragraph = Paragraph::new(Line::from(vec![debug_span]));
f.render_widget(paragraph, area);
return; // Early return to skip the normal status line rendering.
}
let program_info = format!("multieko2 v{}", env!("CARGO_PKG_VERSION"));
let mode_text = if is_edit_mode { "[EDIT]" } else { "[READ-ONLY]" };
@@ -50,16 +52,25 @@ pub fn render_status_line(
let separator = " | ";
let separator_width = UnicodeWidthStr::width(separator);
let fixed_width_with_fps = mode_width + separator_width + separator_width +
program_info_width + separator_width + fps_width +
debug_separator_width + debug_width;
let fixed_width_with_fps = mode_width
+ separator_width
+ separator_width
+ program_info_width
+ separator_width
+ fps_width;
let show_fps = fixed_width_with_fps <= available_width;
let remaining_width_for_dir = available_width.saturating_sub(
mode_width + separator_width +
separator_width + program_info_width +
(if show_fps { separator_width + fps_width } else { 0 }) +
debug_separator_width + debug_width,
mode_width
+ separator_width
+ separator_width
+ program_info_width
+ (if show_fps {
separator_width + fps_width
} else {
0
}),
);
let dir_display_text_str = if UnicodeWidthStr::width(display_dir.as_str()) <= remaining_width_for_dir {
@@ -76,10 +87,11 @@ pub fn render_status_line(
}
};
let mut current_content_width = mode_width + separator_width +
UnicodeWidthStr::width(dir_display_text_str.as_str()) +
separator_width + program_info_width +
debug_separator_width + debug_width;
let mut current_content_width = mode_width
+ separator_width
+ UnicodeWidthStr::width(dir_display_text_str.as_str())
+ separator_width
+ program_info_width;
if show_fps {
current_content_width += separator_width + fps_width;
}
@@ -92,15 +104,13 @@ pub fn render_status_line(
Span::styled(program_info.as_str(), Style::default().fg(theme.secondary)),
];
if show_fps {
line_spans.push(Span::styled(separator, Style::default().fg(theme.border)));
line_spans.push(Span::styled(fps_text.as_str(), Style::default().fg(theme.secondary)));
}
#[cfg(feature = "ui-debug")]
{
line_spans.push(Span::styled(separator, Style::default().fg(theme.border)));
line_spans.push(Span::styled(debug_text, Style::default().fg(theme.accent)));
if show_fps {
line_spans
.push(Span::styled(separator, Style::default().fg(theme.border)));
line_spans.push(Span::styled(
fps_text.as_str(),
Style::default().fg(theme.secondary),
));
}
let padding_needed = available_width.saturating_sub(current_content_width);
@@ -111,8 +121,8 @@ pub fn render_status_line(
));
}
let paragraph = Paragraph::new(Line::from(line_spans))
.style(Style::default().bg(theme.bg));
let paragraph =
Paragraph::new(Line::from(line_spans)).style(Style::default().bg(theme.bg));
f.render_widget(paragraph, area);
}

View File

@@ -1,5 +1,7 @@
// client/src/main.rs
use client::run_ui;
#[cfg(feature = "ui-debug")]
use client::utils::debug_logger::UiDebugWriter;
use dotenvy::dotenv;
use anyhow::Result;
use tracing_subscriber;
@@ -7,8 +9,17 @@ use std::env;
#[tokio::main]
async fn main() -> Result<()> {
if env::var("ENABLE_TRACING").is_ok() {
tracing_subscriber::fmt::init();
#[cfg(feature = "ui-debug")]
{
// If ui-debug is on, set up our custom writer.
let writer = UiDebugWriter::new();
tracing_subscriber::fmt().with_writer(move || writer.clone()).init();
}
#[cfg(not(feature = "ui-debug"))]
{
if env::var("ENABLE_TRACING").is_ok() {
tracing_subscriber::fmt::init();
}
}
dotenv().ok();

View File

@@ -42,10 +42,9 @@ use crate::tui::{
use crate::ui::handlers::context::UiContext;
use crate::ui::handlers::rat_state::UiStateHandler;
use anyhow::Result;
use common::proto::multieko2::search::search_response::Hit; // Correctly imported
use common::proto::multieko2::search::search_response::Hit;
use crossterm::cursor::SetCursorStyle;
use crossterm::event::KeyCode;
use crossterm::event::{Event, KeyEvent};
use crossterm::event::{Event, KeyCode, KeyEvent};
use tokio::sync::mpsc;
use tokio::sync::mpsc::unbounded_channel;
use tracing::{info, error};
@@ -186,15 +185,18 @@ impl EventHandler {
let table_name = search_state.table_name.clone();
let sender = self.search_result_sender.clone();
info!("--- 1. Spawning search task for query: '{}' ---", query);
// We now move the grpc_client into the task, just like with login.
tokio::spawn(async move {
info!("--- 2. Background task started. ---");
match grpc_client.search_table(table_name, query).await {
Ok(response) => {
info!("Search successful. Received {} hits.", response.hits.len());
info!("--- 3a. gRPC call successful. Found {} hits. ---", response.hits.len());
let _ = sender.send(response.hits);
}
Err(e) => {
error!("gRPC search call failed: {}", e);
error!("--- 3b. gRPC call failed: {} ---", e);
let _ = sender.send(vec![]);
}
}

View File

@@ -24,6 +24,8 @@ use crate::ui::handlers::render::render_ui;
use crate::tui::functions::common::login::LoginResult;
use crate::tui::functions::common::register::RegisterResult;
use crate::ui::handlers::context::DialogPurpose;
#[cfg(feature = "ui-debug")]
use crate::utils::debug_logger::get_latest_debug_message;
use crate::tui::functions::common::login;
use crate::tui::functions::common::register;
use crate::utils::columns::filter_user_columns;
@@ -129,6 +131,7 @@ pub async fn run_ui() -> Result<()> {
match event_handler.search_result_receiver.try_recv() {
Ok(hits) => {
info!("--- 4. Main loop received message from channel. ---");
if let Some(search_state) = app_state.search_state.as_mut() {
search_state.results = hits;
search_state.is_loading = false;
@@ -517,10 +520,7 @@ pub async fn run_ui() -> Result<()> {
#[cfg(feature = "ui-debug")]
{
app_state.debug_info = format!(
"Redraw -> event: {}, needs_redraw: {}, pos_changed: {}",
event_processed, needs_redraw, position_changed
);
app_state.debug_info = get_latest_debug_message();
}
if event_processed || needs_redraw || position_changed {

View File

@@ -0,0 +1,46 @@
// client/src/utils/debug_logger.rs
use lazy_static::lazy_static;
use std::io;
use std::sync::{Arc, Mutex};
lazy_static! {
static ref UI_DEBUG_BUFFER: Arc<Mutex<String>> =
Arc::new(Mutex::new(String::from("Logger initialized...")));
}
#[derive(Clone)]
pub struct UiDebugWriter;
impl Default for UiDebugWriter {
fn default() -> Self {
Self::new()
}
}
impl UiDebugWriter {
pub fn new() -> Self {
Self
}
}
// Implement the io::Write trait for our writer.
// tracing_subscriber can use any type that implements `MakeWriter`.
// A simple way to do this is to have our writer implement `io::Write`.
impl io::Write for UiDebugWriter {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
let mut buffer = UI_DEBUG_BUFFER.lock().unwrap();
let message = String::from_utf8_lossy(buf);
// We just want the latest message, trimmed of whitespace.
*buffer = message.trim().to_string();
Ok(buf.len())
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
// A public function to safely get the latest message from anywhere in the app.
pub fn get_latest_debug_message() -> String {
UI_DEBUG_BUFFER.lock().unwrap().clone()
}

View File

@@ -1,4 +1,6 @@
// src/utils/mod.rs
pub mod columns;
pub mod debug_logger;
pub use columns::*;
pub use debug_logger::*;

View File

@@ -17,7 +17,8 @@ use common::proto::multieko2::search::{
pub use common::proto::multieko2::search::searcher_server::SearcherServer;
use common::proto::multieko2::search::searcher_server::Searcher;
use common::search::register_slovak_tokenizers;
use sqlx::{PgPool, Row}; // <-- Import PgPool and Row
use sqlx::{PgPool, Row};
use tracing::info;
// We need to hold the database pool in our service struct.
pub struct SearcherService {
@@ -263,6 +264,8 @@ impl Searcher for SearcherService {
})
.collect();
info!("--- SERVER: Successfully processed search. Returning {} hits. ---", hits.len());
let response = SearchResponse { hits };
Ok(Response::new(response))
}