fix: memory column aligned, closes #20

This commit is contained in:
Jack Wills
2023-01-18 02:06:05 +00:00
parent 97b89349dc
commit 51c580010a
2 changed files with 47 additions and 50 deletions
+23 -20
View File
@@ -55,7 +55,7 @@ fn generate_block<'a>(
.lock() .lock()
.update_heading_map(Region::Panel(panel), area); .update_heading_map(Region::Panel(panel), area);
let current_selected_panel = gui_state.lock().selected_panel; let current_selected_panel = gui_state.lock().selected_panel;
let title = match panel { let mut title = match panel {
SelectablePanel::Containers => { SelectablePanel::Containers => {
format!( format!(
"{} {}", "{} {}",
@@ -68,6 +68,9 @@ fn generate_block<'a>(
} }
SelectablePanel::Commands => String::new(), SelectablePanel::Commands => String::new(),
}; };
if !title.is_empty() {
title = format!(" {title} ");
}
let mut block = Block::default() let mut block = Block::default()
.borders(Borders::ALL) .borders(Borders::ALL)
.border_type(BorderType::Rounded) .border_type(BorderType::Rounded)
@@ -136,19 +139,21 @@ pub fn containers<B: Backend>(
let state_style = Style::default().fg(i.state.get_color()); let state_style = Style::default().fg(i.state.get_color());
let blue = Style::default().fg(Color::Blue); let blue = Style::default().fg(Color::Blue);
// let mems = format!(
// "{:>1} / {:>1}",
// i.mem_stats.back().unwrap_or(&ByteStats::default()),
// i.mem_limit
// );
let lines = Spans::from(vec![ let lines = Spans::from(vec![
Span::styled( Span::styled(
format!("{:<width$}", i.state.to_string(), width = widths.state.1.into()), format!(
"{:<width$}",
i.state.to_string(),
width = widths.state.1.into()
),
state_style, state_style,
), ),
Span::styled( Span::styled(
format!("{MARGIN}{:>width$}", i.status, width = &widths.status.1.into()), format!(
"{MARGIN}{:>width$}",
i.status,
width = &widths.status.1.into()
),
state_style, state_style,
), ),
Span::styled( Span::styled(
@@ -161,7 +166,13 @@ pub fn containers<B: Backend>(
state_style, state_style,
), ),
Span::styled( Span::styled(
format!("{MARGIN}{:>width_current$} / {:>width_limit$}", i.mem_stats.back().unwrap_or(&ByteStats::default()), i.mem_limit, width_current = &widths.mem.1.into(), width_limit = &widths.mem.2.into()), format!(
"{MARGIN}{:>width_current$} / {:>width_limit$}",
i.mem_stats.back().unwrap_or(&ByteStats::default()),
i.mem_limit,
width_current = &widths.mem.1.into(),
width_limit = &widths.mem.2.into()
),
state_style, state_style,
), ),
Span::styled( Span::styled(
@@ -226,22 +237,14 @@ pub fn logs<B: Backend>(
.alignment(Alignment::Center); .alignment(Alignment::Center);
f.render_widget(paragraph, area); f.render_widget(paragraph, area);
} else if let Some(index) = index { } else if let Some(index) = index {
let items = app_data.lock().containers.items[index] let items = List::new(app_data.lock().containers.items[index].logs.to_vec())
.logs
.items
.iter()
.enumerate()
.map(|i| i.1.clone())
.collect::<Vec<_>>();
let items = List::new(items)
.block(block) .block(block)
.highlight_symbol(ARROW) .highlight_symbol(ARROW)
.highlight_style(Style::default().add_modifier(Modifier::BOLD)); .highlight_style(Style::default().add_modifier(Modifier::BOLD));
f.render_stateful_widget( f.render_stateful_widget(
items, items,
area, area,
&mut app_data.lock().containers.items[index].logs.state, app_data.lock().containers.items[index].logs.state(),
); );
} else { } else {
let paragraph = Paragraph::new("no logs found") let paragraph = Paragraph::new("no logs found")
+22 -28
View File
@@ -6,7 +6,7 @@ use crossterm::{
}; };
use parking_lot::Mutex; use parking_lot::Mutex;
use std::{ use std::{
io, io::{self, Write},
sync::{atomic::Ordering, Arc}, sync::{atomic::Ordering, Arc},
}; };
use std::{sync::atomic::AtomicBool, time::Instant}; use std::{sync::atomic::AtomicBool, time::Instant};
@@ -31,11 +31,10 @@ use crate::{
/// Take control of the terminal in order to draw gui /// Take control of the terminal in order to draw gui
pub async fn create_ui( pub async fn create_ui(
app_data: Arc<Mutex<AppData>>, app_data: Arc<Mutex<AppData>>,
sender: Sender<InputMessages>,
is_running: Arc<AtomicBool>,
gui_state: Arc<Mutex<GuiState>>,
docker_sx: Sender<DockerMessage>, docker_sx: Sender<DockerMessage>,
// update_duration: Duration, gui_state: Arc<Mutex<GuiState>>,
is_running: Arc<AtomicBool>,
sender: Sender<InputMessages>,
) -> Result<()> { ) -> Result<()> {
enable_raw_mode()?; enable_raw_mode()?;
let mut stdout = io::stdout(); let mut stdout = io::stdout();
@@ -44,16 +43,14 @@ pub async fn create_ui(
let mut terminal = Terminal::new(backend)?; let mut terminal = Terminal::new(backend)?;
let res = run_app( let res = run_app(
&mut terminal,
app_data, app_data,
sender,
is_running,
gui_state,
docker_sx, docker_sx,
gui_state,
is_running,
sender,
&mut terminal,
) )
.await; .await;
terminal.clear()?;
disable_raw_mode()?; disable_raw_mode()?;
execute!( execute!(
terminal.backend_mut(), terminal.backend_mut(),
@@ -65,46 +62,43 @@ pub async fn create_ui(
if let Err(err) = res { if let Err(err) = res {
println!("{err}"); println!("{err}");
} }
std::io::stdout().flush().unwrap_or(());
Ok(()) Ok(())
} }
/// Run a loop to draw the gui /// Run a loop to draw the gui
async fn run_app<B: Backend + Send>( async fn run_app<B: Backend + Send>(
terminal: &mut Terminal<B>,
app_data: Arc<Mutex<AppData>>, app_data: Arc<Mutex<AppData>>,
sender: Sender<InputMessages>,
is_running: Arc<AtomicBool>,
gui_state: Arc<Mutex<GuiState>>,
docker_sx: Sender<DockerMessage>, docker_sx: Sender<DockerMessage>,
gui_state: Arc<Mutex<GuiState>>,
is_running: Arc<AtomicBool>,
sender: Sender<InputMessages>,
terminal: &mut Terminal<B>,
) -> Result<(), AppError> { ) -> Result<(), AppError> {
let update_duration = let update_duration =
std::time::Duration::from_millis(u64::from(app_data.lock().args.docker_interval)); std::time::Duration::from_millis(u64::from(app_data.lock().args.docker_interval));
let input_poll_rate = std::time::Duration::from_millis(75); let input_poll_rate = std::time::Duration::from_millis(75);
let status_dockerconnect = gui_state.lock().status_contains(&[Status::DockerConnect]); let status_dockerconnect = gui_state.lock().status_contains(&[Status::DockerConnect]);
let mut now = Instant::now();
if status_dockerconnect { if status_dockerconnect {
let mut seconds = 5; let mut seconds = 5;
loop { loop {
if seconds < 1 { if seconds < 1 {
is_running.store(false, Ordering::Relaxed);
break; break;
} }
if now.elapsed() >= std::time::Duration::from_secs(1) {
seconds -= 1;
now = Instant::now();
}
if terminal if terminal
.draw(|f| draw_blocks::error(f, AppError::DockerConnect, Some(seconds))) .draw(|f| draw_blocks::error(f, AppError::DockerConnect, Some(seconds)))
.is_err() .is_err()
{ {
return Err(AppError::Terminal); return Err(AppError::Terminal);
} }
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
seconds -= 1;
} }
} else { } else {
let mut now = Instant::now(); while is_running.load(Ordering::Relaxed) {
loop {
if terminal.draw(|f| ui(f, &app_data, &gui_state)).is_err() {
return Err(AppError::Terminal);
}
// TODO could only draw if in gui mode, that way all inputs & docker commands will run, and can just trace!("{event"}) all over the place
// refactor this into own function, so can be called without drawing to the terminal
if crossterm::event::poll(input_poll_rate).unwrap_or(false) { if crossterm::event::poll(input_poll_rate).unwrap_or(false) {
if let Ok(event) = event::read() { if let Ok(event) = event::read() {
if let Event::Key(key) = event { if let Event::Key(key) = event {
@@ -128,12 +122,12 @@ async fn run_app<B: Backend + Send>(
docker_sx.send(DockerMessage::Update).await.unwrap_or(()); docker_sx.send(DockerMessage::Update).await.unwrap_or(());
now = Instant::now(); now = Instant::now();
} }
if terminal.draw(|f| ui(f, &app_data, &gui_state)).is_err() {
if !is_running.load(Ordering::Relaxed) { return Err(AppError::Terminal);
break;
} }
} }
} }
terminal.clear().unwrap_or(());
Ok(()) Ok(())
} }