Reuse Word markers before inserting anchors

This commit is contained in:
Nick Beckley 2026-09-05 20:36:26 +00:00
parent cb0beb1a12
commit 340fec3cab
2 changed files with 41 additions and 6 deletions

View File

@ -1980,11 +1980,12 @@ static void WordCompanionRuntimeFollowsMultipleImportedSceneAnchors()
Assert(script.Contains("if (paragraph.sceneAnchorId)", StringComparison.Ordinal), "Runtime structure should start scenes from PD-SCENE anchors on ordinary paragraphs."); Assert(script.Contains("if (paragraph.sceneAnchorId)", StringComparison.Ordinal), "Runtime structure should start scenes from PD-SCENE anchors on ordinary paragraphs.");
Assert(script.Contains("return chapter.scenes\r\n .filter((item) => item.startParagraphIndex <= paragraphIndex)", StringComparison.Ordinal) Assert(script.Contains("return chapter.scenes\r\n .filter((item) => item.startParagraphIndex <= paragraphIndex)", StringComparison.Ordinal)
|| script.Contains("return chapter.scenes\n .filter((item) => item.startParagraphIndex <= paragraphIndex)", StringComparison.Ordinal), "Cursor resolution should select the latest preceding scene boundary."); || script.Contains("return chapter.scenes\n .filter((item) => item.startParagraphIndex <= paragraphIndex)", StringComparison.Ordinal), "Cursor resolution should select the latest preceding scene boundary.");
Assert(script.Contains("findExactAnchorControl(paragraph, tag)", StringComparison.Ordinal), "Marker insertion should reuse only the exact canonical SceneID tag."); Assert(script.Contains("findExactAnchorControl(paragraph, tag)", StringComparison.Ordinal), "Marker insertion should prefer the exact canonical SceneID tag.");
Assert(script.Contains("const reusable = existing || findAnchorControl(paragraph, prefix)", StringComparison.Ordinal), "Marker insertion should reuse an existing same-prefix marker on the same paragraph before inserting another control.");
Assert(script.Contains("const rangeLocations = [\"Content\", \"Start\", \"Whole\"]", StringComparison.Ordinal), "Marker insertion should try heading content before progressively smaller Word ranges."); Assert(script.Contains("const rangeLocations = [\"Content\", \"Start\", \"Whole\"]", StringComparison.Ordinal), "Marker insertion should try heading content before progressively smaller Word ranges.");
Assert(script.Contains("paragraph.getRange(rangeLocation).insertContentControl()", StringComparison.Ordinal), "Marker insertion should retry Word-supported paragraph range locations."); Assert(script.Contains("paragraph.getRange(rangeLocation).insertContentControl()", StringComparison.Ordinal), "Marker insertion should retry Word-supported paragraph range locations.");
Assert(script.Contains("await ensureAnchorControl(context, paragraphs.items[index], title, tag, prefix)", StringComparison.Ordinal), "Bulk marker sync should await each marker insertion so Word range failures are isolated."); Assert(script.Contains("await ensureAnchorControl(context, paragraphs.items[index], title, tag, prefix)", StringComparison.Ordinal), "Bulk marker sync should await each marker insertion so Word range failures are isolated.");
Assert(!script.Contains("const existing = findAnchorControl(paragraph, prefix);", StringComparison.Ordinal), "Marker insertion must not collapse distinct PD-SCENE tags by prefix."); Assert(script.Contains("paragraphs.items[index].contentControls.load(\"items/tag,title\")", StringComparison.Ordinal), "Bulk marker sync should inspect existing paragraph markers before deciding to insert content controls.");
} }
static void WordCompanionExistingProjectBookLinkingRemainsAvailable() static void WordCompanionExistingProjectBookLinkingRemainsAvailable()

View File

@ -2621,6 +2621,39 @@
paragraphs.load("items/text,items/style,items/styleBuiltIn"); paragraphs.load("items/text,items/style,items/styleBuiltIn");
await context.sync(); await context.sync();
const markerParagraphIndexes = new Set();
if (chapterInstructions.length > 0 || sceneInstructions.length > 0) {
for (const instruction of [...chapterInstructions, ...sceneInstructions]) {
const index = Number.parseInt(instruction.wordParagraphIndex ?? instruction.WordParagraphIndex, 10);
if (Number.isInteger(index) && paragraphs.items[index]) {
markerParagraphIndexes.add(index);
}
}
} else {
for (const chapter of lastOnboardingScanPreview.chapters || []) {
const index = Number.parseInt(chapter.startPosition, 10);
if (Number.isInteger(index) && paragraphs.items[index]) {
markerParagraphIndexes.add(index);
}
}
for (const scene of lastOnboardingScanPreview.scenes || []) {
const index = Number.parseInt(scene.startPosition, 10);
if (Number.isInteger(index) && paragraphs.items[index]) {
markerParagraphIndexes.add(index);
}
}
}
try {
for (const index of markerParagraphIndexes) {
paragraphs.items[index].contentControls.load("items/tag,title");
}
await context.sync();
} catch (error) {
console.warn("Unable to inspect existing PlotDirector markers before marker sync.", error);
}
if (chapterInstructions.length > 0 || sceneInstructions.length > 0) { if (chapterInstructions.length > 0 || sceneInstructions.length > 0) {
for (const instruction of chapterInstructions) { for (const instruction of chapterInstructions) {
const index = Number.parseInt(instruction.wordParagraphIndex ?? instruction.WordParagraphIndex, 10); const index = Number.parseInt(instruction.wordParagraphIndex ?? instruction.WordParagraphIndex, 10);
@ -4615,10 +4648,11 @@
return false; return false;
} }
if (existing) { const reusable = existing || findAnchorControl(paragraph, prefix);
existing.title = title; if (reusable) {
existing.tag = tag; reusable.title = title;
existing.appearance = "Hidden"; reusable.tag = tag;
reusable.appearance = "Hidden";
await context.sync(); await context.sync();
return true; return true;
} }