diff --git a/src/features/chat/application/state/root-reducer.ts b/src/features/chat/application/state/root-reducer.ts index f32de361..9bb60358 100644 --- a/src/features/chat/application/state/root-reducer.ts +++ b/src/features/chat/application/state/root-reducer.ts @@ -682,7 +682,7 @@ function setComposerSuggestionsSlice( if ( state.suggestSelected === selected && state.suggestionsDismissedSignature === dismissedSignature && - composerSuggestionsEqual(state.suggestions, suggestions) + state.suggestions === suggestions ) { return state; } @@ -693,50 +693,6 @@ function setComposerSuggestionsSlice( }); } -function composerSuggestionsEqual(left: readonly ComposerSuggestion[], right: readonly ComposerSuggestion[]): boolean { - if (left === right) return true; - if (left.length !== right.length) return false; - return left.every((item, index) => { - const other = right[index]; - return ( - item.display === other?.display && - item.detail === other.detail && - item.replacement === other.replacement && - item.start === other.start && - item.appendSpaceOnInsert === other.appendSpaceOnInsert && - composerSuggestionActiveNoteContextEqual(item.activeNoteContext, other.activeNoteContext) && - composerSuggestionSelectionContextEqual(item.selectionContext, other.selectionContext) - ); - }); -} - -function composerSuggestionActiveNoteContextEqual( - left: ComposerSuggestion["activeNoteContext"], - right: ComposerSuggestion["activeNoteContext"], -): boolean { - if (left === right) return true; - if (!left || !right) return false; - return left.name === right.name && left.path === right.path && left.linktext === right.linktext; -} - -function composerSuggestionSelectionContextEqual( - left: ComposerSuggestion["selectionContext"], - right: ComposerSuggestion["selectionContext"], -): boolean { - if (left === right) return true; - if (!left || !right) return false; - return ( - left.name === right.name && - left.path === right.path && - left.linktext === right.linktext && - left.text === right.text && - left.range.from.line === right.range.from.line && - left.range.from.ch === right.range.from.ch && - left.range.to.line === right.range.to.line && - left.range.to.ch === right.range.to.ch - ); -} - function patchChatState(state: ChatState, patch: Partial): ChatState { return patchObject(state, patch); } diff --git a/tests/features/chat/application/state/root-reducer.test.ts b/tests/features/chat/application/state/root-reducer.test.ts index 62b5a345..0d634425 100644 --- a/tests/features/chat/application/state/root-reducer.test.ts +++ b/tests/features/chat/application/state/root-reducer.test.ts @@ -663,6 +663,26 @@ describe("chatReducer", () => { expect(state.runtime.pending.approvalsReviewer).toEqual({ kind: "unchanged" }); }); + it("updates composer suggestions when insertion-only fields change", () => { + const initialSuggestion = { + display: "Alpha", + detail: "alpha.md", + replacement: "[[Alpha]]", + start: 0, + tabCursorOffset: -2, + } satisfies ChatState["composer"]["suggestions"][number]; + const nextSuggestion = { + ...initialSuggestion, + tabCursorOffset: 0, + suffixOnInsert: "]]", + } satisfies ChatState["composer"]["suggestions"][number]; + + let state = chatReducer(chatStateFixture(), { type: "composer/suggestions-set", suggestions: [initialSuggestion] }); + state = chatReducer(state, { type: "composer/suggestions-set", suggestions: [nextSuggestion] }); + + expect(state.composer.suggestions).toEqual([nextSuggestion]); + }); + it("stores updates through ChatStateStore without mutating the initial snapshot", () => { let initial = chatStateFixture(); initial = withChatStateMessageStreamItems(initial, [message("initial")]);