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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ Serie - A rich git commit graph in your terminal, like magic 📚
Usage: serie [OPTIONS]

Options:
-n, --max-count <NUMBER> Maximum number of commits to render
-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 [default: auto] [possible values: auto, double, single]
Expand Down
7 changes: 7 additions & 0 deletions docs/src/getting-started/command-line-options.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Command Line Options

## -n, --max-count \<NUMBER\>

Maximum number of commits to render.

If not specified, all commits will be rendered.
It behaves similarly to the `--max-count` option of `git log`.

## -p, --protocol \<TYPE\>

A protocol type for rendering images of commit graphs.
Expand Down
15 changes: 12 additions & 3 deletions src/git.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,11 +124,11 @@ pub struct Repository {
}

impl Repository {
pub fn load(path: &Path, sort: SortCommit) -> Result<Self> {
pub fn load(path: &Path, sort: SortCommit, max_count: Option<usize>) -> Result<Self> {
check_git_repository(path)?;

let stashes = load_all_stashes(path);
let commits = load_all_commits(path, sort, &stashes);
let commits = load_all_commits(path, sort, &stashes, max_count);

let commits = merge_stashes_to_commits(commits, stashes);
let commit_hashes = commits.iter().map(|c| c.commit_hash.clone()).collect();
Expand Down Expand Up @@ -250,7 +250,12 @@ fn is_bare_repository(path: &Path) -> bool {
output.status.success() && output.stdout == b"true\n"
}

fn load_all_commits(path: &Path, sort: SortCommit, stashes: &[Commit]) -> Vec<Commit> {
fn load_all_commits(
path: &Path,
sort: SortCommit,
stashes: &[Commit],
max_count: Option<usize>,
) -> Vec<Commit> {
let mut cmd = Command::new("git");
cmd.arg("log");

Expand All @@ -271,6 +276,10 @@ fn load_all_commits(path: &Path, sort: SortCommit, stashes: &[Commit]) -> Vec<Co
});
cmd.arg("HEAD");

if let Some(n) = max_count {
cmd.arg("--max-count").arg(n.to_string());
}

cmd.current_dir(path).stdout(Stdio::piped());

let mut process = cmd.spawn().unwrap();
Expand Down
10 changes: 10 additions & 0 deletions src/graph/calc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,16 @@ fn calc_edges(
if max_pos_x < pos_x {
max_pos_x = pos_x;
}

// draw down edge if has parent but parent not in the graph (when max_count is set)
if !commit.parent_commit_hashes.is_empty()
&& repository.commit(&commit.parent_commit_hashes[0]).is_none()
{
edges[pos_y].push(WrappedEdge::new(EdgeType::Down, pos_x, pos_x, hash));
((pos_y + 1)..commits.len()).for_each(|y| {
edges[y].push(WrappedEdge::new(EdgeType::Vertical, pos_x, pos_x, hash));
});
}
}

for commit in commits {
Expand Down
7 changes: 6 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ use serde::Deserialize;
#[derive(Parser)]
#[command(version)]
struct Args {
/// Maximum number of commits to render
#[arg(short = 'n', long, value_name = "NUMBER")]
max_count: Option<usize>,

/// Image protocol to render graph [default: auto]
#[arg(short, long, value_name = "TYPE")]
protocol: Option<ImageProtocolType>,
Expand Down Expand Up @@ -133,6 +137,7 @@ pub fn run() -> Result<()> {
let (core_config, ui_config, graph_config, color_theme, key_bind_patch) = config::load()?;
let key_bind = keybind::KeyBind::new(key_bind_patch);

let max_count = args.max_count;
let image_protocol = args.protocol.or(core_config.option.protocol).into();
let order = args.order.or(core_config.option.order).into();
let graph_width = args.graph_width.or(core_config.option.graph_width);
Expand All @@ -144,7 +149,7 @@ pub fn run() -> Result<()> {

let graph_color_set = color::GraphColorSet::new(&graph_config.color);

let repository = git::Repository::load(Path::new("."), order)?;
let repository = git::Repository::load(Path::new("."), order, max_count)?;

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

Expand Down
11 changes: 8 additions & 3 deletions src/widget/commit_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use ratatui::{
text::{Line, Span},
widgets::{List, ListItem, StatefulWidget, Widget},
};
use rustc_hash::FxHashMap;
use rustc_hash::{FxHashMap, FxHashSet};
use tui_input::{backend::crossterm::EventHandler, Input};

use crate::{
Expand Down Expand Up @@ -180,6 +180,7 @@ impl SearchMatcher {
#[derive(Debug)]
pub struct CommitListState<'a> {
commits: Vec<CommitInfo<'a>>,
commit_hash_set: FxHashSet<&'a CommitHash>,
graph_image_manager: GraphImageManager<'a>,
graph_cell_width: u16,
head: &'a Head,
Expand Down Expand Up @@ -210,8 +211,10 @@ impl<'a> CommitListState<'a> {
default_fuzzy: bool,
) -> CommitListState<'a> {
let total = commits.len();
let commit_hash_set = commits.iter().map(|c| &c.commit.commit_hash).collect();
CommitListState {
commits,
commit_hash_set,
graph_image_manager,
graph_cell_width,
head,
Expand Down Expand Up @@ -242,8 +245,10 @@ impl<'a> CommitListState<'a> {

pub fn select_parent(&mut self) {
if let Some(target_commit) = self.selected_commit_parent_hash().cloned() {
while target_commit.as_str() != self.selected_commit_hash().as_str() {
self.select_next();
if self.commit_hash_set.contains(&target_commit) {
while target_commit.as_str() != self.selected_commit_hash().as_str() {
self.select_next();
}
}
}
}
Expand Down
32 changes: 26 additions & 6 deletions tests/graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,12 @@ fn branch_001() -> TestResult {
git::SortCommit::Chronological,
graph::GraphStyle::Angular,
),
GenerateGraphOption::new(
"branch_001_max_count",
git::SortCommit::Chronological,
graph::GraphStyle::Rounded,
)
.with_max_count(10),
];

copy_git_dir(repo_path, "branch_001");
Expand Down Expand Up @@ -195,6 +201,12 @@ fn branch_002() -> TestResult {
git::SortCommit::Chronological,
graph::GraphStyle::Angular,
),
GenerateGraphOption::new(
"branch_002_max_count",
git::SortCommit::Chronological,
graph::GraphStyle::Rounded,
)
.with_max_count(5),
];

copy_git_dir(repo_path, "branch_002");
Expand Down Expand Up @@ -1340,24 +1352,31 @@ fn parse_date(date: &str) -> DateTime<Utc> {
Utc.from_utc_datetime(&dt)
}

struct GenerateGraphOption<'a> {
output_name: &'a str,
struct GenerateGraphOption {
output_name: &'static str,
sort: git::SortCommit,
style: graph::GraphStyle,
max_count: Option<usize>,
}

impl GenerateGraphOption<'_> {
impl GenerateGraphOption {
fn new(
output_name: &str,
output_name: &'static str,
sort: git::SortCommit,
style: graph::GraphStyle,
) -> GenerateGraphOption<'_> {
) -> GenerateGraphOption {
GenerateGraphOption {
output_name,
sort,
style,
max_count: None,
}
}

fn with_max_count(mut self, max_count: usize) -> GenerateGraphOption {
self.max_count = Some(max_count);
self
}
}

fn generate_and_output_graph_images(repo_path: &Path, options: &[GenerateGraphOption]) {
Expand All @@ -1368,10 +1387,11 @@ fn generate_and_output_graph_images(repo_path: &Path, options: &[GenerateGraphOp

fn generate_and_output_graph_image<P: AsRef<Path>>(path: P, option: &GenerateGraphOption) {
// Build graphs in the same way as application
let max_count = option.max_count;
let graph_color_config = config::GraphColorConfig::default();
let graph_color_set = color::GraphColorSet::new(&graph_color_config);
let cell_width_type = graph::CellWidthType::Double;
let repository = git::Repository::load(path.as_ref(), option.sort).unwrap();
let repository = git::Repository::load(path.as_ref(), option.sort, max_count).unwrap();
let graph = graph::calc_graph(&repository);
let image_params = graph::ImageParams::new(&graph_color_set, cell_width_type);
let drawing_pixels = graph::DrawingPixels::new(&image_params);
Expand Down
Binary file added tests/graph/branch_001_max_count.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 tests/graph/branch_002_max_count.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.