1#[cfg(feature = "jj-parse")]
3#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
4pub enum WorkingCopy {
5 #[default]
6 Background,
7 Current,
8}
9
10#[cfg(feature = "jj-parse")]
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
13pub enum ConflictState {
14 #[default]
15 Clean,
16 Conflicted,
17}
18
19#[cfg(feature = "jj-parse")]
20impl ConflictState {
21 pub fn is_conflicted(self) -> bool {
22 matches!(self, Self::Conflicted)
23 }
24}
25
26#[cfg(feature = "jj-parse")]
28#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
29pub enum ContentState {
30 #[default]
31 HasContent,
32 Empty,
33}
34
35#[cfg(feature = "jj-parse")]
36impl ContentState {
37 pub fn is_empty(self) -> bool {
38 matches!(self, Self::Empty)
39 }
40}
41
42#[cfg(feature = "jj-parse")]
47#[derive(Debug, Clone)]
48pub struct LogEntry {
49 pub commit_id: String,
50 pub change_id: String,
51 pub author_name: String,
52 pub author_email: String,
53 pub description: String,
54 pub parents: Vec<String>,
55 pub local_bookmarks: Vec<String>,
56 pub remote_bookmarks: Vec<String>,
57 pub working_copy: WorkingCopy,
58 pub conflict: ConflictState,
59 pub content: ContentState,
60}
61
62#[cfg(feature = "jj-parse")]
63impl LogEntry {
64 pub fn summary(&self) -> &str {
66 self.description.lines().next().unwrap_or("")
67 }
68}
69
70#[cfg(feature = "jj-parse")]
72#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
73pub enum RemoteStatus {
74 Local,
76 Unsynced,
78 Synced,
80}
81
82#[cfg(feature = "jj-parse")]
83impl RemoteStatus {
84 pub fn has_remote(self) -> bool {
85 !matches!(self, Self::Local)
86 }
87
88 pub fn is_synced(self) -> bool {
89 matches!(self, Self::Synced)
90 }
91}
92
93#[cfg(feature = "jj-parse")]
95#[derive(Debug, Clone, PartialEq, Eq)]
96pub struct Bookmark {
97 pub name: String,
98 pub commit_id: String,
99 pub change_id: String,
100 pub remote: RemoteStatus,
101}
102
103#[cfg(feature = "jj-parse")]
105#[derive(Debug, Clone, PartialEq, Eq)]
106pub struct GitRemote {
107 pub name: String,
108 pub url: String,
109}
110
111#[cfg(all(test, feature = "jj-parse"))]
112mod tests {
113 use super::*;
114
115 #[test]
116 fn conflict_state() {
117 assert!(!ConflictState::Clean.is_conflicted());
118 assert!(ConflictState::Conflicted.is_conflicted());
119 }
120
121 #[test]
122 fn content_state() {
123 assert!(!ContentState::HasContent.is_empty());
124 assert!(ContentState::Empty.is_empty());
125 }
126
127 #[test]
128 fn working_copy_default() {
129 assert_eq!(WorkingCopy::default(), WorkingCopy::Background);
130 }
131
132 #[test]
133 fn remote_status_local() {
134 assert!(!RemoteStatus::Local.has_remote());
135 assert!(!RemoteStatus::Local.is_synced());
136 }
137
138 #[test]
139 fn remote_status_unsynced() {
140 assert!(RemoteStatus::Unsynced.has_remote());
141 assert!(!RemoteStatus::Unsynced.is_synced());
142 }
143
144 #[test]
145 fn remote_status_synced() {
146 assert!(RemoteStatus::Synced.has_remote());
147 assert!(RemoteStatus::Synced.is_synced());
148 }
149
150 #[test]
151 fn log_entry_summary() {
152 let entry = LogEntry {
153 commit_id: "abc".into(),
154 change_id: "xyz".into(),
155 author_name: "A".into(),
156 author_email: "a@b".into(),
157 description: "first line\nsecond line".into(),
158 parents: vec![],
159 local_bookmarks: vec![],
160 remote_bookmarks: vec![],
161 working_copy: WorkingCopy::Background,
162 conflict: ConflictState::Clean,
163 content: ContentState::HasContent,
164 };
165 assert_eq!(entry.summary(), "first line");
166 }
167
168 #[test]
169 fn log_entry_summary_empty_description() {
170 let entry = LogEntry {
171 commit_id: "abc".into(),
172 change_id: "xyz".into(),
173 author_name: "A".into(),
174 author_email: "a@b".into(),
175 description: String::new(),
176 parents: vec![],
177 local_bookmarks: vec![],
178 remote_bookmarks: vec![],
179 working_copy: WorkingCopy::Background,
180 conflict: ConflictState::Clean,
181 content: ContentState::HasContent,
182 };
183 assert_eq!(entry.summary(), "");
184 }
185}