diff --git a/README.md b/README.md index 2a2dd6f..a2c8d50 100644 --- a/README.md +++ b/README.md @@ -69,6 +69,7 @@ Serie - A rich git commit graph in your terminal, like magic 📚 Usage: serie [OPTIONS] Options: + -n, --max-count Maximum number of commits to render -p, --protocol Image protocol to render graph [default: auto] [possible values: auto, iterm, kitty] -o, --order Commit ordering algorithm [default: chrono] [possible values: chrono, topo] -g, --graph-width Commit graph image cell width [default: auto] [possible values: auto, double, single] diff --git a/docs/src/getting-started/command-line-options.md b/docs/src/getting-started/command-line-options.md index c792cf3..c378415 100644 --- a/docs/src/getting-started/command-line-options.md +++ b/docs/src/getting-started/command-line-options.md @@ -1,5 +1,12 @@ # Command Line Options +## -n, --max-count \ + +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 \ A protocol type for rendering images of commit graphs. diff --git a/src/git.rs b/src/git.rs index dca8e68..713ce57 100644 --- a/src/git.rs +++ b/src/git.rs @@ -124,11 +124,11 @@ pub struct Repository { } impl Repository { - pub fn load(path: &Path, sort: SortCommit) -> Result { + pub fn load(path: &Path, sort: SortCommit, max_count: Option) -> Result { 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(); @@ -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 { +fn load_all_commits( + path: &Path, + sort: SortCommit, + stashes: &[Commit], + max_count: Option, +) -> Vec { let mut cmd = Command::new("git"); cmd.arg("log"); @@ -271,6 +276,10 @@ fn load_all_commits(path: &Path, sort: SortCommit, stashes: &[Commit]) -> Vec, + /// Image protocol to render graph [default: auto] #[arg(short, long, value_name = "TYPE")] protocol: Option, @@ -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); @@ -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); diff --git a/src/widget/commit_list.rs b/src/widget/commit_list.rs index 1391c48..8222621 100644 --- a/src/widget/commit_list.rs +++ b/src/widget/commit_list.rs @@ -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::{ @@ -180,6 +180,7 @@ impl SearchMatcher { #[derive(Debug)] pub struct CommitListState<'a> { commits: Vec>, + commit_hash_set: FxHashSet<&'a CommitHash>, graph_image_manager: GraphImageManager<'a>, graph_cell_width: u16, head: &'a Head, @@ -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, @@ -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(); + } } } } diff --git a/tests/graph.rs b/tests/graph.rs index ca3b0ab..2b1d65d 100644 --- a/tests/graph.rs +++ b/tests/graph.rs @@ -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"); @@ -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"); @@ -1340,24 +1352,31 @@ fn parse_date(date: &str) -> DateTime { 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, } -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]) { @@ -1368,10 +1387,11 @@ fn generate_and_output_graph_images(repo_path: &Path, options: &[GenerateGraphOp fn generate_and_output_graph_image>(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); diff --git a/tests/graph/branch_001_max_count.png b/tests/graph/branch_001_max_count.png new file mode 100644 index 0000000..5c0bdfa Binary files /dev/null and b/tests/graph/branch_001_max_count.png differ diff --git a/tests/graph/branch_002_max_count.png b/tests/graph/branch_002_max_count.png new file mode 100644 index 0000000..7cca82e Binary files /dev/null and b/tests/graph/branch_002_max_count.png differ