From 64a4201cbc9778bfe56f0826dd839fb800078d13 Mon Sep 17 00:00:00 2001 From: Peer Sommerlund Date: Fri, 1 May 2026 23:42:57 +0200 Subject: [PATCH] Migrate to gleisbau 0.7.3 --- Cargo.lock | 4 +-- Cargo.toml | 2 +- src/main.rs | 25 ++++++++++++---- src/print/mod.rs | 39 ------------------------ src/print/svg.rs | 71 +++++++++++++++++++++++++++----------------- src/print/unicode.rs | 54 ++++++++++++++++----------------- 6 files changed, 93 insertions(+), 102 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7d4a68d..4084e12 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -364,9 +364,9 @@ dependencies = [ [[package]] name = "gleisbau" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6401871b98a7af32f127715db0e95f8e903daecf63b742e86d3e8192a151d5db" +checksum = "f62d5fddd695288c7bb753bb9018634770675d0eda184e1f10f854a0ac2f7724" dependencies = [ "atty", "chrono", diff --git a/Cargo.toml b/Cargo.toml index 2039d90..a365122 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,4 +34,4 @@ platform-dirs = "0.3" crossterm = {version = "0.29", optional = false} chrono = {version = "0.4", optional = false} textwrap = {version = "0.16", default-features = false, optional = false, features = ["unicode-width"]} -gleisbau = "0.7.2" +gleisbau = "0.7.3" diff --git a/src/main.rs b/src/main.rs index a80a73f..20843f9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -21,6 +21,7 @@ use gleisbau::print::unicode::print_unicode; use gleisbau::settings::{ BranchOrder, BranchSettings, BranchSettingsDef, Characters, MergePatterns, Settings, }; +use itertools::enumerate; use platform_dirs::AppDirs; use std::path::PathBuf; use std::str::FromStr; @@ -631,15 +632,27 @@ fn run( let duration_graph = now.elapsed().as_micros(); if settings.debug { - for branch in &graph.all_branches { + let tracks = graph.tracks.lock().unwrap(); + for (br_inx, branch) in enumerate(&tracks.all_branches) { + let Some(branch_vis) = graph.layout.track_visual(br_inx) else { + eprintln!( + "#{} {} (col --) ({:?}) {} s: --, t: --", + br_inx, + branch.name, + branch.range, + if branch.is_merged { "m" } else { "" }, + ); + continue; + }; eprintln!( - "{} (col {}) ({:?}) {} s: {:?}, t: {:?}", + "#{} {} (col {}) ({:?}) {} s: {:?}, t: {:?}", + br_inx, branch.name, - branch.visual.column.unwrap_or(99), + branch_vis.column.unwrap_or(99), branch.range, if branch.is_merged { "m" } else { "" }, - branch.visual.source_order_group, - branch.visual.target_order_group + branch_vis.source_order_group, + branch_vis.target_order_group ); } } @@ -660,7 +673,7 @@ fn run( "Graph construction: {:.1} ms, printing: {:.1} ms ({} commits)", duration_graph as f32 / 1000.0, duration_print as f32 / 1000.0, - graph.commits.len() + graph.tracks.lock().unwrap().commits.len() ); } Ok(()) diff --git a/src/print/mod.rs b/src/print/mod.rs index 05e223d..3f4f693 100644 --- a/src/print/mod.rs +++ b/src/print/mod.rs @@ -1,47 +1,8 @@ //! Create visual representations of git graphs. -use gleisbau::graph::GitGraph; -use std::cmp::max; - // TODO remove code once gleisbau API has stabilized // Some of these features might return to the CLI tool (this application) //pub mod colors; //pub mod format; pub mod svg; //pub mod unicode; - -/// Find the index at which a between-branch connection -/// has to deviate from the current branch's column. -/// -/// Returns the last index on the current column. -fn get_deviate_index(graph: &GitGraph, index: usize, par_index: usize) -> usize { - let info = &graph.commits[index]; - - let par_info = &graph.commits[par_index]; - let par_branch = &graph.all_branches[par_info.branch_trace.unwrap()]; - - let mut min_split_idx = index; - for sibling_oid in &par_info.children { - if let Some(&sibling_index) = graph.indices.get(sibling_oid) { - if let Some(sibling) = graph.commits.get(sibling_index) { - if let Some(sibling_trace) = sibling.branch_trace { - let sibling_branch = &graph.all_branches[sibling_trace]; - if sibling_oid != &info.oid - && sibling_branch.visual.column == par_branch.visual.column - && sibling_index > min_split_idx - { - min_split_idx = sibling_index; - } - } - } - } - } - - // TODO: in cases where no crossings occur, the rule for merge commits can also be applied to normal commits - // See also branch::trace_branch() - if info.is_merge { - max(index, min_split_idx) - } else { - (par_index as i32 - 1) as usize - } -} diff --git a/src/print/svg.rs b/src/print/svg.rs index 434759d..4b82b0f 100644 --- a/src/print/svg.rs +++ b/src/print/svg.rs @@ -1,7 +1,10 @@ //! Create graphs in SVG format (Scalable Vector Graphics). +use itertools::enumerate; + use gleisbau::graph::CommitInfo; use gleisbau::graph::GitGraph; +use gleisbau::layout::get_deviate_index; use gleisbau::settings::Settings; use svg::node::element::path::Data; use svg::node::element::{Circle, Group, Line, Path, Text, Title}; @@ -9,20 +12,23 @@ use svg::Document; /// Creates a SVG visual representation of a graph. pub fn print_svg(graph: &GitGraph, settings: &Settings) -> Result { + let tracks = graph.tracks.lock().unwrap(); + let layout = &graph.layout; let mut document = Document::new(); - let max_idx = graph.commits.len(); + let max_idx = tracks.commits.len(); let mut widest_summary = 0.0; let mut widest_branch_names = 0.0; if settings.debug { - for branch in &graph.all_branches { + for (branch_inx, branch) in enumerate(&tracks.all_branches) { if let (Some(start), Some(end)) = branch.range { + let branch_visual = layout.track_visual(branch_inx).unwrap(); document = document.add(bold_line( start, - branch.visual.column.unwrap(), + branch_visual.column.unwrap(), end, - branch.visual.column.unwrap(), + branch_visual.column.unwrap(), "cyan", )); } @@ -31,7 +37,7 @@ pub fn print_svg(graph: &GitGraph, settings: &Settings) -> Result Result usize { - graph + let tracks = graph.tracks.lock().unwrap(); + let layout = &graph.layout; + tracks .commits .iter() .filter_map(|info| { info.branch_trace - .and_then(|trace| graph.all_branches[trace].visual.column) + .and_then(|trace| layout.track_visual(trace)) + .and_then(|visual| visual.column) }) .max() .unwrap_or(0) } +// index is graph.commits[index] fn draw_commit(info: &CommitInfo, graph: &GitGraph, index: usize) -> Group { + let tracks = graph.tracks.lock().unwrap(); + let layout = &graph.layout; let mut group = Group::new(); if let Some(trace) = info.branch_trace { - let branch = &graph.all_branches[trace]; - let branch_color = &branch.visual.svg_color; + let branch_visual = graph.layout.track_visual(trace).unwrap(); + let branch_color = &branch_visual.svg_color; for p in 0..2 { let parent = info.parents[p]; let Some(par_oid) = parent else { continue; }; - let Some(par_idx) = graph.indices.get(&par_oid) else { - // Parent is outside scope of graph.indices + let Some(par_idx) = tracks.indices.get(&par_oid) else { + // Parent is outside scope of tracks.indices // so draw a vertical line to the bottom - let idx_bottom = graph.commits.len(); + let idx_bottom = tracks.commits.len(); group = group.add(line( index, - branch.visual.column.unwrap(), + branch_visual.column.unwrap(), idx_bottom, - branch.visual.column.unwrap(), + branch_visual.column.unwrap(), branch_color, )); continue; }; - let par_info = &graph.commits[*par_idx]; - let par_branch = &graph.all_branches[par_info.branch_trace.unwrap()]; + let par_info = &tracks.commits[*par_idx]; + let par_branch_idx = par_info.branch_trace.unwrap(); + let par_branch_visual = layout.track_visual(par_branch_idx).unwrap(); group = group.add(path( index, - branch.visual.column.unwrap(), + branch_visual.column.unwrap(), *par_idx, - par_branch.visual.column.unwrap(), - if branch.visual.column == par_branch.visual.column { + par_branch_visual.column.unwrap(), + if branch_visual.column == par_branch_visual.column { index } else { - super::get_deviate_index(graph, index, *par_idx) + get_deviate_index(&tracks, layout, index, *par_idx) }, if info.is_merge { - &par_branch.visual.svg_color + &par_branch_visual.svg_color } else { branch_color }, @@ -151,7 +166,7 @@ fn draw_commit(info: &CommitInfo, graph: &GitGraph, index: usize) -> Group { group = group.add( commit_dot( index, - branch.visual.column.unwrap(), + branch_visual.column.unwrap(), branch_color, !info.is_merge, ) @@ -180,10 +195,12 @@ fn draw_branches( ) -> Option<(Group, f32)> { let (x, y) = commit_coord(index, column); - let mut branch_names = info - .branches + let mut branch_names = graph + .labels + .get_labels(&info.oid) + .unwrap_or(&vec![]) .iter() - .map(|b| graph.all_branches[*b].name.clone()) + .map(|label| label.name.clone()) .collect::>(); if graph.head.oid == info.oid { diff --git a/src/print/unicode.rs b/src/print/unicode.rs index 3cbff63..eb61ebe 100644 --- a/src/print/unicode.rs +++ b/src/print/unicode.rs @@ -50,13 +50,13 @@ graph-lines, text-lines, start-row Some entries in this vector might be empty strings or correspond to inserted blank lines for visual spacing. -3. start_row: `Vec`: Starting row for commit in the `graph.commits` vector. +3. start_row: `Vec`: Starting row for commit in the `tracks.commits` vector. */ pub type UnicodeGraphInfo = (Vec, Vec, Vec); /// Creates a text-based visual representation of a graph. pub fn print_unicode(graph: &GitGraph, settings: &Settings) -> Result { - if graph.all_branches.is_empty() { + if tracks.all_branches.is_empty() { return Ok((vec![], vec![], vec![])); } @@ -128,7 +128,7 @@ fn build_commit_lines_and_map<'a>( inserts: &HashMap>>, wrap_options: &Option>, ) -> Result<(Vec>, Vec), String> { - let head_idx = graph.indices.get(&graph.head.oid); + let head_idx = tracks.indices.get(&graph.head.oid); // Compute commit text into text_lines and add blank rows // if needed to match branch graph inserts. @@ -136,7 +136,7 @@ fn build_commit_lines_and_map<'a>( let mut text_lines = vec![]; let mut offset = 0; - for (idx, info) in graph.commits.iter().enumerate() { + for (idx, info) in tracks.commits.iter().enumerate() { index_map.push(idx + offset); // Calculate needed graph inserts (for ranges only) @@ -203,11 +203,11 @@ fn draw_graph_lines( }, ); - for (idx, info) in graph.commits.iter().enumerate() { + for (idx, info) in tracks.commits.iter().enumerate() { let Some(trace) = info.branch_trace else { continue; }; - let branch = &graph.all_branches[trace]; + let branch = &tracks.all_branches[trace]; let column = branch.visual.column.unwrap(); let idx_map = index_map[idx]; @@ -245,8 +245,8 @@ fn draw_parent_lines( let Some(par_oid) = parent else { continue; }; - let Some(par_idx) = graph.indices.get(&par_oid) else { - // Parent is outside scope of graph.indices + let Some(par_idx) = tracks.indices.get(&par_oid) else { + // Parent is outside scope of tracks.indices // so draw a vertical line to the bottom let idx_bottom = grid.height; vline( @@ -260,8 +260,8 @@ fn draw_parent_lines( }; let par_idx_map = index_map[*par_idx]; - let par_info = &graph.commits[*par_idx]; - let par_branch = &graph.all_branches[par_info.branch_trace.unwrap()]; + let par_info = &tracks.commits[*par_idx]; + let par_branch = &tracks.all_branches[par_info.branch_trace.unwrap()]; let par_column = par_branch.visual.column.unwrap(); let (color, pers) = if info.is_merge { @@ -566,7 +566,7 @@ fn update_right_cell_backward(grid: &mut Grid, index: usize, from_2: usize, colo /// # Returns /// /// A `HashMap` where the keys are the indices of commits in the -/// `graph.commits` vector, and the values are vectors of vectors +/// `tracks.commits` vector, and the values are vectors of vectors /// of `Occ`. Each inner vector represents a potential row of /// insertions needed *before* the commit at the key index. The /// `Occ` enum describes what occupies a cell in that row @@ -580,11 +580,11 @@ fn get_inserts(graph: &GitGraph, compact: bool) -> HashMap>> // First, for each commit, we initialize an entry in the `inserts` // map with a single row containing the commit itself. This ensures // that every commit has a position in the grid. - for (idx, info) in graph.commits.iter().enumerate() { + for (idx, info) in tracks.commits.iter().enumerate() { // Get the visual column assigned to the branch of this commit. Unwrap is safe here // because `branch_trace` should always point to a valid branch with an assigned column // for commits that are included in the filtered graph. - let column = graph.all_branches[info.branch_trace.unwrap()] + let column = tracks.all_branches[info.branch_trace.unwrap()] .visual .column .unwrap(); @@ -594,12 +594,12 @@ fn get_inserts(graph: &GitGraph, compact: bool) -> HashMap>> // Now, iterate through the commits again to identify connections // needed between parents that are not directly adjacent in the - // `graph.commits` list. - for (idx, info) in graph.commits.iter().enumerate() { + // `tracks.commits` list. + for (idx, info) in tracks.commits.iter().enumerate() { // If the commit has a branch trace (meaning it belongs to a visualized branch). if let Some(trace) = info.branch_trace { // Get the `BranchInfo` for the current commit's branch. - let branch = &graph.all_branches[trace]; + let branch = &tracks.all_branches[trace]; // Get the visual column of the current commit's branch. Unwrap is safe as explained above. let column = branch.visual.column.unwrap(); @@ -609,10 +609,10 @@ fn get_inserts(graph: &GitGraph, compact: bool) -> HashMap>> let Some(par_oid) = parent else { continue; }; - // Try to find the index of the parent commit in the `graph.commits` vector. - if let Some(par_idx) = graph.indices.get(&par_oid) { - let par_info = &graph.commits[*par_idx]; - let par_branch = &graph.all_branches[par_info.branch_trace.unwrap()]; + // Try to find the index of the parent commit in the `tracks.commits` vector. + if let Some(par_idx) = tracks.indices.get(&par_oid) { + let par_info = &tracks.commits[*par_idx]; + let par_branch = &tracks.all_branches[par_info.branch_trace.unwrap()]; let par_column = par_branch.visual.column.unwrap(); // Determine the sorted range of columns between the current commit and its parent. let column_range = sorted(column, par_column); @@ -620,7 +620,7 @@ fn get_inserts(graph: &GitGraph, compact: bool) -> HashMap>> // If the column of the current commit is different from the column of its parent, // it means we need to draw a horizontal line (an "insert") to connect them. if column != par_column { - // Find the index in the `graph.commits` list where the visual connection + // Find the index in the `tracks.commits` list where the visual connection // should deviate from the parent's line. This helps in drawing the graph // correctly when branches diverge or merge. let split_index = super::get_deviate_index(graph, idx, *par_idx); @@ -784,7 +784,7 @@ pub fn format_branches( ) -> String { let curr_color = info .branch_trace - .map(|branch_idx| &graph.all_branches[branch_idx].visual.term_color); + .map(|branch_idx| &tracks.all_branches[branch_idx].visual.term_color); let mut branch_str = String::new(); @@ -805,14 +805,14 @@ pub fn format_branches( let branches = info.branches.iter().sorted_by_key(|br| { if let Some(head) = head { - head.name != graph.all_branches[**br].name + head.name != tracks.all_branches[**br].name } else { false } }); for (idx, branch_index) in branches.enumerate() { - let branch = &graph.all_branches[*branch_index]; + let branch = &tracks.all_branches[*branch_index]; let branch_color = branch.visual.term_color; if let Some(head) = head { @@ -843,7 +843,7 @@ pub fn format_branches( if !info.tags.is_empty() { write!(branch_str, " [").unwrap(); for (idx, tag_index) in info.tags.iter().enumerate() { - let tag = &graph.all_branches[*tag_index]; + let tag = &tracks.all_branches[*tag_index]; let tag_color = curr_color.unwrap_or(&tag.visual.term_color); let tag_name = &tag.name[5..]; @@ -867,10 +867,10 @@ pub fn format_branches( /// Occupied row ranges enum Occ { /// Horizontal position of commit markers - // First field (usize): The index of a commit within the graph.commits vector. + // First field (usize): The index of a commit within the tracks.commits vector. // Second field (usize): The visual column in the grid where this commit is located. This column is determined by the branch the commit belongs to. // Purpose: This variant of Occ signifies that a specific row in the grid is occupied by a commit marker (dot or circle) at a particular column. - Commit(usize, usize), // index in Graph.commits, column + Commit(usize, usize), // index in tracks.commits, column /// Horizontal line connecting two commits // First field (usize): The index of the starting commit of a visual connection (usually the child commit).