1- use crate :: wrapper:: messages:: { Document , DocumentId } ;
1+ use crate :: wrapper:: messages:: { Document , DocumentId , PersistedDocumentInfo } ;
22
33#[ derive( Default , serde:: Serialize , serde:: Deserialize ) ]
44pub ( crate ) struct PersistentData {
5- documents : DocumentStore ,
5+ documents : Vec < PersistedDocumentInfo > ,
66 current_document : Option < DocumentId > ,
77 #[ serde( skip) ]
88 document_order : Option < Vec < DocumentId > > ,
99}
1010
1111impl PersistentData {
1212 pub ( crate ) fn write_document ( & mut self , id : DocumentId , document : Document ) {
13- self . documents . write ( id, document) ;
14- if let Some ( order) = & self . document_order {
15- self . documents . force_order ( order) ;
13+ let info = PersistedDocumentInfo {
14+ id,
15+ name : document. name . clone ( ) ,
16+ path : document. path . clone ( ) ,
17+ is_saved : document. is_saved ,
18+ } ;
19+ if let Some ( existing) = self . documents . iter_mut ( ) . find ( |doc| doc. id == id) {
20+ * existing = info;
21+ } else {
22+ self . documents . push ( info) ;
23+ }
24+
25+ if let Err ( e) = std:: fs:: write ( Self :: document_content_path ( & id) , document. content ) {
26+ tracing:: error!( "Failed to write document {id:?} to disk: {e}" ) ;
1627 }
28+
1729 self . flush ( ) ;
1830 }
1931
2032 pub ( crate ) fn delete_document ( & mut self , id : & DocumentId ) {
2133 if Some ( * id) == self . current_document {
2234 self . current_document = None ;
2335 }
24- self . documents . delete ( id) ;
36+
37+ self . documents . retain ( |doc| doc. id != * id) ;
38+ if let Err ( e) = std:: fs:: remove_file ( Self :: document_content_path ( id) ) {
39+ tracing:: error!( "Failed to delete document {id:?} from disk: {e}" ) ;
40+ }
41+
2542 self . flush ( ) ;
2643 }
2744
2845 pub ( crate ) fn current_document_id ( & self ) -> Option < DocumentId > {
2946 match self . current_document {
3047 Some ( id) => Some ( id) ,
31- None => Some ( * self . documents . document_ids ( ) . first ( ) ?) ,
48+ None => Some ( self . documents . first ( ) ?. id ) ,
3249 }
3350 }
3451
35- pub ( crate ) fn current_document ( & self ) -> Option < ( DocumentId , Document ) > {
36- let current_id = self . current_document_id ( ) ?;
37- Some ( ( current_id, self . documents . read ( & current_id) ?) )
38- }
39-
40- pub ( crate ) fn documents_before_current ( & self ) -> Vec < ( DocumentId , Document ) > {
41- let Some ( current_id) = self . current_document_id ( ) else {
42- return Vec :: new ( ) ;
43- } ;
44- self . documents
45- . document_ids ( )
46- . into_iter ( )
47- . take_while ( |id| * id != current_id)
48- . filter_map ( |id| Some ( ( id, self . documents . read ( & id) ?) ) )
49- . collect ( )
50- }
51-
52- pub ( crate ) fn documents_after_current ( & self ) -> Vec < ( DocumentId , Document ) > {
53- let Some ( current_id) = self . current_document_id ( ) else {
54- return Vec :: new ( ) ;
55- } ;
56- self . documents
57- . document_ids ( )
58- . into_iter ( )
59- . skip_while ( |id| * id != current_id)
60- . skip ( 1 )
61- . filter_map ( |id| Some ( ( id, self . documents . read ( & id) ?) ) )
62- . collect ( )
52+ pub ( crate ) fn documents ( & self ) -> Vec < ( DocumentId , Document ) > {
53+ self . documents . iter ( ) . filter_map ( |doc| Some ( ( doc. id , self . read_document ( & doc. id ) ?) ) ) . collect ( )
6354 }
6455
6556 pub ( crate ) fn set_current_document ( & mut self , id : DocumentId ) {
@@ -68,11 +59,31 @@ impl PersistentData {
6859 }
6960
7061 pub ( crate ) fn force_document_order ( & mut self , order : Vec < DocumentId > ) {
62+ let mut ordered_prefix_length = 0 ;
63+ for id in & order {
64+ if let Some ( offset) = self . documents [ ordered_prefix_length..] . iter ( ) . position ( |doc| doc. id == * id) {
65+ let found_index = ordered_prefix_length + offset;
66+ if found_index != ordered_prefix_length {
67+ self . documents [ ordered_prefix_length..=found_index] . rotate_right ( 1 ) ;
68+ }
69+ ordered_prefix_length += 1 ;
70+ }
71+ }
7172 self . document_order = Some ( order) ;
72- self . documents . force_order ( self . document_order . as_ref ( ) . unwrap ( ) ) ;
7373 self . flush ( ) ;
7474 }
7575
76+ fn read_document ( & self , id : & DocumentId ) -> Option < Document > {
77+ let info = self . documents . iter ( ) . find ( |doc| doc. id == * id) ?;
78+ let content = std:: fs:: read_to_string ( Self :: document_content_path ( id) ) . ok ( ) ?;
79+ Some ( Document {
80+ content,
81+ name : info. name . clone ( ) ,
82+ path : info. path . clone ( ) ,
83+ is_saved : info. is_saved ,
84+ } )
85+ }
86+
7687 fn flush ( & self ) {
7788 let data = match ron:: ser:: to_string_pretty ( self , Default :: default ( ) ) {
7889 Ok ( d) => d,
@@ -107,86 +118,42 @@ impl PersistentData {
107118 }
108119 } ;
109120 * self = loaded;
110- }
111121
112- fn state_file_path ( ) -> std:: path:: PathBuf {
113- let mut path = crate :: dirs:: app_data_dir ( ) ;
114- path. push ( crate :: consts:: APP_STATE_FILE_NAME ) ;
115- path
122+ self . garbage_collect_document_files ( ) ;
116123 }
117- }
118124
119- #[ derive( Default , serde:: Serialize , serde:: Deserialize ) ]
120- struct DocumentStore ( Vec < DocumentInfo > ) ;
121- impl DocumentStore {
122- fn write ( & mut self , id : DocumentId , document : Document ) {
123- let meta = DocumentInfo :: new ( id, & document) ;
124- if let Some ( existing) = self . 0 . iter_mut ( ) . find ( |meta| meta. id == id) {
125- * existing = meta;
126- } else {
127- self . 0 . push ( meta) ;
128- }
129- if let Err ( e) = std:: fs:: write ( Self :: document_path ( & id) , document. content ) {
130- tracing:: error!( "Failed to write document {id:?} to disk: {e}" ) ;
131- }
132- }
125+ fn garbage_collect_document_files ( & self ) {
126+ let valid_paths: std:: collections:: HashSet < _ > = self . documents . iter ( ) . map ( |doc| Self :: document_content_path ( & doc. id ) ) . collect ( ) ;
133127
134- fn delete ( & mut self , id : & DocumentId ) {
135- self . 0 . retain ( |meta| meta. id != * id) ;
136- if let Err ( e) = std:: fs:: remove_file ( Self :: document_path ( id) ) {
137- tracing:: error!( "Failed to delete document {id:?} from disk: {e}" ) ;
138- }
139- }
140-
141- fn read ( & self , id : & DocumentId ) -> Option < Document > {
142- let meta = self . 0 . iter ( ) . find ( |meta| meta. id == * id) ?;
143- let content = std:: fs:: read_to_string ( Self :: document_path ( id) ) . ok ( ) ?;
144- Some ( Document {
145- content,
146- name : meta. name . clone ( ) ,
147- path : meta. path . clone ( ) ,
148- is_saved : meta. is_saved ,
149- } )
150- }
128+ let directory = crate :: dirs:: app_autosave_documents_dir ( ) ;
129+ let entries = match std:: fs:: read_dir ( & directory) {
130+ Ok ( entries) => entries,
131+ Err ( e) if e. kind ( ) == std:: io:: ErrorKind :: NotFound => return ,
132+ Err ( e) => {
133+ tracing:: error!( "Failed to read autosave documents directory: {e}" ) ;
134+ return ;
135+ }
136+ } ;
151137
152- fn force_order ( & mut self , desired_order : & [ DocumentId ] ) {
153- let mut ordered_prefix_len = 0 ;
154- for id in desired_order {
155- if let Some ( offset) = self . 0 [ ordered_prefix_len..] . iter ( ) . position ( |meta| meta. id == * id) {
156- let found_index = ordered_prefix_len + offset;
157- if found_index != ordered_prefix_len {
158- self . 0 [ ordered_prefix_len..=found_index] . rotate_right ( 1 ) ;
138+ for entry in entries. flatten ( ) {
139+ let path = entry. path ( ) ;
140+ if path. is_file ( ) && !valid_paths. contains ( & path) {
141+ if let Err ( e) = std:: fs:: remove_file ( & path) {
142+ tracing:: error!( "Failed to remove orphaned document file {path:?}: {e}" ) ;
159143 }
160- ordered_prefix_len += 1 ;
161144 }
162145 }
163146 }
164147
165- fn document_ids ( & self ) -> Vec < DocumentId > {
166- self . 0 . iter ( ) . map ( |meta| meta. id ) . collect ( )
148+ fn state_file_path ( ) -> std:: path:: PathBuf {
149+ let mut path = crate :: dirs:: app_data_dir ( ) ;
150+ path. push ( crate :: consts:: APP_STATE_FILE_NAME ) ;
151+ path
167152 }
168153
169- fn document_path ( id : & DocumentId ) -> std:: path:: PathBuf {
154+ fn document_content_path ( id : & DocumentId ) -> std:: path:: PathBuf {
170155 let mut path = crate :: dirs:: app_autosave_documents_dir ( ) ;
171156 path. push ( format ! ( "{:x}.{}" , id. 0 , graphite_desktop_wrapper:: FILE_EXTENSION ) ) ;
172157 path
173158 }
174159}
175-
176- #[ derive( serde:: Serialize , serde:: Deserialize ) ]
177- struct DocumentInfo {
178- id : DocumentId ,
179- name : String ,
180- path : Option < std:: path:: PathBuf > ,
181- is_saved : bool ,
182- }
183- impl DocumentInfo {
184- fn new ( id : DocumentId , Document { name, path, is_saved, .. } : & Document ) -> Self {
185- Self {
186- id,
187- name : name. clone ( ) ,
188- path : path. clone ( ) ,
189- is_saved : * is_saved,
190- }
191- }
192- }
0 commit comments