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 get_current_commit() -> Option<String> {
let args: Vec<OsString> = vec![
"log".into(),
"-r".into(),
"@".into(),
"--no-pager".into(),
"-T".into(),
r#"{change_id.short()}"#.into(),
];
let output = Jj::system().output_if_available(args)?;
if !output.status.success() {
return None;
}
let commit = String::from_utf8_lossy(&output.stdout).trim().to_string();
if commit.is_empty() {
None
} else {
Some(commit)
}
}
fn get_current_description() -> Option<String> {
let args: Vec<OsString> = vec![
"log".into(),
"-r".into(),
"@".into(),
"--no-pager".into(),
"-T".into(),
r#"{description}"#.into(),
];
let output = Jj::system().output_if_available(args)?;
if !output.status.success() {
return None;
}
let description = String::from_utf8_lossy(&output.stdout).trim().to_string();
if description.is_empty() {
None
} else {
Some(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());
}
}