Text: carriage returns in typed or created text start paragraphs
frame.create's text and text.insert kept CR and CR LF as characters, so text
written with InDesign's, classic Mac or Windows line ends ("One\rTwo") became
a single paragraph, and paragraph formatting (spaceAfter) never applied
between the parts. They now become \n, the paragraph separator, as edit.paste
and text import already did.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
316e1ffe62
commit
b54fa8d9bb
|
|
@ -230,6 +230,12 @@ pub(crate) fn bool_or(p: &Value, key: &str, default: bool) -> bool {
|
|||
pub(crate) fn str_param<'a>(p: &'a Value, key: &str) -> Option<&'a str> {
|
||||
p.get(key).and_then(Value::as_str)
|
||||
}
|
||||
/// Plain text from a parameter, with CR LF and lone CR (classic Mac and InDesign line ends) as
|
||||
/// `\n`, the paragraph separator, as edit.paste and text import already do. Kept as they were,
|
||||
/// the CRs joined the paragraphs into one.
|
||||
pub(crate) fn text_param(p: &Value, key: &str) -> String {
|
||||
str_param(p, key).unwrap_or("").replace("\r\n", "\n").replace('\r', "\n")
|
||||
}
|
||||
pub(crate) fn id_param(p: &Value, key: &str) -> Option<ItemId> {
|
||||
p.get(key).and_then(Value::as_u64).map(ItemId)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -795,7 +795,7 @@ fn frame_create(s: &mut Session, p: &Value) -> Result<Value> {
|
|||
let content = str_param(p, "content").unwrap_or("graphic");
|
||||
let sr = spread_param(p, "spread");
|
||||
let lid = s.doc()?.active_layer;
|
||||
let text = str_param(p, "text").unwrap_or("").to_string();
|
||||
let text = super::text_param(p, "text");
|
||||
let caret = bool_or(p, "caret", content == "text");
|
||||
let vertical = bool_or(p, "vertical", false);
|
||||
let sides = p.get("sides").and_then(Value::as_u64).map_or(s.prefs.polygon_sides, |v| v as u32).clamp(3, 100);
|
||||
|
|
@ -2369,3 +2369,24 @@ mod gap_tests {
|
|||
assert!(s.execute("gap.move", &json!({"at": [150, 200], "delta": 5})).is_err(), "inside an object");
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod line_end_tests {
|
||||
use super::*;
|
||||
|
||||
/// "One\rTwo" made one paragraph (the CR stayed in the text) instead of two.
|
||||
#[test]
|
||||
fn carriage_returns_separate_paragraphs() {
|
||||
let mut s = Session::new();
|
||||
s.execute("file.new", &json!({})).unwrap();
|
||||
let r = s.execute("frame.create", &json!({"rect": [36, 36, 300, 300], "content": "text", "text": "One\rTwo\r\nThree"})).unwrap();
|
||||
let sid = designcraft_doc::StoryId(r["story"].as_u64().unwrap());
|
||||
let story = |s: &Session| s.doc().unwrap().doc.story(sid).unwrap().clone();
|
||||
assert_eq!(story(&s).text, "One\nTwo\nThree");
|
||||
assert_eq!(story(&s).paras.len(), 3);
|
||||
// The caret is at the end: typed text gets the same treatment.
|
||||
s.execute("text.insert", &json!({"text": "\rFour", "raw": true})).unwrap();
|
||||
assert_eq!(story(&s).text, "One\nTwo\nThree\nFour");
|
||||
assert_eq!(story(&s).paras.len(), 4);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -327,7 +327,7 @@ fn release(s: &mut Session, p: &Value) -> Result<Value> {
|
|||
}
|
||||
|
||||
fn insert(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
let text = str_param(p, "text").unwrap_or("").to_string();
|
||||
let text = super::text_param(p, "text");
|
||||
// Tab in a table cell moves to the next cell (Shift-Tab: `table.prevCell`).
|
||||
if text == "\t" && s.doc()?.selection.text.is_some_and(|t| t.cell.is_some()) {
|
||||
return super::table::step_cell(s, true);
|
||||
|
|
|
|||
Loading…
Reference in New Issue