Skip to main content

gitv_tui/bookmarks/
mod.rs

1use 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}