1- use crate :: wrapper:: messages:: { Document , DocumentId } ;
1+ use crate :: wrapper:: messages:: { Document , DocumentId , PersistedDocumentInfo } ;
22
3+ // Wraps PersistedState (shared with the web frontend) and adds desktop-specific behavior like file I/O
34#[ derive( Default , serde:: Serialize , serde:: Deserialize ) ]
45pub ( crate ) struct PersistentData {
5- documents : DocumentStore ,
6+ documents : Vec < PersistedDocumentInfo > ,
67 current_document : Option < DocumentId > ,
78 #[ serde( skip) ]
89 document_order : Option < Vec < DocumentId > > ,
910}
1011
1112impl PersistentData {
1213 pub ( crate ) fn write_document ( & mut self , id : DocumentId , document : Document ) {
13- self . documents . write ( id, document) ;
14+ // Update or add the document metadata
15+ let info = PersistedDocumentInfo {
16+ id,
17+ name : document. name . clone ( ) ,
18+ path : document. path . clone ( ) ,
19+ is_saved : document. is_saved ,
20+ } ;
21+ if let Some ( existing) = self . documents . iter_mut ( ) . find ( |doc| doc. id == id) {
22+ * existing = info;
23+ } else {
24+ self . documents . push ( info) ;
25+ }
26+
27+ // Write the document content to a separate file
28+ if let Err ( e) = std:: fs:: write ( Self :: document_content_path ( & id) , document. content ) {
29+ tracing:: error!( "Failed to write document {id:?} to disk: {e}" ) ;
30+ }
31+
1432 if let Some ( order) = & self . document_order {
15- self . documents . force_order ( order) ;
33+ self . force_order ( order. clone ( ) ) ;
1634 }
1735 self . flush ( ) ;
1836 }
@@ -21,31 +39,35 @@ impl PersistentData {
2139 if Some ( * id) == self . current_document {
2240 self . current_document = None ;
2341 }
24- self . documents . delete ( id) ;
42+
43+ self . documents . retain ( |doc| doc. id != * id) ;
44+ if let Err ( e) = std:: fs:: remove_file ( Self :: document_content_path ( id) ) {
45+ tracing:: error!( "Failed to delete document {id:?} from disk: {e}" ) ;
46+ }
47+
2548 self . flush ( ) ;
2649 }
2750
2851 pub ( crate ) fn current_document_id ( & self ) -> Option < DocumentId > {
2952 match self . current_document {
3053 Some ( id) => Some ( id) ,
31- None => Some ( * self . documents . document_ids ( ) . first ( ) ?) ,
54+ None => Some ( self . documents . first ( ) ?. id ) ,
3255 }
3356 }
3457
3558 pub ( crate ) fn current_document ( & self ) -> Option < ( DocumentId , Document ) > {
3659 let current_id = self . current_document_id ( ) ?;
37- Some ( ( current_id, self . documents . read ( & current_id) ?) )
60+ Some ( ( current_id, self . read_document ( & current_id) ?) )
3861 }
3962
4063 pub ( crate ) fn documents_before_current ( & self ) -> Vec < ( DocumentId , Document ) > {
4164 let Some ( current_id) = self . current_document_id ( ) else {
4265 return Vec :: new ( ) ;
4366 } ;
4467 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) ?) ) )
68+ . iter ( )
69+ . take_while ( |doc| doc. id != current_id)
70+ . filter_map ( |doc| Some ( ( doc. id , self . read_document ( & doc. id ) ?) ) )
4971 . collect ( )
5072 }
5173
@@ -54,11 +76,10 @@ impl PersistentData {
5476 return Vec :: new ( ) ;
5577 } ;
5678 self . documents
57- . document_ids ( )
58- . into_iter ( )
59- . skip_while ( |id| * id != current_id)
79+ . iter ( )
80+ . skip_while ( |doc| doc. id != current_id)
6081 . skip ( 1 )
61- . filter_map ( |id | Some ( ( id, self . documents . read ( & id) ?) ) )
82+ . filter_map ( |doc | Some ( ( doc . id , self . read_document ( & doc . id ) ?) ) )
6283 . collect ( )
6384 }
6485
@@ -68,11 +89,37 @@ impl PersistentData {
6889 }
6990
7091 pub ( crate ) fn force_document_order ( & mut self , order : Vec < DocumentId > ) {
92+ self . force_order ( order. clone ( ) ) ;
7193 self . document_order = Some ( order) ;
72- self . documents . force_order ( self . document_order . as_ref ( ) . unwrap ( ) ) ;
7394 self . flush ( ) ;
7495 }
7596
97+ // Reads serialized document content from disk and combines it with the stored metadata
98+ fn read_document ( & self , id : & DocumentId ) -> Option < Document > {
99+ let info = self . documents . iter ( ) . find ( |doc| doc. id == * id) ?;
100+ let content = std:: fs:: read_to_string ( Self :: document_content_path ( id) ) . ok ( ) ?;
101+ Some ( Document {
102+ content,
103+ name : info. name . clone ( ) ,
104+ path : info. path . clone ( ) ,
105+ is_saved : info. is_saved ,
106+ } )
107+ }
108+
109+ // Reorders the documents array to match a desired ordering, keeping unmentioned documents at the end
110+ fn force_order ( & mut self , desired_order : Vec < DocumentId > ) {
111+ let mut ordered_prefix_length = 0 ;
112+ for id in & desired_order {
113+ if let Some ( offset) = self . documents [ ordered_prefix_length..] . iter ( ) . position ( |doc| doc. id == * id) {
114+ let found_index = ordered_prefix_length + offset;
115+ if found_index != ordered_prefix_length {
116+ self . documents [ ordered_prefix_length..=found_index] . rotate_right ( 1 ) ;
117+ }
118+ ordered_prefix_length += 1 ;
119+ }
120+ }
121+ }
122+
76123 fn flush ( & self ) {
77124 let data = match ron:: ser:: to_string_pretty ( self , Default :: default ( ) ) {
78125 Ok ( d) => d,
@@ -114,79 +161,10 @@ impl PersistentData {
114161 path. push ( crate :: consts:: APP_STATE_FILE_NAME ) ;
115162 path
116163 }
117- }
118-
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- }
133-
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- }
151164
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 ) ;
159- }
160- ordered_prefix_len += 1 ;
161- }
162- }
163- }
164-
165- fn document_ids ( & self ) -> Vec < DocumentId > {
166- self . 0 . iter ( ) . map ( |meta| meta. id ) . collect ( )
167- }
168-
169- fn document_path ( id : & DocumentId ) -> std:: path:: PathBuf {
165+ fn document_content_path ( id : & DocumentId ) -> std:: path:: PathBuf {
170166 let mut path = crate :: dirs:: app_autosave_documents_dir ( ) ;
171167 path. push ( format ! ( "{:x}.{}" , id. 0 , graphite_desktop_wrapper:: FILE_EXTENSION ) ) ;
172168 path
173169 }
174170}
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