use super::id::{ChangeId, CommitId};
#[derive(Debug, Clone)]
pub struct AnnotationLine {
pub change_id: ChangeId,
pub commit_id: CommitId,
pub author: String,
pub timestamp: String,
pub line_number: usize,
pub content: String,
pub first_in_hunk: bool,
}
#[derive(Debug, Clone, Default)]
pub struct AnnotationContent {
pub file_path: String,
pub lines: Vec<AnnotationLine>,
}
impl AnnotationContent {
pub fn new(file_path: String) -> Self {
Self {
file_path,
lines: Vec::new(),
}
}
pub fn is_empty(&self) -> bool {
self.lines.is_empty()
}
pub fn len(&self) -> usize {
self.lines.len()
}
}
impl AnnotationLine {
pub fn short_timestamp(&self) -> String {
if self.timestamp.len() >= 10 {
let date_part = &self.timestamp[..10]; if date_part.len() >= 10 {
return date_part[5..10].to_string(); }
}
self.timestamp.clone()
}
pub fn short_author(&self, max_len: usize) -> String {
if self.author.chars().count() <= max_len {
self.author.clone()
} else {
self.author.chars().take(max_len - 1).collect::<String>() + "…"
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_annotation_content_new() {
let content = AnnotationContent::new("src/main.rs".to_string());
assert_eq!(content.file_path, "src/main.rs");
assert!(content.is_empty());
}
#[test]
fn test_annotation_line_short_timestamp() {
let line = AnnotationLine {
change_id: ChangeId::new("twzksoxt".to_string()),
commit_id: CommitId::new("abcd1234".to_string()),
author: "nakamura".to_string(),
timestamp: "2026-01-30 10:43".to_string(),
line_number: 1,
content: "test".to_string(),
first_in_hunk: true,
};
assert_eq!(line.short_timestamp(), "01-30");
}
#[test]
fn test_annotation_line_short_author() {
let line = AnnotationLine {
change_id: ChangeId::new("twzksoxt".to_string()),
commit_id: CommitId::new("abcd1234".to_string()),
author: "nakamura.shuta".to_string(),
timestamp: "2026-01-30 10:43".to_string(),
line_number: 1,
content: "test".to_string(),
first_in_hunk: true,
};
assert_eq!(line.short_author(8), "nakamur…");
assert_eq!(line.short_author(20), "nakamura.shuta");
}
}