diff --git a/Cargo.lock b/Cargo.lock index 4239ed2..863a734 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "atty" version = "0.2.14" @@ -91,50 +93,50 @@ dependencies = [ [[package]] name = "crossterm" -version = "0.18.2" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e86d73f2a0b407b5768d10a8c720cf5d2df49a9efc10ca09176d201ead4b7fb" +checksum = "7c36c10130df424b2f3552fcc2ddcd9b28a27b1e54b358b45874f88d1ca6888c" dependencies = [ "bitflags", - "crossterm_winapi 0.6.2", + "crossterm_winapi 0.7.0", "lazy_static", "libc", "mio", "parking_lot", - "signal-hook", + "signal-hook 0.1.17", "winapi", ] [[package]] name = "crossterm" -version = "0.19.0" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c36c10130df424b2f3552fcc2ddcd9b28a27b1e54b358b45874f88d1ca6888c" +checksum = "c0ebde6a9dd5e331cd6c6f48253254d117642c31653baa475e394657c59c1f7d" dependencies = [ "bitflags", - "crossterm_winapi 0.7.0", - "lazy_static", + "crossterm_winapi 0.8.0", "libc", "mio", "parking_lot", - "signal-hook", + "signal-hook 0.3.9", + "signal-hook-mio", "winapi", ] [[package]] name = "crossterm_winapi" -version = "0.6.2" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2265c3f8e080075d9b6417aa72293fc71662f34b4af2612d8d1b074d29510db" +checksum = "0da8964ace4d3e4a044fd027919b2237000b24315a37c916f61809f1ff2140b9" dependencies = [ "winapi", ] [[package]] name = "crossterm_winapi" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0da8964ace4d3e4a044fd027919b2237000b24315a37c916f61809f1ff2140b9" +checksum = "3a6966607622438301997d3dac0d2f6e9a90c68bb6bc1785ea98456ab93c0507" dependencies = [ "winapi", ] @@ -168,6 +170,7 @@ dependencies = [ name = "gitt" version = "0.1.0" dependencies = [ + "cassowary", "chrono", "clap", "crossterm 0.19.0", @@ -494,11 +497,32 @@ dependencies = [ "signal-hook-registry", ] +[[package]] +name = "signal-hook" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "470c5a6397076fae0094aaf06a08e6ba6f37acb77d3b1b91ea92b4d6c8650c39" +dependencies = [ + "libc", + "signal-hook-registry", +] + +[[package]] +name = "signal-hook-mio" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29fd5867f1c4f2c5be079aee7a2adf1152ebb04a4bc4d341f504b7dece607ed4" +dependencies = [ + "libc", + "mio", + "signal-hook 0.3.9", +] + [[package]] name = "signal-hook-registry" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16f1d0fef1604ba8f7a073c7e701f213e056707210e9020af4528e0101ce11a6" +checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" dependencies = [ "libc", ] @@ -572,13 +596,13 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tui" -version = "0.14.0" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ced152a8e9295a5b168adc254074525c17ac4a83c90b2716274cc38118bddc9" +checksum = "39c8ce4e27049eed97cfa363a5048b09d995e209994634a0efc26a14ab6c0c23" dependencies = [ "bitflags", "cassowary", - "crossterm 0.18.2", + "crossterm 0.20.0", "unicode-segmentation", "unicode-width", ] diff --git a/Cargo.toml b/Cargo.toml index fe49dc2..1849bd4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,7 @@ edition = "2018" [dependencies] git2 = "0.13" crossterm = { version = "0.19" } -tui = { version = "0.14", default-features = false, features = ['crossterm'] } +tui = { version = "0.16", default-features = false, features = ['crossterm'] } +cassowary = "0.3" # keep this in sync /w tui? clap = { version = "3.0.0-beta.2" } chrono = "0.4.19" diff --git a/src/main.rs b/src/main.rs index ba66d87..fe1172f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -30,6 +30,10 @@ fn main() -> Result<(), Box> { let tick_rate = std::time::Duration::from_millis(200); let mut handler = controller::EventHandler::new(tick_rate); + let bounds: Vec<_> = (0..6).map(|_| cassowary::Variable::new()).collect(); + let window_width = cassowary::Variable::new(); + let mut column_solver = widgets::commit_list_column_width_solver(&bounds, &window_width); + // TODO: use RAII for this somehow crossterm::execute!(std::io::stdout(), crossterm::terminal::EnterAlternateScreen)?; crossterm::terminal::enable_raw_mode().expect("can run in raw mode"); @@ -85,17 +89,18 @@ fn main() -> Result<(), Box> { drop(commits); app_model.resize_revision_window(length); + column_solver + .suggest_value(window_width, chunk_commit.width as f64) + .expect("constraints solver failed"); + let column_widths = widgets::solver_changes_to_lengths(&column_solver, &bounds); + let list = tui::widgets::Table::new(commit_items) .block(commits_block) .highlight_style( tui::style::Style::default().add_modifier(tui::style::Modifier::BOLD), ) // TODO: https://github.com/fdehau/tui-rs/issues/499 - .widths(&[ - tui::layout::Constraint::Length(84), - tui::layout::Constraint::Length(40), - tui::layout::Constraint::Length(10), // Commit date (truncates time by default) - ]); + .widths(column_widths.as_slice()); let (details_index, details_window, details_length) = app_model.diff_line_scroll(); let details_scroll = widgets::VerticalBar { diff --git a/src/widgets.rs b/src/widgets.rs index c5e4829..b5f1c09 100644 --- a/src/widgets.rs +++ b/src/widgets.rs @@ -1,3 +1,6 @@ +use cassowary::strength::{REQUIRED, STRONG, WEAK}; +use cassowary::WeightedRelation::*; +use cassowary::{Solver, Variable}; use tui::buffer::Buffer; use tui::layout::Rect; use tui::style::Style; @@ -46,3 +49,57 @@ impl Widget for VerticalBar { buf.set_style(window_area, self.style); } } + +// bounds consists of pairs of variables representing left and right position of the column +pub fn commit_list_column_width_solver(bounds: &[Variable], window_width: &Variable) -> Solver { + let mut solver = Solver::new(); + solver + .add_constraints(&[ + *window_width | GE(REQUIRED) | 0.0, // positive window width + bounds[0] | EQ(REQUIRED) | 0.0, // left align + bounds[3] | EQ(REQUIRED) | bounds[4] - 1.0, // right align + bounds[5] | EQ(REQUIRED) | *window_width, // right align + bounds[2] | GE(REQUIRED) | bounds[1], // no overlap + bounds[4] | GE(REQUIRED) | bounds[3], // no overlap + // positive widths + bounds[0] | LE(REQUIRED) | bounds[1], + bounds[2] | LE(REQUIRED) | bounds[3], + bounds[4] | LE(REQUIRED) | bounds[5], + // preferred widths: + bounds[1] - bounds[0] | EQ(WEAK) | *window_width * (72.0 / 100.0), + bounds[3] - bounds[2] | EQ(WEAK) | *window_width * (18.0 / 100.0), + bounds[5] - bounds[4] | EQ(WEAK) | *window_width * (9.0 / 100.0), + // constrain some columns to a range: + bounds[3] - bounds[2] | LE(REQUIRED) | 40.0, + bounds[3] - bounds[2] | GE(STRONG) | 20.0, + bounds[5] - bounds[4] | LE(REQUIRED) | 15.0, + bounds[5] - bounds[4] | GE(STRONG) | 10.0, + // require one column to have a minimum size + bounds[1] - bounds[0] | GE(STRONG) | 50.0, + // fixed length + //box1.right - box1.left | EQ(WEAK) | 79.0, + //box2.right - box2.left | EQ(WEAK) | 20.0, + //box3.right - box3.left | EQ(WEAK) | 10.0, + ]) + .unwrap(); + solver + .add_edit_variable(*window_width, STRONG) + .expect("Unable to add edit variable"); + + solver +} + +pub fn solver_changes_to_lengths( + solver: &Solver, + bounds: &[Variable], +) -> Vec { + let widths: Vec<_> = bounds + .windows(2) + .map(|bounds| solver.get_value(bounds[1]) - solver.get_value(bounds[0])) + .collect(); + vec![ + tui::layout::Constraint::Length((widths[0] + widths[1]) as u16), + tui::layout::Constraint::Length((widths[2] + widths[3]) as u16), + tui::layout::Constraint::Length((widths[4]) as u16), + ] +}