From 3ac7f77563f5da542a59a87afa07b61ae1c92001 Mon Sep 17 00:00:00 2001 From: Alessandro Bortolin Date: Thu, 26 Sep 2024 11:08:10 +0200 Subject: [PATCH] Migrate from deprecated tui to ratatui --- Cargo.lock | 170 ++++++++++++++++++++--- Cargo.toml | 2 +- src/tools/find_bad_case/curses_ui.rs | 41 +++--- task-maker-format/Cargo.toml | 4 +- task-maker-format/src/ioi/curses_ui.rs | 37 ++--- task-maker-format/src/terry/curses_ui.rs | 25 ++-- task-maker-format/src/ui/curses.rs | 47 +++---- task-maker-format/src/ui/mod.rs | 4 +- 8 files changed, 227 insertions(+), 103 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5b9cd00da..d4b5ed6ca 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,18 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if 1.0.0", + "once_cell", + "version_check", + "zerocopy", +] + [[package]] name = "aho-corasick" version = "1.1.3" @@ -26,6 +38,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "allocator-api2" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" + [[package]] name = "anstream" version = "0.6.15" @@ -245,6 +263,15 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53" +[[package]] +name = "castaway" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0abae9be0aaf9ea96a3b1b8b1b55c602ca751eba1b1500220cea4ecbafe7c0d5" +dependencies = [ + "rustversion", +] + [[package]] name = "cc" version = "1.1.21" @@ -364,6 +391,20 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "compact_str" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6050c3a16ddab2e412160b31f2c871015704239bca62f72f6e5f0be631d3f644" +dependencies = [ + "castaway", + "cfg-if 1.0.0", + "itoa", + "rustversion", + "ryu", + "static_assertions", +] + [[package]] name = "console" version = "0.15.8" @@ -667,6 +708,10 @@ name = "hashbrown" version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "ahash", + "allocator-api2", +] [[package]] name = "heck" @@ -736,6 +781,16 @@ dependencies = [ "generic-array", ] +[[package]] +name = "instability" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b23a0c8dfe501baac4adf6ebbfa6eddf8f0c07f56b058cc1288017e32397846c" +dependencies = [ + "quote 1.0.37", + "syn 2.0.77", +] + [[package]] name = "instant" version = "0.1.13" @@ -819,6 +874,17 @@ version = "0.2.159" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" +[[package]] +name = "libredox" +version = "0.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3af92c55d7d839293953fcd0fda5ecfe93297cfde6ffbdec13b41d99c0ba6607" +dependencies = [ + "bitflags 2.6.0", + "libc", + "redox_syscall 0.4.1", +] + [[package]] name = "libredox" version = "0.1.3" @@ -841,6 +907,15 @@ version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +[[package]] +name = "lru" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37ee39891760e7d94734f6f63fedc29a2e4a152f836120753a72503f09fcf904" +dependencies = [ + "hashbrown", +] + [[package]] name = "matches" version = "0.1.10" @@ -1198,11 +1273,32 @@ dependencies = [ "getrandom", ] +[[package]] +name = "ratatui" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdef7f9be5c0122f890d58bdf4d964349ba6a6161f705907526d891efabba57d" +dependencies = [ + "bitflags 2.6.0", + "cassowary", + "compact_str", + "instability", + "itertools 0.13.0", + "lru", + "paste", + "strum", + "strum_macros", + "termion", + "unicode-segmentation", + "unicode-truncate", + "unicode-width", +] + [[package]] name = "redox_syscall" -version = "0.2.16" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" dependencies = [ "bitflags 1.3.2", ] @@ -1229,7 +1325,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ "getrandom", - "libredox", + "libredox 0.1.3", "thiserror", ] @@ -1290,6 +1386,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "rustversion" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" + [[package]] name = "ryu" version = "1.0.18" @@ -1426,12 +1528,40 @@ dependencies = [ "num", ] +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "strsim" version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" +[[package]] +name = "strum" +version = "0.26.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" +dependencies = [ + "heck", + "proc-macro2 1.0.86", + "quote 1.0.37", + "rustversion", + "syn 2.0.77", +] + [[package]] name = "supports-color" version = "2.1.0" @@ -1592,6 +1722,7 @@ dependencies = [ "pest", "pest_derive", "pretty_assertions", + "ratatui", "regex", "serde", "serde_json", @@ -1606,7 +1737,6 @@ dependencies = [ "tempfile", "termcolor", "termion", - "tui", "typescript-definitions", "unic", "wildmatch", @@ -1647,6 +1777,7 @@ dependencies = [ "lazy_static", "log", "num_cpus", + "ratatui", "regex", "rlimit", "scopeguard", @@ -1660,7 +1791,6 @@ dependencies = [ "task-maker-lang", "task-maker-store", "tempfile", - "tui", "typescript-definitions", "url", "walkdir", @@ -1707,13 +1837,13 @@ dependencies = [ [[package]] name = "termion" -version = "1.5.6" +version = "4.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "077185e2eac69c3f8379a4298e1e07cd36beb962290d4a51199acf0fdc10607e" +checksum = "1ccce68e518d1173e80876edd54760b60b792750d0cab6444a79101c6ea03848" dependencies = [ "libc", + "libredox 0.0.2", "numtoa", - "redox_syscall 0.2.16", "redox_termios", ] @@ -1761,19 +1891,6 @@ dependencies = [ "serde", ] -[[package]] -name = "tui" -version = "0.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccdd26cbd674007e649a272da4475fb666d3aa0ad0531da7136db6fab0e5bad1" -dependencies = [ - "bitflags 1.3.2", - "cassowary", - "termion", - "unicode-segmentation", - "unicode-width", -] - [[package]] name = "typenum" version = "1.17.0" @@ -2144,6 +2261,17 @@ version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" +[[package]] +name = "unicode-truncate" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3644627a5af5fa321c95b9b235a72fd24cd29c648c2c379431e6628655627bf" +dependencies = [ + "itertools 0.13.0", + "unicode-segmentation", + "unicode-width", +] + [[package]] name = "unicode-width" version = "0.1.14" diff --git a/Cargo.toml b/Cargo.toml index f03c7f19f..0144f26ab 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -86,7 +86,7 @@ rlimit = "0.10" # Geenrating random numbers (the seed in find-bad-case tool) fastrand = "2.0" # Curses UI -tui = { version = "0.19", default-features = false, features = ["termion"] } +ratatui = { version = "0.28", default-features = false, features = ["termion"] } # Typescript definition generation typescript-definitions = { git = "https://github.com/onelson/typescript-definitions", branch = "no-debug-attrs"} diff --git a/src/tools/find_bad_case/curses_ui.rs b/src/tools/find_bad_case/curses_ui.rs index 420aed9a4..b03228574 100644 --- a/src/tools/find_bad_case/curses_ui.rs +++ b/src/tools/find_bad_case/curses_ui.rs @@ -1,25 +1,24 @@ use itertools::Itertools; -use tui::layout::{Constraint, Direction, Layout, Rect}; -use tui::text::{Span, Spans}; -use tui::widgets::{Paragraph, Wrap}; +use ratatui::layout::{Constraint, Direction, Layout, Rect}; +use ratatui::text::{Line, Span}; +use ratatui::widgets::{Paragraph, Wrap}; +use ratatui::Frame; use task_maker_format::ui::curses::{BLUE, BOLD, GREEN, RED}; -use task_maker_format::ui::{ - inner_block, render_block, render_server_status, CursesDrawer, FrameType, -}; +use task_maker_format::ui::{inner_block, render_block, render_server_status, CursesDrawer}; use crate::tools::find_bad_case::state::{SharedUIState, TestcaseStatus, UIState}; pub struct CursesUI; impl CursesDrawer for CursesUI { - fn draw(state: &UIState, frame: &mut FrameType, loading: char, frame_index: usize) { + fn draw(state: &UIState, frame: &mut Frame, loading: char, frame_index: usize) { CursesUI::draw_frame(state, frame, loading, frame_index); } } impl CursesUI { - fn draw_frame(state: &UIState, f: &mut FrameType, loading: char, frame_index: usize) { + fn draw_frame(state: &UIState, f: &mut Frame, loading: char, frame_index: usize) { let header_len = 10; // Number of lines of the header. let workers_len = state .executor_status @@ -38,7 +37,7 @@ impl CursesUI { ] .as_ref(), ) - .split(f.size()); + .split(f.area()); let shared = state.shared.read().unwrap(); Self::render_header(state, &shared, f, chunks[0]); @@ -52,7 +51,7 @@ impl CursesUI { ); } - fn render_header(state: &UIState, shared: &SharedUIState, f: &mut FrameType, rect: Rect) { + fn render_header(state: &UIState, shared: &SharedUIState, f: &mut Frame, rect: Rect) { let errors = state .batches .iter() @@ -61,32 +60,32 @@ impl CursesUI { .count(); let text = vec![ - Spans(vec![ + Line::from(vec![ Span::styled("Solution: ", *BOLD), Span::raw(state.solution.to_string_lossy().to_string()), ]), - Spans(vec![ + Line::from(vec![ Span::styled("Generator args: ", *BOLD), Span::raw(state.generator_args.iter().join(" ")), ]), - Spans(vec![ + Line::from(vec![ Span::styled("Batch size: ", *BOLD), Span::raw(state.batch_size.to_string()), ]), - Spans(vec![ + Line::from(vec![ Span::styled("Batch index: ", *BOLD), Span::raw(shared.batch_index.to_string()), ]), - Spans(vec![Span::styled("Progress:", *BLUE)]), - Spans(vec![ + Line::from(vec![Span::styled("Progress:", *BLUE)]), + Line::from(vec![ Span::styled(" Generated: ", *BOLD), Span::raw(state.progress.inputs_generated.to_string()), ]), - Spans(vec![ + Line::from(vec![ Span::styled(" Solved: ", *BOLD), Span::raw(state.progress.inputs_solved.to_string()), ]), - Spans(vec![ + Line::from(vec![ Span::styled(" Average gen: ", *BOLD), Span::raw(format!( "{:.3}s\n", @@ -94,14 +93,14 @@ impl CursesUI { / (state.progress.inputs_generated.max(1) as f64) )), ]), - Spans(vec![ + Line::from(vec![ Span::styled(" Average sol: ", *BOLD), Span::raw(format!( "{:.3}s", state.progress.solution_time_sum / (state.progress.inputs_solved.max(1) as f64) )), ]), - Spans(vec![ + Line::from(vec![ Span::styled(" Errors: ", *BOLD), Span::raw(errors.to_string()), ]), @@ -111,7 +110,7 @@ impl CursesUI { f.render_widget(paragraph, rect); } - fn render_generation_status(state: &UIState, f: &mut FrameType, rect: Rect) { + fn render_generation_status(state: &UIState, f: &mut Frame, rect: Rect) { let mut text = vec![]; for i in 0..state.batches.len().min(10) { let mut line = Vec::new(); diff --git a/task-maker-format/Cargo.toml b/task-maker-format/Cargo.toml index 5ebbceec8..618c54512 100644 --- a/task-maker-format/Cargo.toml +++ b/task-maker-format/Cargo.toml @@ -30,8 +30,8 @@ glob = "0.3" pest = "2.1" pest_derive = "2.1" # Curses UI -tui = { version = "0.19", default-features = false, features = ["termion"] } -termion = "1.5" +ratatui = { version = "0.28", default-features = false, features = ["termion"] } +termion = "4" # Global constants lazy_static = "1.3" # Checking equalness between floats diff --git a/task-maker-format/src/ioi/curses_ui.rs b/task-maker-format/src/ioi/curses_ui.rs index b0369e6ce..6f8c60986 100644 --- a/task-maker-format/src/ioi/curses_ui.rs +++ b/task-maker-format/src/ioi/curses_ui.rs @@ -1,10 +1,11 @@ use std::path::Path; use itertools::Itertools; -use tui::layout::{Constraint, Direction, Layout, Rect}; -use tui::style::{Color, Modifier, Style}; -use tui::text::{Span, Spans}; -use tui::widgets::{Block, Borders, Paragraph}; +use ratatui::layout::{Constraint, Direction, Layout, Rect}; +use ratatui::style::{Color, Modifier, Style}; +use ratatui::text::{Line, Span}; +use ratatui::widgets::{Block, Borders, Paragraph}; +use ratatui::Frame; use task_maker_dag::ExecutionStatus; @@ -15,7 +16,7 @@ use crate::ioi::{ }; use crate::ui::curses::{ compilation_status_text, draw_compilations, inner_block, render_block, render_server_status, - CursesDrawer, CursesUI as GenericCursesUI, FrameType, GREEN, ORANGE, RED, YELLOW, + CursesDrawer, CursesUI as GenericCursesUI, GREEN, ORANGE, RED, YELLOW, }; use crate::ui::UIExecutionStatus; use crate::ScoreStatus; @@ -27,21 +28,21 @@ pub(crate) type CursesUI = GenericCursesUI; pub(crate) struct Drawer; impl CursesDrawer for Drawer { - fn draw(state: &UIState, frame: &mut FrameType, loading: char, frame_index: usize) { + fn draw(state: &UIState, frame: &mut Frame, loading: char, frame_index: usize) { draw_frame(state, frame, loading, frame_index); } } /// Draw a frame of interface to the provided `Frame`. -fn draw_frame(state: &UIState, f: &mut FrameType, loading: char, frame_index: usize) { - let size = f.size(); +fn draw_frame(state: &UIState, f: &mut Frame, loading: char, frame_index: usize) { + let size = f.area(); if size.width < 16 || size.height < 16 { let error = Span::styled("Too small", Style::default().add_modifier(Modifier::BOLD)); let paragraph = Paragraph::new(error); f.render_widget(paragraph, size); return; } - let header: Spans = vec![ + let header: Line = vec![ Span::styled( state.task.title.clone(), Style::default().add_modifier(Modifier::BOLD), @@ -80,7 +81,7 @@ fn draw_frame(state: &UIState, f: &mut FrameType, loading: char, frame_index: us .map(|s| s.connected_workers.len()) .unwrap_or(0) as u16 + 2; - let total_height = f.size().height; + let total_height = f.area().height; // fixed size section heights let top_height = header_len + compilations_len + booklet_len + generations_len; // if the sections don't just fit, reduce the size of the workers until they fit but @@ -104,7 +105,7 @@ fn draw_frame(state: &UIState, f: &mut FrameType, loading: char, frame_index: us ] .as_ref(), ) - .split(f.size()); + .split(f.area()); let paragraph = Paragraph::new(header).block(Block::default().borders(Borders::NONE)); f.render_widget(paragraph, chunks[0]); if compilations_len > 0 { @@ -141,14 +142,14 @@ fn draw_frame(state: &UIState, f: &mut FrameType, loading: char, frame_index: us } /// Draw the content of the booklet box. -fn draw_booklets(frame: &mut FrameType, rect: Rect, state: &UIState, loading: char) { - let text: Vec = state +fn draw_booklets(frame: &mut Frame, rect: Rect, state: &UIState, loading: char) { + let text: Vec = state .booklets .keys() .sorted() .flat_map(|name| { let booklet = &state.booklets[name]; - let mut text: Vec = vec![vec![ + let mut text: Vec = vec![vec![ Span::raw(format!("{:<20} ", name)), ui_execution_status_text(&booklet.status, loading), ] @@ -185,7 +186,7 @@ fn ui_execution_status_text(status: &UIExecutionStatus, loading: char) -> Span { } /// Draw the content of the generation box. -fn draw_generations(frame: &mut FrameType, rect: Rect, state: &UIState, loading: char) { +fn draw_generations(frame: &mut Frame, rect: Rect, state: &UIState, loading: char) { let text: Vec = state .generations .iter() @@ -203,7 +204,7 @@ fn draw_generations(frame: &mut FrameType, rect: Rect, state: &UIState, loading: res }) .collect(); - let paragraph = Paragraph::new(Spans(text)); + let paragraph = Paragraph::new(Line::from(text)); frame.render_widget(paragraph, rect); } @@ -223,7 +224,7 @@ fn generation_status_text(status: &TestcaseGenerationStatus, loading: char) -> S } /// Draw the content of the evaluation box. -fn draw_evaluations(frame: &mut FrameType, rect: Rect, state: &UIState, loading: char) { +fn draw_evaluations(frame: &mut Frame, rect: Rect, state: &UIState, loading: char) { let max_len = state .evaluations .keys() @@ -231,7 +232,7 @@ fn draw_evaluations(frame: &mut FrameType, rect: Rect, state: &UIState, loading: .max() .unwrap_or(0) + 4; - let text: Vec = state + let text: Vec = state .evaluations .keys() .sorted() diff --git a/task-maker-format/src/terry/curses_ui.rs b/task-maker-format/src/terry/curses_ui.rs index 2f7b8b564..c0de237f5 100644 --- a/task-maker-format/src/terry/curses_ui.rs +++ b/task-maker-format/src/terry/curses_ui.rs @@ -1,15 +1,16 @@ use itertools::Itertools; -use tui::layout::{Constraint, Direction, Layout, Rect}; -use tui::style::{Modifier, Style}; -use tui::text::{Span, Spans}; -use tui::widgets::{Block, Borders, Paragraph}; +use ratatui::layout::{Constraint, Direction, Layout, Rect}; +use ratatui::style::{Modifier, Style}; +use ratatui::text::{Line, Span}; +use ratatui::widgets::{Block, Borders, Paragraph}; +use ratatui::Frame; use crate::terry::finish_ui::FinishUI; use crate::terry::ui_state::{SolutionState, SolutionStatus, UIState}; use crate::terry::{CaseStatus, SolutionOutcome}; use crate::ui::curses::{ compilation_status_text, draw_compilations, inner_block, render_block, render_server_status, - CursesDrawer, CursesUI as GenericCursesUI, FrameType, GREEN, RED, YELLOW, + CursesDrawer, CursesUI as GenericCursesUI, GREEN, RED, YELLOW, }; use crate::ui::FinishUIUtils; @@ -20,14 +21,14 @@ pub(crate) type CursesUI = GenericCursesUI; pub(crate) struct Drawer; impl CursesDrawer for Drawer { - fn draw(state: &UIState, frame: &mut FrameType, loading: char, frame_index: usize) { + fn draw(state: &UIState, frame: &mut Frame, loading: char, frame_index: usize) { draw_frame(state, frame, loading, frame_index); } } /// Draw a frame of interface to the provided `Frame`. -fn draw_frame(state: &UIState, f: &mut FrameType, loading: char, frame_index: usize) { - let header: Spans = vec![ +fn draw_frame(state: &UIState, f: &mut Frame, loading: char, frame_index: usize) { + let header: Line = vec![ Span::styled( state.task.description.clone(), Style::default().add_modifier(Modifier::BOLD), @@ -55,7 +56,7 @@ fn draw_frame(state: &UIState, f: &mut FrameType, loading: char, frame_index: us .map(|s| s.connected_workers.len()) .unwrap_or(0) as u16 + 2; - let total_height = f.size().height; + let total_height = f.area().height; // fixed size section heights let top_height = header_len + compilations_len; // if the sections don't just fit, reduce the size of the workers until they fit but @@ -77,7 +78,7 @@ fn draw_frame(state: &UIState, f: &mut FrameType, loading: char, frame_index: us ] .as_ref(), ) - .split(f.size()); + .split(f.area()); let paragraph = Paragraph::new(header).block(Block::default().borders(Borders::NONE)); f.render_widget(paragraph, chunks[0]); if compilations_len > 0 { @@ -104,9 +105,9 @@ fn draw_frame(state: &UIState, f: &mut FrameType, loading: char, frame_index: us } /// Draw the evaluations of the solutions. -fn draw_evaluations(frame: &mut FrameType, rect: Rect, state: &UIState, loading: char) { +fn draw_evaluations(frame: &mut Frame, rect: Rect, state: &UIState, loading: char) { let max_len = FinishUIUtils::get_max_len(&state.solutions); - let text: Vec = state + let text: Vec = state .solutions .keys() .sorted() diff --git a/task-maker-format/src/ui/curses.rs b/task-maker-format/src/ui/curses.rs index 0a0bfcb87..a0a7cb2a5 100644 --- a/task-maker-format/src/ui/curses.rs +++ b/task-maker-format/src/ui/curses.rs @@ -8,20 +8,20 @@ use std::sync::{Arc, RwLock}; use std::thread::JoinHandle; use std::time::SystemTime; -use anyhow::Error; +use anyhow::{Context, Error}; use itertools::Itertools; use nix::sys::signal::{self, Signal}; use nix::unistd::Pid; +use ratatui::backend::TermionBackend; +use ratatui::layout::Rect; +use ratatui::style::{Color, Modifier, Style}; +use ratatui::text::{Line, Span}; +use ratatui::widgets::{Block, Borders, Paragraph}; +use ratatui::{Frame, Terminal}; use termion::event::{Event, Key}; use termion::input::{MouseTerminal, TermRead}; -use termion::raw::{IntoRawMode, RawTerminal}; -use termion::screen::AlternateScreen; -use tui::backend::TermionBackend; -use tui::layout::Rect; -use tui::style::{Color, Modifier, Style}; -use tui::text::{Span, Spans}; -use tui::widgets::{Block, Borders, Paragraph}; -use tui::{Frame, Terminal}; +use termion::raw::IntoRawMode; +use termion::screen::IntoAlternateScreen; use task_maker_exec::{ExecutorStatus, ExecutorWorkerStatus}; @@ -32,10 +32,6 @@ pub(crate) const FPS: u64 = 30; /// After how many seconds rotate the list of workers if they don't fit on the screen. pub(crate) const ROTATION_DELAY: u64 = 1; -/// The type of the terminal with its backend. -pub type FrameType<'a> = - Frame<'a, TermionBackend>>>>; - macro_rules! define_color_inner { ($color:expr,) => { $color @@ -101,7 +97,7 @@ where pub trait CursesDrawer { /// Draw a frame of the UI using the provided state, onto the frame, using the loading /// character. Frame index is a counter of the number of frames encountered so far. - fn draw(state: &State, frame: &mut FrameType, loading: char, frame_index: usize); + fn draw(state: &State, frame: &mut Frame, loading: char, frame_index: usize); } impl CursesUI @@ -133,8 +129,9 @@ where stop: Arc, ) -> Result, Error> { let stdout = io::stdout().into_raw_mode()?; - let stdout = MouseTerminal::from(stdout); - let stdout = AlternateScreen::from(stdout); + let stdout = MouseTerminal::from(stdout) + .into_alternate_screen() + .context("Failed to enter alternate screen mode, the terminal may not support it")?; let backend = TermionBackend::new(stdout); let mut terminal = Terminal::new(backend)?; terminal.hide_cursor()?; @@ -220,7 +217,7 @@ pub fn inner_block(rect: Rect) -> Rect { /// Draw the compilation block. pub(crate) fn draw_compilations<'a, I>( - frame: &mut FrameType, + frame: &mut Frame, rect: Rect, compilations: I, loading: char, @@ -234,7 +231,7 @@ pub(crate) fn draw_compilations<'a, I>( .max() .unwrap_or(0) + 4; - let text: Vec = compilations + let text: Vec = compilations .iter() .sorted_by_key(|(k, _)| *k) .map(|(file, status)| { @@ -267,7 +264,7 @@ pub(crate) fn compilation_status_text(status: &CompilationStatus, loading: char) } /// Render a block with the specified title. -pub fn render_block>(frame: &mut FrameType, rect: Rect, title: S) { +pub fn render_block>(frame: &mut Frame, rect: Rect, title: S) { let block = Block::default() .title(Span::styled(title.as_ref(), *BLUE)) .borders(Borders::ALL); @@ -276,7 +273,7 @@ pub fn render_block>(frame: &mut FrameType, rect: Rect, title: S) /// Draw the server status block. pub fn render_server_status( - frame: &mut FrameType, + frame: &mut Frame, rect: Rect, status: Option<&ExecutorStatus>, loading: char, @@ -305,7 +302,7 @@ pub fn render_server_status( /// Draw the summary of the server status on the border of the block. fn draw_server_status_summary( - frame: &mut FrameType, + frame: &mut Frame, rect: Rect, status: Option<&ExecutorStatus>, ) { @@ -314,7 +311,7 @@ fn draw_server_status_summary( } else { return; }; - let paragraph = Paragraph::new(Spans(vec![ + let paragraph = Paragraph::new(Line::from(vec![ Span::styled(" Ready ", Style::default().add_modifier(Modifier::BOLD)), Span::raw(format!("{} ─", status.ready_execs)), Span::styled(" Waiting ", Style::default().add_modifier(Modifier::BOLD)), @@ -326,7 +323,7 @@ fn draw_server_status_summary( /// Draw the content of the server status box, splitting the workers in 2 groups if they don't fit, /// and rotating them if they still don't fit. fn draw_server_status( - frame: &mut FrameType, + frame: &mut Frame, rect: Rect, status: Option<&ExecutorStatus>, loading: char, @@ -377,7 +374,7 @@ fn draw_server_status( /// Draw a chunk of workers in the specified rectangle. fn draw_workers_chunk( - frame: &mut FrameType, + frame: &mut Frame, rect: Rect, workers: &[&ExecutorWorkerStatus], loading: char, @@ -387,7 +384,7 @@ fn draw_workers_chunk( .map(|worker| worker.name.len()) .max() .unwrap_or(0); - let text: Vec = workers + let text: Vec = workers .iter() .map(|worker| { let worker_name = format!("- {: