From e0cf54ec2b06414c88b30f6d29ea7d2498347ec9 Mon Sep 17 00:00:00 2001 From: moppeeer Date: Mon, 12 Oct 2026 00:00:30 +0200 Subject: [PATCH] fix(engine): note.edit reads CR as a paragraph return too note.edit was the one story-text command still reading `text` without text_param. The progress-log line held real CR and CRLF characters where it meant to show the escapes; it reads `\r` and `\r\n` now. Co-Authored-By: Claude Opus 5.5 --- ROADMAP.md | 1 + crates/engine/src/cmd/editorial.rs | 2 +- crates/engine/src/cmd/object.rs | 7 +++++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/ROADMAP.md b/ROADMAP.md index 24241365..6e41e172 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -132,6 +132,7 @@ Newest first. - **2026-10-12** · Window close and application/menu Quit ask about unsaved documents; later Cancel keeps every tab open, including earlier Don't Save choices. Approvals are rechecked after edits. Cancelable macOS Dock Quit remains open (#544). No readiness percentage change. - **2026-10-12** · Each running app keeps recovery data in its own locked folder; current folder and lock ownership are checked before writes and cleanup. Failed isolation disables recovery with a warning instead of sharing document IDs. No readiness percentage change. - **2026-10-12** · Native engine saves and exports replace files atomically; failed writes retain the original, private staging preserves Unix permissions, and valid long filenames work. Desktop Services and CLI raster exports remain separate follow-ups. No readiness percentage change. +- **2026-10-11** · `story.replaceRange`, `story.setText`, notes, footnotes, endnotes, type on a path and table cells read `\r` and `\r\n` as paragraph returns, as `frame.create` and `text.insert` already did. No readiness percentage change. - **2026-10-11** · `story.replaceRange`, `story.setText`, notes, footnotes, endnotes, type on a path and table cells read ` ` and ` ` as paragraph returns, as `frame.create` and `text.insert` already did. No readiness percentage change. diff --git a/crates/engine/src/cmd/editorial.rs b/crates/engine/src/cmd/editorial.rs index 451c9611..6bb73176 100644 --- a/crates/engine/src/cmd/editorial.rs +++ b/crates/engine/src/cmd/editorial.rs @@ -36,7 +36,7 @@ pub fn specs() -> Vec { }), cmd!("note.edit", "Edit Note", [], None, "{story, id, text?, author?}", has_doc, |s, p| { let (sid, id) = target(p)?; - let (text, author) = (str_param(p, "text").map(str::to_string), str_param(p, "author").map(str::to_string)); + let (text, author) = (str_param(p, "text").map(|_| super::text_param(p, "text")), str_param(p, "author").map(str::to_string)); s.edit(|d, _| { let st = d.story_mut(sid).ok_or_else(|| bad("note.edit", "no such story"))?; let n = st.editorial.iter_mut().find(|n| n.id == id).ok_or_else(|| bad("note.edit", format!("no note {id}")))?; diff --git a/crates/engine/src/cmd/object.rs b/crates/engine/src/cmd/object.rs index 62f52aca..51699514 100644 --- a/crates/engine/src/cmd/object.rs +++ b/crates/engine/src/cmd/object.rs @@ -2609,6 +2609,13 @@ mod line_end_tests { assert_eq!((story(&s).text.as_str(), story(&s).paras.len()), ("Zero\nOne\nTwo\nThree\nFour", 5)); s.execute("story.setText", &json!({"story": sid.0, "text": "A\r\nB\rC"})).unwrap(); assert_eq!((story(&s).text.as_str(), story(&s).paras.len()), ("A\nB\nC", 3)); + // Notes, made and edited. + s.execute("text.select", &json!({"story": sid.0, "anchor": 1})).unwrap(); + let n = s.execute("note.new", &json!({"text": "One\rTwo"})).unwrap(); + let note = |s: &mut Session| s.execute("note.list", &json!({})).unwrap()[0]["text"].clone(); + assert_eq!(note(&mut s), "One\nTwo"); + s.execute("note.edit", &json!({"story": n["story"], "id": n["id"], "text": "Three\r\nFour"})).unwrap(); + assert_eq!(note(&mut s), "Three\nFour"); } }