diff --git a/Cargo.toml b/Cargo.toml index 8dee0eb..f6af93e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -83,11 +83,13 @@ mockall = "0.12" wiremock = "0.6" [profile.release] -opt-level = 3 -lto = true -codegen-units = 1 +opt-level = "s" +lto = "thin" +codegen-units = 2 +panic = "abort" strip = true +debug = false [profile.dev] -opt-level = 0 +opt-level = 1 debug = true diff --git a/src/generator/mod.rs b/src/generator/mod.rs index f0ce494..32de3cc 100644 --- a/src/generator/mod.rs +++ b/src/generator/mod.rs @@ -47,7 +47,7 @@ impl ContentGenerator { format: CommitFormat, language: Language, ) -> Result { - let diff = repo.get_staged_diff() + let diff = repo.get_staged_diff_sorted() .context("Failed to get staged diff")?; if diff.is_empty() { @@ -116,7 +116,7 @@ impl ContentGenerator { ) -> Result { use dialoguer::Select; - let diff = repo.get_staged_diff()?; + let diff = repo.get_staged_diff_sorted()?; if diff.is_empty() { anyhow::bail!("No staged changes"); diff --git a/src/git/mod.rs b/src/git/mod.rs index 7198fa7..2d92ce6 100644 --- a/src/git/mod.rs +++ b/src/git/mod.rs @@ -346,6 +346,119 @@ impl GitRepo { Ok(diff_text) } + /// Get staged diff with files sorted by importance + /// Important files (source code) come first, then config files like Cargo.toml, + /// then lock files like Cargo.lock + pub fn get_staged_diff_sorted(&self) -> Result { + let diff = self.get_staged_diff()?; + + if diff.is_empty() { + return Ok(diff); + } + + let mut file_diffs = Vec::new(); + let mut current_file_diff = String::new(); + let mut current_file = String::new(); + + for line in diff.lines() { + if line.starts_with("diff --git") { + // Save previous file diff if any + if !current_file_diff.is_empty() && !current_file.is_empty() { + file_diffs.push((current_file.clone(), current_file_diff.clone())); + } + current_file = extract_file_from_diff_line(line); + current_file_diff = format!("{}\n", line); + } else { + current_file_diff.push_str(line); + current_file_diff.push('\n'); + } + } + + // Add the last file diff + if !current_file_diff.is_empty() && !current_file.is_empty() { + file_diffs.push((current_file, current_file_diff)); + } + + // Sort by file importance + file_diffs.sort_by(|a, b| { + let score_a = file_importance_score(&a.0); + let score_b = file_importance_score(&b.0); + score_b.cmp(&score_a) // Descending order + }); + + // Combine sorted diffs + let sorted_diff: String = file_diffs.into_iter() + .map(|(_, diff)| diff) + .collect(); + + Ok(sorted_diff) + } +} + +/// Extract filename from diff --git line +fn extract_file_from_diff_line(line: &str) -> String { + // Format: "diff --git a/path/to/file b/path/to/file" + let parts: Vec<&str> = line.split_whitespace().collect(); + if parts.len() >= 3 { + // Return the second path (after b/) + if let Some(path) = parts[2].strip_prefix("b/") { + return path.to_string(); + } + // Fallback to first path (after a/) + if let Some(path) = parts[1].strip_prefix("a/") { + return path.to_string(); + } + } + line.to_string() +} + +/// Calculate file importance score +/// Higher score = more important +fn file_importance_score(filename: &str) -> i32 { + // Priority list for important file types + let important_extensions = [ + ".rs", ".py", ".js", ".ts", ".tsx", ".jsx", ".go", ".java", ".cpp", ".c", ".rust", + ".vue", ".svelte", ".html", ".css", ".scss", ".sass", ".less", + ]; + + // Config files that are important but less than source code + let config_files = [ + "Cargo.toml", "package.json", "go.mod", "go.sum", "pom.xml", + "Makefile", "CMakeLists.txt", "build.gradle", "gradle.properties", + ]; + + // Lock files - lowest priority + let lock_files = [ + "Cargo.lock", "package-lock.json", "yarn.lock", "pnpm-lock.yaml", + "Gemfile.lock", "composer.lock", + ]; + + // Check lock files first (lowest priority) + for lock in lock_files.iter() { + if filename.ends_with(lock) { + return 1; + } + } + + // Check config files (medium priority) + for config in config_files.iter() { + if filename.ends_with(config) { + return 2; + } + } + + // Check important source files (highest priority) + for ext in important_extensions.iter() { + if filename.ends_with(ext) { + return 3; + } + } + + // Default priority for other files + 2 +} + +impl GitRepo { /// Get unstaged diff pub fn get_unstaged_diff(&self) -> Result { let diff = self.repo.diff_index_to_workdir(None, None)?;