gitv_tui/bookmarks/
mod.rs1use std::{
2 collections::{HashMap, HashSet},
3 io::Write,
4 path::PathBuf,
5 sync::OnceLock,
6};
7
8use serde::{Deserialize, Serialize};
9
10use crate::logging::{DATA_FOLDER, project_directory};
11
12pub static BOOKMARKS_DIR: OnceLock<PathBuf> = OnceLock::new();
13
14#[derive(Serialize, Deserialize, Debug, Default)]
15pub struct Bookmarks(HashMap<String, HashSet<u64>>);
16
17impl Bookmarks {
18 pub fn add(&mut self, owner: &str, repo: &str, issue_number: u64) {
19 let key = format!("{}/{}", owner, repo);
20 self.0.entry(key).or_default().insert(issue_number);
21 }
22
23 pub fn remove(&mut self, owner: &str, repo: &str, issue_number: u64) {
24 let key = format!("{}/{}", owner, repo);
25 if let Some(issues) = self.0.get_mut(&key) {
26 issues.remove(&issue_number);
27 if issues.is_empty() {
28 self.0.remove(&key);
29 }
30 }
31 }
32
33 pub fn is_bookmarked(&self, owner: &str, repo: &str, issue_number: u64) -> bool {
34 let key = format!("{}/{}", owner, repo);
35 self.0
36 .get(&key)
37 .is_some_and(|issues| issues.contains(&issue_number))
38 }
39
40 pub fn get_bookmarked_issues(&self, owner: &str, repo: &str) -> Vec<u64> {
41 let key = format!("{}/{}", owner, repo);
42 self.0
43 .get(&key)
44 .map_or(vec![], |issues| issues.iter().cloned().collect())
45 }
46
47 pub fn write(&self, buf: &mut impl Write) -> std::io::Result<()> {
48 let path = get_bookmarks_file();
49 if let Some(parent) = path.parent() {
50 std::fs::create_dir_all(parent)?;
51 }
52 let contents = serde_json::to_vec(self)?;
53 buf.write_all(&contents)
54 }
55
56 pub fn write_to_file(&self) -> std::io::Result<()> {
57 let path = get_bookmarks_file();
58 if let Some(parent) = path.parent() {
59 std::fs::create_dir_all(parent)?;
60 }
61 let contents = serde_json::to_vec(self)?;
62 std::fs::write(path, contents)
63 }
64}
65
66fn get_bookmarks_file() -> &'static PathBuf {
67 BOOKMARKS_DIR.get_or_init(|| {
68 let bdir = if let Some(s) = DATA_FOLDER.clone() {
69 s
70 } else if let Some(proj_dirs) = project_directory() {
71 proj_dirs.data_local_dir().to_path_buf()
72 } else {
73 PathBuf::from(".").join(".data")
74 };
75 bdir.join("bookmarks/bookmarks.json")
76 })
77}
78
79pub fn read_bookmarks() -> Bookmarks {
80 let path = get_bookmarks_file();
81 if let Ok(contents) = std::fs::read_to_string(path) {
82 serde_json::from_str(&contents).unwrap_or_default()
83 } else {
84 Bookmarks::default()
85 }
86}