use serde::{Deserialize, Serialize};
use std::ffi::OsString;
use crate::plugins::NamedTool;
use crate::plugins::binaries::Jj;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct JjStatus {
pub branch: String,
pub commit: String,
pub description: String,
}
pub fn get_status() -> Option<JjStatus> {
if !is_jj_repo() {
return None;
}
let branch = get_branch()?;
let commit = get_current_commit()?;
let description = get_current_description()?;
Some(JjStatus {
branch,
commit,
description,
})
}
pub fn get_recent_commits(count: usize) -> Option<Vec<String>> {
if !is_jj_repo() {
return None;
}
let args: Vec<OsString> = vec![
"log".into(),
"--no-pager".into(),
"-r".into(),
"main..".into(),
"-n".into(),
count.to_string().into(),
"-T".into(),
r#"description.first_line()"#.into(),
];
let output = Jj::system().output_if_available(args)?;
if !output.status.success() {
return None;
}
let output_str = String::from_utf8_lossy(&output.stdout);
let commits: Vec<String> = output_str
.lines()
.filter(|line| !line.is_empty())
.map(|line| line.trim().to_string())
.collect();
if commits.is_empty() {
None
} else {
Some(commits)
}
}
fn is_jj_repo() -> bool {
std::path::Path::new(".jj").exists()
}
fn get_branch() -> Option<String> {
let output =
Jj::system().output_if_available(vec!["branch".into(), "list".into(), "-q".into()])?;
if !output.status.success() {
return None;
}
let branch = String::from_utf8_lossy(&output.stdout).trim().to_string();
if branch.is_empty() {
None
} else {
Some(branch)
}
}
fn jj_log_current(template: &str) -> Option<String> {
let args: Vec<OsString> = vec![
"log".into(),
"-r".into(),
"@".into(),
"--no-pager".into(),
"-T".into(),
template.into(),
];
let output = Jj::system().output_if_available(args)?;
if !output.status.success() {
return None;
}
let text = String::from_utf8_lossy(&output.stdout).trim().to_string();
if text.is_empty() { None } else { Some(text) }
}
fn get_current_commit() -> Option<String> {
jj_log_current(r#"{change_id.short()}"#)
}
fn get_current_description() -> Option<String> {
jj_log_current(r#"{description}"#)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_jj_repo_detection() {
assert!(!is_jj_repo());
}
#[test]
fn test_get_status_no_jj_repo() {
let status = get_status();
assert!(status.is_none());
}
#[test]
fn test_get_recent_commits_no_jj_repo() {
let commits = get_recent_commits(5);
assert!(commits.is_none());
}
}