Skip to content

Commit 37074a1

Browse files
psuongKeavon
authored andcommitted
id-based-docs (#376)
* Added some notes on what ds to use for the documents. * Added a separate list of ids to associate ID to doc. Looks up all documents by id to retrieve an index via linear search. * Fixed function name. * Removed id recycling, replaced document vector with hashmap. * Uses the same logic for PrevDocument in closing
1 parent d0e65e2 commit 37074a1

File tree

1 file changed

+72
-67
lines changed

1 file changed

+72
-67
lines changed

editor/src/document/document_message_handler.rs

Lines changed: 72 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,8 @@ use crate::message_prelude::*;
33
use graphene::layers::Layer;
44
use graphene::{LayerId, Operation as DocumentOperation};
55
use log::warn;
6-
76
use serde::{Deserialize, Serialize};
8-
use std::collections::VecDeque;
7+
use std::collections::{HashMap, VecDeque};
98

109
use super::DocumentMessageHandler;
1110
use crate::consts::DEFAULT_DOCUMENT_NAME;
@@ -36,28 +35,37 @@ pub enum DocumentsMessage {
3635

3736
#[derive(Debug, Clone)]
3837
pub struct DocumentsMessageHandler {
39-
documents: Vec<DocumentMessageHandler>,
38+
documents: HashMap<u64, DocumentMessageHandler>,
39+
document_ids: Vec<u64>,
40+
document_id_counter: u64,
4041
active_document_index: usize,
4142
copy_buffer: Vec<Layer>,
4243
}
4344

4445
impl DocumentsMessageHandler {
4546
pub fn active_document(&self) -> &DocumentMessageHandler {
46-
&self.documents[self.active_document_index]
47+
let id = self.document_ids[self.active_document_index];
48+
self.documents.get(&id).unwrap()
4749
}
50+
4851
pub fn active_document_mut(&mut self) -> &mut DocumentMessageHandler {
49-
&mut self.documents[self.active_document_index]
52+
let id = self.document_ids[self.active_document_index];
53+
self.documents.get_mut(&id).unwrap()
5054
}
55+
5156
fn generate_new_document_name(&self) -> String {
5257
let mut doc_title_numbers = self
53-
.documents
58+
.document_ids
5459
.iter()
55-
.filter_map(|d| {
56-
d.name
60+
.filter_map(|id| self.documents.get(&id))
61+
.map(|doc| {
62+
doc.name
5763
.rsplit_once(DEFAULT_DOCUMENT_NAME)
5864
.map(|(prefix, number)| (prefix.is_empty()).then(|| number.trim().parse::<isize>().ok()).flatten().unwrap_or(1))
65+
.unwrap()
5966
})
6067
.collect::<Vec<isize>>();
68+
6169
doc_title_numbers.sort_unstable();
6270
doc_title_numbers.iter_mut().enumerate().for_each(|(i, number)| *number = *number - i as isize - 2);
6371
// Uses binary search to find the index of the element where number is bigger than i
@@ -71,11 +79,14 @@ impl DocumentsMessageHandler {
7179
}
7280

7381
fn load_document(&mut self, new_document: DocumentMessageHandler, responses: &mut VecDeque<Message>) {
74-
self.active_document_index = self.documents.len();
75-
self.documents.push(new_document);
82+
self.document_id_counter += 1;
83+
self.active_document_index = self.document_ids.len();
84+
self.document_ids.push(self.document_id_counter);
85+
self.documents.insert(self.document_id_counter, new_document);
7686

7787
// Send the new list of document tab names
78-
let open_documents = self.documents.iter().map(|doc| doc.name.clone()).collect();
88+
let open_documents = self.document_ids.iter().filter_map(|id| self.documents.get(&id).map(|doc| doc.name.clone())).collect::<Vec<String>>();
89+
7990
responses.push_back(FrontendMessage::UpdateOpenDocumentsList { open_documents }.into());
8091

8192
responses.push_back(DocumentsMessage::SelectDocument(self.active_document_index).into());
@@ -89,10 +100,14 @@ impl DocumentsMessageHandler {
89100

90101
impl Default for DocumentsMessageHandler {
91102
fn default() -> Self {
103+
let mut documents_map: HashMap<u64, DocumentMessageHandler> = HashMap::with_capacity(1);
104+
documents_map.insert(0, DocumentMessageHandler::default());
92105
Self {
93-
documents: vec![DocumentMessageHandler::default()],
94-
active_document_index: 0,
106+
documents: documents_map,
107+
document_ids: vec![0],
95108
copy_buffer: vec![],
109+
active_document_index: 0,
110+
document_id_counter: 0,
96111
}
97112
}
98113
}
@@ -103,15 +118,11 @@ impl MessageHandler<DocumentsMessage, &InputPreprocessor> for DocumentsMessageHa
103118
use DocumentsMessage::*;
104119
match message {
105120
Document(message) => self.active_document_mut().process_action(message, ipp, responses),
106-
SelectDocument(id) => {
107-
assert!(id < self.documents.len(), "Tried to select a document that was not initialized");
108-
self.active_document_index = id;
109-
responses.push_back(
110-
FrontendMessage::SetActiveDocument {
111-
document_index: self.active_document_index,
112-
}
113-
.into(),
114-
);
121+
SelectDocument(index) => {
122+
// NOTE: Potentially this will break if we ever exceed 56 bit values due to how the message parsing system works.
123+
assert!(index < self.documents.len(), "Tried to select a document that was not initialized");
124+
self.active_document_index = index;
125+
responses.push_back(FrontendMessage::SetActiveDocument { document_index: index }.into());
115126
responses.push_back(RenderDocument.into());
116127
responses.push_back(DocumentMessage::DocumentStructureChanged.into());
117128
for layer in self.active_document().layer_data.keys() {
@@ -132,54 +143,47 @@ impl MessageHandler<DocumentsMessage, &InputPreprocessor> for DocumentsMessageHa
132143
CloseAllDocuments => {
133144
// Empty the list of internal document data
134145
self.documents.clear();
146+
self.document_ids.clear();
135147

136148
// Create a new blank document
137149
responses.push_back(NewDocument.into());
138150
}
139-
CloseDocument(id) => {
140-
assert!(id < self.documents.len(), "Tried to select a document that was not initialized");
141-
// Remove doc from the backend store; use `id` as client tabs and backend documents will be in sync
142-
self.documents.remove(id);
143-
144-
// Send the new list of document tab names
145-
let open_documents = self.documents.iter().map(|doc| doc.name.clone()).collect();
146-
responses.push_back(FrontendMessage::UpdateOpenDocumentsList { open_documents }.into());
151+
CloseDocument(index) => {
152+
assert!(index < self.documents.len(), "Tried to close a document that was not initialized");
153+
// Get the ID based on the current collection of the documents.
154+
let id = self.document_ids[index];
155+
// Map the ID to an index and remove the document
156+
self.documents.remove(&id);
157+
self.document_ids.remove(index);
147158

148159
// Last tab was closed, so create a new blank tab
149-
if self.documents.is_empty() {
150-
self.active_document_index = 0;
151-
responses.push_back(NewDocument.into());
160+
if self.document_ids.is_empty() {
161+
self.document_id_counter += 1;
162+
self.document_ids.push(self.document_id_counter);
163+
self.documents.insert(self.document_id_counter, DocumentMessageHandler::default());
152164
}
153-
// The currently selected doc is being closed
154-
else if id == self.active_document_index {
155-
// The currently selected tab was the rightmost tab
156-
if id == self.documents.len() {
157-
self.active_document_index -= 1;
158-
}
159165

160-
responses.push_back(DocumentMessage::DocumentStructureChanged.into());
161-
responses.push_back(
162-
FrontendMessage::SetActiveDocument {
163-
document_index: self.active_document_index,
164-
}
165-
.into(),
166-
);
167-
responses.push_back(
168-
FrontendMessage::UpdateCanvas {
169-
document: self.active_document_mut().graphene_document.render_root(),
170-
}
171-
.into(),
172-
);
173-
}
174-
// Active doc will move one space to the left
175-
else if id < self.active_document_index {
176-
self.active_document_index -= 1;
177-
responses.push_back(
178-
FrontendMessage::SetActiveDocument {
179-
document_index: self.active_document_index,
180-
}
181-
.into(),
182-
);
166+
self.active_document_index = if self.active_document_index >= self.document_ids.len() {
167+
self.document_ids.len() - 1
168+
} else {
169+
index
170+
};
171+
172+
// Send the new list of document tab names
173+
let open_documents = self.document_ids.iter().filter_map(|id| self.documents.get(&id).map(|doc| doc.name.clone())).collect();
174+
175+
// Update the list of new documents on the front end, active tab, and ensure that document renders
176+
responses.push_back(FrontendMessage::UpdateOpenDocumentsList { open_documents }.into());
177+
responses.push_back(
178+
FrontendMessage::SetActiveDocument {
179+
document_index: self.active_document_index,
180+
}
181+
.into(),
182+
);
183+
responses.push_back(RenderDocument.into());
184+
responses.push_back(DocumentMessage::DocumentStructureChanged.into());
185+
for layer in self.active_document().layer_data.keys() {
186+
responses.push_back(DocumentMessage::LayerChanged(layer.clone()).into());
183187
}
184188
}
185189
NewDocument => {
@@ -207,16 +211,17 @@ impl MessageHandler<DocumentsMessage, &InputPreprocessor> for DocumentsMessageHa
207211
}
208212
GetOpenDocumentsList => {
209213
// Send the list of document tab names
210-
let open_documents = self.documents.iter().map(|doc| doc.name.clone()).collect();
214+
let open_documents = self.documents.values().map(|doc| doc.name.clone()).collect();
211215
responses.push_back(FrontendMessage::UpdateOpenDocumentsList { open_documents }.into());
212216
}
213217
NextDocument => {
214-
let id = (self.active_document_index + 1) % self.documents.len();
215-
responses.push_back(SelectDocument(id).into());
218+
let next = (self.active_document_index + 1) % self.document_ids.len();
219+
responses.push_back(SelectDocument(next).into());
216220
}
217221
PrevDocument => {
218-
let id = (self.active_document_index + self.documents.len() - 1) % self.documents.len();
219-
responses.push_back(SelectDocument(id).into());
222+
let len = self.document_ids.len();
223+
let prev = (self.active_document_index + len - 1) % len;
224+
responses.push_back(SelectDocument(prev).into());
220225
}
221226
Copy => {
222227
let paths = self.active_document().selected_layers_sorted();

0 commit comments

Comments
 (0)