Phase 16E.1 - Word Companion Runtime Performance Stabilisation

This commit is contained in:
Nick Beckley 2026-06-27 22:18:24 +01:00
parent d442de5837
commit 18f204460f
2 changed files with 62 additions and 6 deletions

View File

@ -196,6 +196,9 @@
let sceneTrackingMode = "Manual"; let sceneTrackingMode = "Manual";
let sceneContextStale = false; let sceneContextStale = false;
let selectionRefreshTimer = null; let selectionRefreshTimer = null;
let runtimeSelectionDirty = false;
let runtimeLastActivityAt = 0;
const runtimeIdleDelayMs = 1800;
let selectionHandlerRegistered = false; let selectionHandlerRegistered = false;
let isAutoRefreshingScene = false; let isAutoRefreshingScene = false;
let sceneWordCountSyncTimer = null; let sceneWordCountSyncTimer = null;
@ -204,6 +207,7 @@
let lastSyncedWordCount = null; let lastSyncedWordCount = null;
let lastLinkedSceneTitle = ""; let lastLinkedSceneTitle = "";
let lastLinkedChapterTitle = ""; let lastLinkedChapterTitle = "";
let runtimeLastDebugAt = 0;
let currentSceneLinks = { let currentSceneLinks = {
characters: [], characters: [],
assets: [], assets: [],
@ -211,6 +215,15 @@
primaryLocationId: null primaryLocationId: null
}; };
const runtimeDebug = (message) => {
const now = Date.now();
if (now - runtimeLastDebugAt < 1000) {
return;
}
runtimeLastDebugAt = now;
console.debug(`[Word Companion Runtime] ${message}`);
};
const setOfficeStatus = (message) => { const setOfficeStatus = (message) => {
if (officeStatus) { if (officeStatus) {
officeStatus.textContent = message; officeStatus.textContent = message;
@ -337,6 +350,19 @@
}; };
const setCurrentStructure = (chapterTitle, sceneTitle, wordCount, chapterAnchorId = null, sceneAnchorId = null, chapterIndex = null) => { const setCurrentStructure = (chapterTitle, sceneTitle, wordCount, chapterAnchorId = null, sceneAnchorId = null, chapterIndex = null) => {
const nextChapterTitle = chapterTitle || "";
const nextSceneTitle = sceneTitle || "";
const nextWordCount = Number.isInteger(wordCount) ? wordCount : null;
const nextChapterIndex = Number.isInteger(chapterIndex) && chapterIndex > 0 ? chapterIndex : null;
const nextChapterAnchorId = Number.isInteger(chapterAnchorId) && chapterAnchorId > 0 ? chapterAnchorId : null;
const nextSceneAnchorId = Number.isInteger(sceneAnchorId) && sceneAnchorId > 0 ? sceneAnchorId : null;
const unchanged = detectedChapterTitle === nextChapterTitle
&& detectedSceneTitle === nextSceneTitle
&& detectedSceneWordCount === nextWordCount
&& detectedChapterIndex === nextChapterIndex
&& detectedChapterAnchorId === nextChapterAnchorId
&& detectedSceneAnchorId === nextSceneAnchorId;
detectedChapterTitle = chapterTitle || ""; detectedChapterTitle = chapterTitle || "";
detectedSceneTitle = sceneTitle || ""; detectedSceneTitle = sceneTitle || "";
detectedSceneWordCount = Number.isInteger(wordCount) ? wordCount : null; detectedSceneWordCount = Number.isInteger(wordCount) ? wordCount : null;
@ -344,6 +370,10 @@
detectedChapterAnchorId = Number.isInteger(chapterAnchorId) && chapterAnchorId > 0 ? chapterAnchorId : null; detectedChapterAnchorId = Number.isInteger(chapterAnchorId) && chapterAnchorId > 0 ? chapterAnchorId : null;
detectedSceneAnchorId = Number.isInteger(sceneAnchorId) && sceneAnchorId > 0 ? sceneAnchorId : null; detectedSceneAnchorId = Number.isInteger(sceneAnchorId) && sceneAnchorId > 0 ? sceneAnchorId : null;
if (unchanged) {
return;
}
if (currentChapter) { if (currentChapter) {
currentChapter.textContent = chapterTitle || "Not detected"; currentChapter.textContent = chapterTitle || "Not detected";
} }
@ -891,7 +921,10 @@
const setText = (element, value) => { const setText = (element, value) => {
if (element) { if (element) {
element.textContent = value; const nextValue = value === null || value === undefined ? "" : String(value);
if (element.textContent !== nextValue) {
element.textContent = nextValue;
}
} }
}; };
@ -1671,13 +1704,19 @@
const currentChapterItem = chapterForParagraphIndex(documentStructureCache, paragraphIndex); const currentChapterItem = chapterForParagraphIndex(documentStructureCache, paragraphIndex);
const currentSceneItem = sceneForParagraphIndex(currentChapterItem, paragraphIndex); const currentSceneItem = sceneForParagraphIndex(currentChapterItem, paragraphIndex);
const changed = currentChapterItem?.paragraphIndex !== documentStructureCache.currentChapter?.paragraphIndex const changed = currentChapterItem?.startParagraphIndex !== documentStructureCache.currentChapter?.startParagraphIndex
|| currentSceneItem?.paragraphIndex !== documentStructureCache.currentScene?.paragraphIndex; || currentSceneItem?.startParagraphIndex !== documentStructureCache.currentScene?.startParagraphIndex
|| currentChapterItem?.anchorId !== documentStructureCache.currentChapter?.anchorId
|| currentSceneItem?.anchorId !== documentStructureCache.currentScene?.anchorId;
documentStructureCache.currentParagraphIndex = paragraphIndex; documentStructureCache.currentParagraphIndex = paragraphIndex;
documentStructureCache.currentChapter = currentChapterItem; documentStructureCache.currentChapter = currentChapterItem;
documentStructureCache.currentScene = currentSceneItem; documentStructureCache.currentScene = currentSceneItem;
if (!changed) {
return false;
}
setCurrentStructure( setCurrentStructure(
currentChapterItem?.title, currentChapterItem?.title,
currentSceneItem?.title, currentSceneItem?.title,
@ -2129,6 +2168,7 @@
const selectedIndex = findSelectedParagraphIndex(cache, selectionParagraphs.items); const selectedIndex = findSelectedParagraphIndex(cache, selectionParagraphs.items);
documentStructureCache = cache; documentStructureCache = cache;
applyRuntimeSelection(selectedIndex); applyRuntimeSelection(selectedIndex);
runtimeDebug("Cache rebuilt.");
return cache; return cache;
}; };
@ -4022,7 +4062,9 @@
}; };
const refreshCurrentSceneFromSelection = async () => { const refreshCurrentSceneFromSelection = async () => {
selectionRefreshTimer = null;
if (isAutoRefreshingScene || !isAuthenticated || !selectedBook()) { if (isAutoRefreshingScene || !isAuthenticated || !selectedBook()) {
runtimeDebug("Runtime update skipped.");
return; return;
} }
@ -4038,8 +4080,17 @@
return; return;
} }
const idleForMs = Date.now() - runtimeLastActivityAt;
if (runtimeSelectionDirty && idleForMs < runtimeIdleDelayMs) {
runtimeDebug("Runtime update skipped (typing active).");
scheduleSelectionRefresh(runtimeIdleDelayMs - idleForMs);
return;
}
isAutoRefreshingScene = true; isAutoRefreshingScene = true;
runtimeSelectionDirty = false;
setSceneTrackingState("Live"); setSceneTrackingState("Live");
runtimeDebug("Runtime update executed.");
try { try {
const selectionParagraphs = await window.Word.run(async (context) => await readSelectionParagraphs(context)); const selectionParagraphs = await window.Word.run(async (context) => await readSelectionParagraphs(context));
@ -4071,14 +4122,19 @@
} }
}; };
const scheduleSelectionRefresh = () => { const scheduleSelectionRefresh = (delayMs = runtimeIdleDelayMs) => {
if (selectionRefreshTimer) { if (selectionRefreshTimer) {
window.clearTimeout(selectionRefreshTimer); window.clearTimeout(selectionRefreshTimer);
} }
selectionRefreshTimer = window.setTimeout(refreshCurrentSceneFromSelection, 850); selectionRefreshTimer = window.setTimeout(refreshCurrentSceneFromSelection, Math.max(0, delayMs));
runtimeDebug("Runtime update scheduled.");
}; };
const handleDocumentSelectionChanged = () => { const handleDocumentSelectionChanged = () => {
runtimeSelectionDirty = true;
runtimeLastActivityAt = Date.now();
clearPendingSceneWordCountSync();
runtimeDebug("Selection changed.");
scheduleSelectionRefresh(); scheduleSelectionRefresh();
}; };

File diff suppressed because one or more lines are too long