Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
25 changes: 19 additions & 6 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
);
}
}
Expand All @@ -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(())
Expand Down
39 changes: 0 additions & 39 deletions src/print/mod.rs
Original file line number Diff line number Diff line change
@@ -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
}
}
71 changes: 44 additions & 27 deletions src/print/svg.rs
Original file line number Diff line number Diff line change
@@ -1,28 +1,34 @@
//! 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};
use svg::Document;

/// Creates a SVG visual representation of a graph.
pub fn print_svg(graph: &GitGraph, settings: &Settings) -> Result<String, String> {
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",
));
}
Expand All @@ -31,7 +37,7 @@ pub fn print_svg(graph: &GitGraph, settings: &Settings) -> Result<String, String

let max_column = find_max_column(graph);

for (idx, info) in graph.commits.iter().enumerate() {
for (idx, info) in tracks.commits.iter().enumerate() {
document = document.add(draw_commit(info, graph, idx));

let commit = graph.repository.find_commit(info.oid).unwrap();
Expand All @@ -40,10 +46,12 @@ pub fn print_svg(graph: &GitGraph, settings: &Settings) -> Result<String, String
document = document.add(draw_summary(idx, max_column, commit_summary));

if let Some(trace) = info.branch_trace {
let branch = &graph.all_branches[trace];
let branch_visual = layout
.track_visual(trace)
.expect("Branch should have a layout");

if let Some((branches, width)) =
draw_branches(idx, branch.visual.column.unwrap(), info, graph)
draw_branches(idx, branch_visual.column.unwrap(), info, graph)
{
document = document.add(branches);

Expand Down Expand Up @@ -91,57 +99,64 @@ fn set_document_size(
}

fn find_max_column(graph: &GitGraph) -> 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
},
Expand All @@ -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,
)
Expand Down Expand Up @@ -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::<Vec<String>>();

if graph.head.oid == info.oid {
Expand Down
Loading
Loading