Skip to content

Commit d44b0cd

Browse files
authored
Make documents fall back to "Untitled Document" (+ number suffix) if given a blank name (#4074)
* Make documents fall back to "Untitled Document" (+ number suffix) if given a blank name * Bug fix
1 parent b152f46 commit d44b0cd

6 files changed

Lines changed: 43 additions & 20 deletions

File tree

editor/src/messages/dialog/dialog_message_handler.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ impl MessageHandler<DialogMessage, DialogMessageContext<'_>> for DialogMessageHa
126126
DialogMessage::RequestNewDocumentDialog => {
127127
self.on_dismiss = Some(DialogMessage::Close.into());
128128
self.new_document_dialog = NewDocumentDialogMessageHandler {
129-
name: portfolio.generate_new_document_name(),
129+
name: portfolio.generate_new_document_name(None),
130130
infinite: false,
131131
dimensions: glam::UVec2::new(1920, 1080),
132132
};

editor/src/messages/portfolio/document/document_message_handler.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -784,7 +784,15 @@ impl MessageHandler<DocumentMessage, DocumentMessageContext<'_>> for DocumentMes
784784
responses.add(EventMessage::SelectionChanged);
785785
}
786786
DocumentMessage::RenameDocument { new_name } => {
787-
self.name = new_name.clone();
787+
let new_name = new_name.trim().to_string();
788+
789+
// No-op when the resolved name is unchangedL committing the rename field without edits (or with
790+
// only whitespace edits) shouldn't dissociate the document from its file on disk or mark it unsaved.
791+
if new_name == self.name {
792+
return;
793+
}
794+
795+
self.name = new_name;
788796

789797
self.path = None;
790798
self.set_save_state(false);

editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2475,7 +2475,7 @@ impl NodeGraphMessageHandler {
24752475
Separator::new(SeparatorStyle::Related).widget_instance(),
24762476
TextInput::new(context.document_name)
24772477
.tooltip_description("Name of the current document.")
2478-
.on_update(|text_input| DocumentMessage::RenameDocument { new_name: text_input.value.clone() }.into())
2478+
.on_update(|text_input| PortfolioMessage::RenameDocument { new_name: text_input.value.clone() }.into())
24792479
.widget_instance(),
24802480
Separator::new(SeparatorStyle::Related).widget_instance(),
24812481
])];

editor/src/messages/portfolio/portfolio_message.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,9 @@ pub enum PortfolioMessage {
168168
SelectDocument {
169169
document_id: DocumentId,
170170
},
171+
RenameDocument {
172+
new_name: String,
173+
},
171174
SubmitDocumentExport {
172175
name: String,
173176
file_type: FileType,

editor/src/messages/portfolio/portfolio_message_handler.rs

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -498,7 +498,7 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
498498
}
499499
PortfolioMessage::NewDocumentWithName { name } => {
500500
let mut new_document = DocumentMessageHandler::default();
501-
new_document.name = name;
501+
new_document.name = self.resolve_document_name(name, None);
502502

503503
responses.add(DocumentMessage::PTZUpdate);
504504

@@ -799,28 +799,24 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
799799
}
800800
});
801801

802-
match (document_name, document_path, document_name_from_path) {
803-
(Some(name), _, None) => {
804-
document.name = name;
805-
}
802+
let candidate_name = match (document_name, document_path, document_name_from_path) {
803+
(Some(name), _, None) => name,
806804
(_, Some(path), Some(name)) => {
807-
document.name = name;
808805
document.path = Some(path);
806+
name
809807
}
810-
(_, _, Some(name)) => {
811-
document.name = name;
812-
}
813-
_ => {
814-
document.name = DEFAULT_DOCUMENT_NAME.to_string();
815-
}
816-
}
808+
(_, _, Some(name)) => name,
809+
_ => String::new(),
810+
};
811+
document.name = self.resolve_document_name(candidate_name, None);
817812

818813
// Load the document into the portfolio so it opens in the editor
819814
self.load_document(document, document_id, responses);
820815
}
821816
PortfolioMessage::OpenImage { name, image } => {
817+
// `NewDocumentWithName`'s handler routes empty/None-equivalent names through `resolve_document_name` which assigns the next available "Untitled Document {N}".
822818
responses.add(PortfolioMessage::NewDocumentWithName {
823-
name: name.clone().unwrap_or(DEFAULT_DOCUMENT_NAME.into()),
819+
name: name.clone().unwrap_or_default(),
824820
});
825821

826822
responses.add(DocumentMessage::PasteImage {
@@ -847,7 +843,7 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
847843
}
848844
PortfolioMessage::OpenSvg { name, svg } => {
849845
responses.add(PortfolioMessage::NewDocumentWithName {
850-
name: name.clone().unwrap_or(DEFAULT_DOCUMENT_NAME.into()),
846+
name: name.clone().unwrap_or_default(),
851847
});
852848

853849
// Parse the SVG to extract its declared canvas origin and dimensions from the viewBox attribute.
@@ -1359,6 +1355,10 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
13591355
self.refresh_panel_content(target_active, responses);
13601356
}
13611357
}
1358+
PortfolioMessage::RenameDocument { new_name } => {
1359+
let resolved_name = self.resolve_document_name(new_name, self.active_document_id);
1360+
responses.add(DocumentMessage::RenameDocument { new_name: resolved_name });
1361+
}
13621362
PortfolioMessage::SelectDocument { document_id } => {
13631363
// Auto-save the document we are leaving
13641364
let mut node_graph_open = false;
@@ -1744,10 +1744,22 @@ impl PortfolioMessageHandler {
17441744
}
17451745
}
17461746

1747-
pub fn generate_new_document_name(&self) -> String {
1747+
/// Resolves a proposed document name: if it's empty or only whitespace, falls back to the next
1748+
/// available "Untitled Document {N}" via [`Self::generate_new_document_name`]. Otherwise trims surrounding
1749+
/// whitespace and returns it. `exclude` is forwarded so a renaming document can skip its own current
1750+
/// name when computing the fallback (preventing self-collision).
1751+
pub fn resolve_document_name(&self, name: String, exclude: Option<DocumentId>) -> String {
1752+
let trimmed = name.trim();
1753+
if trimmed.is_empty() { self.generate_new_document_name(exclude) } else { trimmed.to_string() }
1754+
}
1755+
1756+
/// `exclude` lets a renaming caller skip its own current name so a document can rename back to its
1757+
/// existing slot rather than colliding with itself and getting bumped to the next number.
1758+
pub fn generate_new_document_name(&self, exclude: Option<DocumentId>) -> String {
17481759
let mut doc_title_numbers = self
17491760
.document_ids
17501761
.iter()
1762+
.filter(|id| exclude != Some(**id))
17511763
.filter_map(|id| self.document_details(*id))
17521764
.filter_map(|doc| {
17531765
doc.name

frontend/wrapper/src/editor_wrapper.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -410,7 +410,7 @@ impl EditorWrapper {
410410
/// Rename the currently active document.
411411
#[wasm_bindgen(js_name = renameDocument)]
412412
pub fn rename_document(&self, new_name: String) {
413-
let message = DocumentMessage::RenameDocument { new_name };
413+
let message = PortfolioMessage::RenameDocument { new_name };
414414
self.dispatch(message);
415415
}
416416

0 commit comments

Comments
 (0)