Skip to content

Commit

Permalink
Half-width graph support (#50)
Browse files Browse the repository at this point in the history
* Implement --graph-width option

* Add tests

* Update README

* Update README
  • Loading branch information
lusingander committed Sep 15, 2024
1 parent 132c12e commit 4225309
Show file tree
Hide file tree
Showing 10 changed files with 173 additions and 40 deletions.
45 changes: 37 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,11 +95,12 @@ Serie - A rich git commit graph in your terminal, like magic 📚
Usage: serie [OPTIONS]
Options:
-p, --protocol <TYPE> Image protocol to render graph [default: auto] [possible values: auto, iterm, kitty]
-o, --order <TYPE> Commit ordering algorithm [default: chrono] [possible values: chrono, topo]
--preload Preload all graph images
-h, --help Print help
-V, --version Print version
-p, --protocol <TYPE> Image protocol to render graph [default: auto] [possible values: auto, iterm, kitty]
-o, --order <TYPE> Commit ordering algorithm [default: chrono] [possible values: chrono, topo]
-g, --graph-width <TYPE> Commit graph image cell width [possible values: double, single]
--preload Preload all graph images
-h, --help Print help
-V, --version Print version
```

#### -p, --protocol \<TYPE\>
Expand All @@ -115,11 +116,39 @@ Refer to [Compatibility](#compatibility) for details.

`--order chrono` will order commits by commit date if possible.

<img src="./img/order-chrono.png" width=500>

`--order topo` will order commits on the same branch consecutively if possible.

<img src="./img/order-topo.png" width=500>
<details>
<summary>Screenshots</summary>

<img src="./img/order-chrono.png" width=400>

`--order chrono`

<img src="./img/order-topo.png" width=400>

`--order topo`

</details>

#### -g, --graph-width \<TYPE\>

The character width that a graph image unit cell occupies.

If not specified, `double` will be used automatically if there is enough width to display it, `single` otherwise.

<details>
<summary>Screenshots</summary>

<img src="./img/graph-width-double.png" width=300>

`--graph-width double`

<img src="./img/graph-width-single.png" width=300>

`--graph-width single`

</details>

#### --preload

Expand Down
Binary file added img/graph-width-double.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/graph-width-single.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified img/order-chrono.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified img/order-topo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 6 additions & 2 deletions src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use crate::{
event::{AppEvent, Receiver, Sender, UserEvent},
external::copy_to_clipboard,
git::Repository,
graph::{Graph, GraphImageManager},
graph::{CellWidthType, Graph, GraphImageManager},
keybind::KeyBind,
protocol::ImageProtocol,
view::View,
Expand Down Expand Up @@ -61,6 +61,7 @@ impl<'a> App<'a> {
keybind: &'a KeyBind,
ui_config: &'a UiConfig,
color_set: &'a ColorSet,
cell_width_type: CellWidthType,
image_protocol: ImageProtocol,
tx: Sender,
) -> Self {
Expand All @@ -79,7 +80,10 @@ impl<'a> App<'a> {
CommitInfo::new(commit, refs, graph_color)
})
.collect();
let graph_cell_width = (graph.max_pos_x + 1) as u16 * 2;
let graph_cell_width = match cell_width_type {
CellWidthType::Double => (graph.max_pos_x + 1) as u16 * 2,
CellWidthType::Single => (graph.max_pos_x + 1) as u16,
};
let head = repository.head();
let commit_list_state = CommitListState::new(
commits,
Expand Down
54 changes: 47 additions & 7 deletions src/check.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,53 @@
use ratatui::crossterm::terminal;

use crate::graph::Graph;
use crate::graph::{CellWidthType, Graph};

pub fn term_size(graph: &Graph) -> std::io::Result<()> {
pub fn decide_cell_width_type(
graph: &Graph,
cell_width_type: Option<CellWidthType>,
) -> std::io::Result<CellWidthType> {
let (w, h) = terminal::size()?;
let image_cell_width = (graph.max_pos_x + 1) * 2;
let required_width = image_cell_width + 2;
if required_width > w as usize {
panic!("Terminal size {w}x{h} is too small. Required width is {required_width}.");
let cell_width_type =
decide_cell_width_type_from(graph.max_pos_x, w as usize, h as usize, cell_width_type);
Ok(cell_width_type)
}

fn decide_cell_width_type_from(
max_pos_x: usize,
term_width: usize,
term_height: usize,
cell_width_type: Option<CellWidthType>,
) -> CellWidthType {
let single_image_cell_width = max_pos_x + 1;
let double_image_cell_width = single_image_cell_width * 2;

match cell_width_type {
Some(CellWidthType::Double) => {
let required_width = double_image_cell_width + 2;
if required_width > term_width {
panic!("Terminal size {term_width}x{term_height} is too small. Required width is {required_width} (graph_width = double).");
}
CellWidthType::Double
}
Some(CellWidthType::Single) => {
let required_width = single_image_cell_width + 2;
if required_width > term_width {
panic!("Terminal size {term_width}x{term_height} is too small. Required width is {required_width} (graph_width = single).");
}
CellWidthType::Single
}
None => {
let double_required_width = double_image_cell_width + 2;
if double_required_width <= term_width {
return CellWidthType::Double;
}
let single_required_width = single_image_cell_width + 2;
if single_required_width <= term_width {
return CellWidthType::Single;
}
panic!(
"Terminal size {term_width}x{term_height} is too small. Required width is {single_required_width} (graph_width = single) or {double_required_width} (graph_width = double)."
);
}
}
Ok(())
}
67 changes: 50 additions & 17 deletions src/graph/image.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ pub struct GraphImageManager<'a> {
encoded_image_map: FxHashMap<CommitHash, String>,

graph: &'a Graph<'a>,
cell_width_type: CellWidthType,
image_params: ImageParams,
drawing_pixels: DrawingPixels,
image_protocol: ImageProtocol,
Expand All @@ -27,17 +28,19 @@ impl<'a> GraphImageManager<'a> {
pub fn new(
graph: &'a Graph,
options: GraphImageOptions,
cell_width_type: CellWidthType,
image_protocol: ImageProtocol,
preload: bool,
) -> Self {
let image_params = ImageParams::new(&options.color_set);
let image_params = ImageParams::new(&options.color_set, cell_width_type);
let drawing_pixels = DrawingPixels::new(&image_params);

let mut m = GraphImageManager {
encoded_image_map: FxHashMap::default(),
image_params,
drawing_pixels,
graph,
cell_width_type,
image_protocol,
};
if preload {
Expand All @@ -59,7 +62,8 @@ impl<'a> GraphImageManager<'a> {
.enumerate()
.map(|(i, commit)| {
let edges = &self.graph.edges[i];
let image = graph_image.images[edges].encode(self.image_protocol);
let image =
graph_image.images[edges].encode(self.cell_width_type, self.image_protocol);
(commit.commit_hash.clone(), image)
})
.collect()
Expand All @@ -75,7 +79,7 @@ impl<'a> GraphImageManager<'a> {
&self.drawing_pixels,
commit_hash,
);
let image = graph_row_image.encode(self.image_protocol);
let image = graph_row_image.encode(self.cell_width_type, self.image_protocol);
self.encoded_image_map.insert(commit_hash.clone(), image);
}
}
Expand All @@ -102,8 +106,11 @@ impl Debug for GraphRowImage {
}

impl GraphRowImage {
fn encode(&self, image_protocol: ImageProtocol) -> String {
let image_cell_width = self.cell_count * 2;
fn encode(&self, cell_width_type: CellWidthType, image_protocol: ImageProtocol) -> String {
let image_cell_width = match cell_width_type {
CellWidthType::Double => self.cell_count * 2,
CellWidthType::Single => self.cell_count,
};
image_protocol.encode(&self.bytes, image_cell_width)
}
}
Expand All @@ -120,13 +127,19 @@ pub struct ImageParams {
background_color: image::Rgba<u8>,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CellWidthType {
Double, // 2 cells
Single,
}

impl ImageParams {
pub fn new(color_set: &ColorSet) -> Self {
let width = 50;
let height = 50;
let line_width = 5;
let circle_inner_radius = 10;
let circle_outer_radius = 13;
pub fn new(color_set: &ColorSet, cell_width_type: CellWidthType) -> Self {
let (width, height, line_width, circle_inner_radius, circle_outer_radius) =
match cell_width_type {
CellWidthType::Double => (50, 50, 5, 10, 13),
CellWidthType::Single => (25, 50, 3, 7, 10),
};
let edge_colors = color_set
.colors
.iter()
Expand Down Expand Up @@ -696,7 +709,8 @@ mod tests {
let cell_count = 4;
let graph_color_config = GraphColorConfig::default();
let color_set = ColorSet::new(&graph_color_config);
let image_params = ImageParams::new(&color_set);
let cell_width_type = CellWidthType::Double;
let image_params = ImageParams::new(&color_set, cell_width_type);
let drawing_pixels = DrawingPixels::new(&image_params);
let file_name = "default_params";

Expand All @@ -709,7 +723,8 @@ mod tests {
let cell_count = 4;
let graph_color_config = GraphColorConfig::default();
let color_set = ColorSet::new(&graph_color_config);
let mut image_params = ImageParams::new(&color_set);
let cell_width_type = CellWidthType::Double;
let mut image_params = ImageParams::new(&color_set, cell_width_type);
image_params.width = 100;
let drawing_pixels = DrawingPixels::new(&image_params);
let file_name = "wide_image";
Expand All @@ -723,21 +738,37 @@ mod tests {
let cell_count = 4;
let graph_color_config = GraphColorConfig::default();
let color_set = ColorSet::new(&graph_color_config);
let mut image_params = ImageParams::new(&color_set);
let cell_width_type = CellWidthType::Double;
let mut image_params = ImageParams::new(&color_set, cell_width_type);
image_params.height = 100;
let drawing_pixels = DrawingPixels::new(&image_params);
let file_name = "tall_image";

test_calc_graph_row_image(params, cell_count, image_params, drawing_pixels, file_name);
}

#[test]
fn test_calc_graph_row_image_single_cell_width() {
let params = simple_test_params();
let cell_count = 4;
let graph_color_config = GraphColorConfig::default();
let color_set = ColorSet::new(&graph_color_config);
let cell_width_type = CellWidthType::Single;
let image_params = ImageParams::new(&color_set, cell_width_type);
let drawing_pixels = DrawingPixels::new(&image_params);
let file_name = "single_cell_width";

test_calc_graph_row_image(params, cell_count, image_params, drawing_pixels, file_name);
}

#[test]
fn test_calc_graph_row_image_circle_radius() {
let params = straight_test_params();
let cell_count = 2;
let graph_color_config = GraphColorConfig::default();
let color_set = ColorSet::new(&graph_color_config);
let mut image_params = ImageParams::new(&color_set);
let cell_width_type = CellWidthType::Double;
let mut image_params = ImageParams::new(&color_set, cell_width_type);
image_params.circle_inner_radius = 5;
image_params.circle_outer_radius = 12;
let drawing_pixels = DrawingPixels::new(&image_params);
Expand All @@ -752,7 +783,8 @@ mod tests {
let cell_count = 2;
let graph_color_config = GraphColorConfig::default();
let color_set = ColorSet::new(&graph_color_config);
let mut image_params = ImageParams::new(&color_set);
let cell_width_type = CellWidthType::Double;
let mut image_params = ImageParams::new(&color_set, cell_width_type);
image_params.line_width = 1;
let drawing_pixels = DrawingPixels::new(&image_params);
let file_name = "line_width";
Expand All @@ -775,7 +807,8 @@ mod tests {
background: "#00ff0070".into(),
};
let color_set = ColorSet::new(&graph_color_config);
let image_params = ImageParams::new(&color_set);
let cell_width_type = CellWidthType::Double;
let image_params = ImageParams::new(&color_set, cell_width_type);
let drawing_pixels = DrawingPixels::new(&image_params);
let file_name = "color";

Expand Down
32 changes: 29 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ struct Args {
#[arg(short, long, value_name = "TYPE", default_value = "chrono")]
order: CommitOrderType,

/// Commit graph image cell width
#[arg(short, long, value_name = "TYPE")]
graph_width: Option<GraphWidthType>,

/// Preload all graph images
#[arg(long, default_value = "false")]
preload: bool,
Expand Down Expand Up @@ -68,6 +72,21 @@ impl From<CommitOrderType> for graph::SortCommit {
}
}

#[derive(Debug, Clone, ValueEnum)]
enum GraphWidthType {
Double,
Single,
}

impl From<GraphWidthType> for graph::CellWidthType {
fn from(width: GraphWidthType) -> Self {
match width {
GraphWidthType::Double => graph::CellWidthType::Double,
GraphWidthType::Single => graph::CellWidthType::Single,
}
}
}

pub fn run() -> std::io::Result<()> {
color_eyre::install().unwrap();
let args = Args::parse();
Expand All @@ -81,11 +100,17 @@ pub fn run() -> std::io::Result<()> {

let graph = graph::calc_graph(&repository);

check::term_size(&graph)?;
let cell_width_type =
check::decide_cell_width_type(&graph, args.graph_width.map(|w| w.into()))?;

let graph_image_options = graph::GraphImageOptions::new(color_set.clone());
let graph_image_manager =
GraphImageManager::new(&graph, graph_image_options, image_protocol, args.preload);
let graph_image_manager = GraphImageManager::new(
&graph,
graph_image_options,
cell_width_type,
image_protocol,
args.preload,
);

let mut terminal = ratatui::init();

Expand All @@ -98,6 +123,7 @@ pub fn run() -> std::io::Result<()> {
&key_bind,
&ui_config,
&color_set,
cell_width_type,
image_protocol,
tx,
);
Expand Down
Loading

0 comments on commit 4225309

Please sign in to comment.