mirror of
https://github.com/storytold/wordcraft.git
synced 2026-10-28 04:17:06 -06:00
references: a table of figures from Word replaces its saved list (#3013)
A Word table of figures whose saved list sits in the field's result, in the field's own paragraph, was listed twice after Update Table: the cached result stayed and the rebuilt entries followed it. The rebuild now clears that result and keeps the paragraph's tab leader for the entries. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019Nnsfu3QGqjD1aFZbBgUWP
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
a923cf6dc5
commit
47bcb64dbe
@@ -918,6 +918,28 @@ pub fn update_generated(s: &mut Session) -> Result<(), CmdError> {
|
||||
i += 1;
|
||||
continue;
|
||||
}
|
||||
// A table of figures from Word can hold the list it saved as the field's result, in the
|
||||
// field's own paragraph: the rebuilt entries replace it, keeping its leader.
|
||||
let mut saved_leader = None;
|
||||
if figures_label(&kind).is_some()
|
||||
&& let Ok(p) = s.doc.para_mut(StoryRef::Body, &Path::top(i))
|
||||
{
|
||||
let leader = p.props.tabs.as_ref().and_then(|t| t.last()).map(|t| t.leader);
|
||||
let mut cleared = false;
|
||||
for o in &mut p.objects {
|
||||
if let InlineObject::Field { instr, result, .. } = o
|
||||
&& !result.is_empty()
|
||||
&& figures_label(instr).is_some()
|
||||
{
|
||||
result.clear();
|
||||
cleared = true;
|
||||
}
|
||||
}
|
||||
if cleared {
|
||||
saved_leader = leader;
|
||||
p.touch();
|
||||
}
|
||||
}
|
||||
// Remove old entries, keeping their tab leader.
|
||||
let leader = s
|
||||
.doc
|
||||
@@ -926,6 +948,7 @@ pub fn update_generated(s: &mut Session) -> Result<(), CmdError> {
|
||||
.and_then(|b| b.as_para())
|
||||
.filter(|p| p.props.style.as_deref() == Some(ENTRY_STYLE))
|
||||
.and_then(|p| p.props.tabs.as_ref()?.last().map(|t| t.leader))
|
||||
.or(saved_leader)
|
||||
.unwrap_or(TabLeader::Dot);
|
||||
while s.doc.body.get(i + 1).and_then(|b| b.as_para()).is_some_and(|p| p.props.style.as_deref() == Some(ENTRY_STYLE)) {
|
||||
s.doc.remove_block(StoryRef::Body, &Path::top(i + 1))?;
|
||||
@@ -1531,6 +1554,36 @@ mod tests {
|
||||
assert_eq!(list_entries(&s), want);
|
||||
}
|
||||
|
||||
/// #3013 review: a table of figures from Word whose saved list sits in the field's result (one
|
||||
/// paragraph) is replaced by the rebuilt entries, not listed twice, and keeps its leader.
|
||||
#[test]
|
||||
fn table_of_figures_from_word_replaces_its_saved_list() {
|
||||
let mut s = Session::new(wordcraft_doc::Document::from_text("Kiln\nList"));
|
||||
s.run("select.text", &json!({"text": "Kiln"})).unwrap();
|
||||
s.run("references.caption", &json!({"label": "Figure", "text": "Kiln"})).unwrap();
|
||||
let last = s.doc.body.len() - 1;
|
||||
let p = s.doc.para_mut(StoryRef::Body, &Path::top(last)).unwrap();
|
||||
p.props.style = Some("TableofFigures".into());
|
||||
p.props.tabs = Some(vec![TabStop { pos: 400.0, align: TabAlign::Right, leader: TabLeader::Hyphen }]);
|
||||
let end = p.len();
|
||||
p.delete(0, end).unwrap();
|
||||
let field = InlineObject::Field {
|
||||
instr: r#"TOC \h \z \c "Figure""#.into(),
|
||||
result: "Figure 1: Kiln\t1".into(),
|
||||
locked: false,
|
||||
dirty: false,
|
||||
code: false,
|
||||
form: String::new(),
|
||||
};
|
||||
p.insert_object(0, field, &CharProps::default()).unwrap();
|
||||
for _ in 0..2 {
|
||||
s.run("references.updateFigures", &json!({})).unwrap();
|
||||
let text = s.doc.plain_text(StoryRef::Body);
|
||||
assert_eq!(text.matches("Figure 1: Kiln\t1").count(), 1, "{text:?}");
|
||||
assert_eq!(list_entries(&s), [("Figure 1: Kiln\t1".to_string(), Some(TabLeader::Hyphen))]);
|
||||
}
|
||||
}
|
||||
|
||||
/// #3013 review: `\c` picks captions by their SEQ identifier, as Word does, not by the text
|
||||
/// before the number (`STYLEREF`, " Specimen ", `SEQ Figure` is a figure).
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user