1use std::path::PathBuf;
2
3use crate::{Candidate, CandidateMetadata};
4
5#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
6pub enum PreviewKey {
7 Session(String),
8 Directory(PathBuf),
9 File(PathBuf),
10 Metadata(String),
11}
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14pub enum PreviewKind {
15 SessionSummary,
16 Directory,
17 File,
18 Metadata,
19}
20
21#[derive(Debug, Clone, PartialEq, Eq)]
22pub enum PreviewRequest {
23 SessionSummary {
24 key: PreviewKey,
25 session_name: String,
26 },
27 Directory {
28 key: PreviewKey,
29 path: PathBuf,
30 },
31 File {
32 key: PreviewKey,
33 path: PathBuf,
34 },
35 Metadata {
36 key: PreviewKey,
37 title: String,
38 },
39}
40
41impl PreviewRequest {
42 #[must_use]
43 pub fn key(&self) -> &PreviewKey {
44 match self {
45 Self::SessionSummary { key, .. }
46 | Self::Directory { key, .. }
47 | Self::File { key, .. }
48 | Self::Metadata { key, .. } => key,
49 }
50 }
51
52 #[must_use]
53 pub fn kind(&self) -> PreviewKind {
54 match self {
55 Self::SessionSummary { .. } => PreviewKind::SessionSummary,
56 Self::Directory { .. } => PreviewKind::Directory,
57 Self::File { .. } => PreviewKind::File,
58 Self::Metadata { .. } => PreviewKind::Metadata,
59 }
60 }
61}
62
63#[derive(Debug, Clone, PartialEq, Eq)]
64pub struct PreviewContent {
65 pub title: String,
66 pub body: Vec<String>,
67 pub truncated: bool,
68}
69
70impl PreviewContent {
71 #[must_use]
72 pub fn from_text(title: impl Into<String>, text: impl AsRef<str>, max_lines: usize) -> Self {
73 let mut body = text
74 .as_ref()
75 .lines()
76 .take(max_lines)
77 .map(ToOwned::to_owned)
78 .collect::<Vec<_>>();
79 let truncated = text.as_ref().lines().count() > max_lines;
80
81 if body.is_empty() {
82 body.push(String::new());
83 }
84
85 Self {
86 title: title.into(),
87 body,
88 truncated,
89 }
90 }
91
92 #[must_use]
93 pub fn from_text_tail(
94 title: impl Into<String>,
95 text: impl AsRef<str>,
96 max_lines: usize,
97 ) -> Self {
98 let lines = text
99 .as_ref()
100 .lines()
101 .map(ToOwned::to_owned)
102 .collect::<Vec<_>>();
103 let truncated = lines.len() > max_lines;
104 let start = lines.len().saturating_sub(max_lines);
105 let mut body = lines.into_iter().skip(start).collect::<Vec<_>>();
106
107 if body.is_empty() {
108 body.push(String::new());
109 }
110
111 Self {
112 title: title.into(),
113 body,
114 truncated,
115 }
116 }
117}
118
119#[must_use]
120pub fn preview_request_for_candidate(candidate: &Candidate) -> PreviewRequest {
121 match &candidate.metadata {
122 CandidateMetadata::Session(metadata) => PreviewRequest::SessionSummary {
123 key: candidate.preview_key.clone(),
124 session_name: metadata.session_name.clone(),
125 },
126 CandidateMetadata::Directory(metadata) => PreviewRequest::Directory {
127 key: candidate.preview_key.clone(),
128 path: metadata.full_path.clone(),
129 },
130 CandidateMetadata::Window(metadata) => PreviewRequest::Metadata {
131 key: candidate.preview_key.clone(),
132 title: format!("{}:{}", metadata.session_name, metadata.index),
133 },
134 CandidateMetadata::Project(metadata) => PreviewRequest::Directory {
135 key: candidate.preview_key.clone(),
136 path: metadata.root.clone(),
137 },
138 CandidateMetadata::Worktree(metadata) => PreviewRequest::Directory {
139 key: candidate.preview_key.clone(),
140 path: metadata.full_path.clone(),
141 },
142 }
143}
144
145#[cfg(test)]
146mod tests {
147 use std::path::PathBuf;
148
149 use crate::{
150 Candidate, PreviewKey, PreviewRequest, WorktreeMetadata, preview_request_for_candidate,
151 };
152
153 #[test]
154 fn maps_worktree_candidates_to_directory_previews_using_full_path() {
155 let full_path = PathBuf::from("/tmp/demo-worktree");
156 let candidate = Candidate::worktree(WorktreeMetadata {
157 full_path: full_path.clone(),
158 display_path: "~/demo-worktree".to_string(),
159 branch: Some("feature/demo".to_string()),
160 });
161
162 let request = preview_request_for_candidate(&candidate);
163
164 assert_eq!(
165 request,
166 PreviewRequest::Directory {
167 key: PreviewKey::Directory(full_path.clone()),
168 path: full_path,
169 }
170 );
171 }
172}