From: Simon Tatham Date: Sat, 6 Jan 2024 13:10:33 +0000 (+0000) Subject: Save an "ldb" file in the config directory. X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ian/git?a=commitdiff_plain;h=4862e4a92a28a9319a66a82c9daadff8da87982e;p=mastodonochrome.git Save an "ldb" file in the config directory. This is updated whenever we exit a File. I think that's a reasonable balance between updating it on every single press of Space when paging through the file (excessive disk churn), and waiting until the whole client exits (excessive risk of forgetting to save it at all). Perhaps an even better idea would be to schedule a timer to checkpoint the LDB every few minutes if it had changed. --- diff --git a/TODO.md b/TODO.md index 6e511e2..df7f094 100644 --- a/TODO.md +++ b/TODO.md @@ -26,6 +26,7 @@ This is already marked in the code with multiple FIXMEs: * errors in `get_user_to_examine` and `get_post_id_to_read`, although again if it's just 'no such thing' then the Error Log is overkill. Should only be for 'help, the server is totally confused'. +* errors in `save_ldb` Each of those should instead catch the error, make an Error Log record, and transfer you to the error-log viewer with a beep, just the diff --git a/src/config.rs b/src/config.rs index 5c6cc29..d60ed4f 100644 --- a/src/config.rs +++ b/src/config.rs @@ -55,6 +55,7 @@ impl From for ConfigError { } } +#[derive(Clone)] pub struct ConfigLocation { dir: PathBuf, } diff --git a/src/file.rs b/src/file.rs index b49c417..8110e0f 100644 --- a/src/file.rs +++ b/src/file.rs @@ -1308,19 +1308,16 @@ impl } } - fn save_file_position( - &self, file_positions: &mut HashMap) - { - if let Some(id) = self.file_desc.feed_id() { + fn save_file_position(&self) -> Option<(FeedId, SavedFilePos)> { + self.file_desc.feed_id().map(|id| { let sfp = SavedFilePos { file_pos: Some(self.pos), latest_read_id: self.latest_read_index .and_then(|i| self.contents.id_at_index(i)) .map(|s| s.to_owned()), }; - file_positions.insert(id.clone(), sfp); - todo!(); - } + (id.clone(), sfp) + }) } fn got_search_expression(&mut self, dir: SearchDirection, regex: String) diff --git a/src/tui.rs b/src/tui.rs index bdac95a..16a7236 100644 --- a/src/tui.rs +++ b/src/tui.rs @@ -11,7 +11,7 @@ use ratatui::{ style::{Style, Color, Modifier}, }; use std::cmp::min; -use std::collections::{HashMap, HashSet}; +use std::collections::{BTreeMap, HashMap, HashSet}; use std::io::{Stdout, Write, stdout}; use std::fs::File; use unicode_width::UnicodeWidthStr; @@ -160,6 +160,7 @@ pub enum OurKey { PgUp, PgDn, Home, End, Ins, Del, } +#[derive(Debug)] pub struct TuiError { message: String, } @@ -195,6 +196,13 @@ impl From for TuiError { } } } +impl From for TuiError { + fn from(err: serde_json::Error) -> Self { + TuiError { + message: err.to_string(), + } + } +} impl std::fmt::Display for TuiError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> @@ -231,7 +239,7 @@ impl Tui { let mut terminal = Terminal::new(CrosstermBackend::new(stdout()))?; terminal.clear()?; - let state = TuiLogicalState::new(&client); + let state = TuiLogicalState::new(&client, cfgloc.clone()); let mut tui = Tui { terminal, @@ -429,6 +437,7 @@ pub enum LogicalAction { PostReEdit(Post), } +#[derive(PartialEq, Eq, Debug, Clone)] pub struct SavedFilePos { // The current position we're _looking at_ within the file, within // this run @@ -453,8 +462,7 @@ pub trait ActivityState { LogicalAction; fn handle_feed_updates(&mut self, _feeds_updated: &HashSet, _client: &mut Client) {} - fn save_file_position( - &self, _file_positions: &mut HashMap) {} + fn save_file_position(&self) -> Option<(FeedId, SavedFilePos)> { None } fn got_search_expression(&mut self, _dir: SearchDirection, _regex: String) -> LogicalAction { @@ -468,10 +476,11 @@ struct TuiLogicalState { overlay_activity_state: Option>, last_area: Option, file_positions: HashMap, + cfgloc: ConfigLocation, } impl TuiLogicalState { - fn new(client: &Client) -> Self { + fn new(client: &Client, cfgloc: ConfigLocation) -> Self { let activity_stack = ActivityStack::new(); let activity_state = main_menu(client); @@ -481,6 +490,7 @@ impl TuiLogicalState { overlay_activity_state: None, last_area: None, file_positions: HashMap::new(), + cfgloc, } } @@ -638,7 +648,17 @@ impl TuiLogicalState { } fn changed_activity(&mut self, client: &mut Client, post: Option) { - self.activity_state.save_file_position(&mut self.file_positions); + if let Some((feed_id, saved_pos)) = + self.activity_state.save_file_position() + { + let changed = self.file_positions.get(&feed_id) != Some(&saved_pos); + self.file_positions.insert(feed_id, saved_pos); + if changed { + // FIXME: maybe suddenly change our mind and go to the + // Error Log + self.save_ldb().unwrap(); + } + } self.activity_state = self.new_activity_state( self.activity_stack.top(), client, post); self.overlay_activity_state = match self.activity_stack.overlay() { @@ -733,4 +753,30 @@ impl TuiLogicalState { result.expect("FIXME: need to implement the Error Log here") } + + fn save_ldb(&self) -> Result<(), TuiError> { + let mut ldb = BTreeMap::new(); + for (key, value) in &self.file_positions { + let keystr = match key { + FeedId::Home => "home".to_owned(), + FeedId::Mentions => "mentions".to_owned(), + FeedId::Ego => "ego".to_owned(), + + // For all other feeds, we don't persist the last-read + // position. + _ => continue, + }; + + let valstr = match &value.latest_read_id { + Some(s) => s.clone(), + None => continue, + }; + + ldb.insert(keystr, valstr); + } + let mut json = serde_json::to_string_pretty(&ldb)?; + json.push('\n'); + self.cfgloc.create_file("ldb", &json)?; + Ok(()) + } }