Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions apps/web/src/components/ComposerPromptEditorTiptap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1013,7 +1013,7 @@ function ComposerPromptEditorTiptapInner(

const handleEditorChange = (updated: TiptapEditor) => {
const map = serializeEditorDoc(updated.state.doc);
const contextIds = literalText ? [] : map.contextIds;
const contextIds = literalText ? [] : [...map.contextIds];
const { from, to } = updated.state.selection;
const fromFlat = pmToFlat(map, from);
const toFlat = pmToFlat(map, to);
Expand Down Expand Up @@ -1468,7 +1468,7 @@ function ComposerPromptEditorTiptapInner(
value: map.value,
cursor: collapseExpandedComposerCursor(map.value, expandedCursor, literalText),
expandedCursor,
contextIds: literalText ? [] : map.contextIds,
contextIds: literalText ? [] : [...map.contextIds],
};
const toFlat = pmToFlat(map, to);
selectionRangeRef.current = {
Expand Down
22 changes: 18 additions & 4 deletions apps/web/src/composer-rich-text-doc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -811,11 +811,12 @@ export interface RichRun {
nodeName?: string;
}

// Shared by every caller that serializes the same doc, so it must not be mutated.
export interface RichDocMap {
value: string;
runs: RichRun[];
docLength: number;
contextIds: string[];
readonly value: string;
readonly runs: ReadonlyArray<Readonly<RichRun>>;
readonly docLength: number;
readonly contextIds: ReadonlyArray<string>;
}

function readAtomSource(node: ProseMirrorNode): string {
Expand Down Expand Up @@ -1285,7 +1286,20 @@ export function serializeSelection(doc: ProseMirrorNode, from: number, to: numbe
return serializeEditorDoc(doc.type.create(null, content)).value;
}

// Docs are immutable, and one keystroke serializes the same doc from the marker
// plugin, onUpdate, and onSelectionUpdate.
const serializedDocs = new WeakMap<ProseMirrorNode, RichDocMap>();

export function serializeEditorDoc(doc: ProseMirrorNode): RichDocMap {
let map = serializedDocs.get(doc);
if (!map) {
map = serializeDoc(doc);
serializedDocs.set(doc, map);
}
return map;
}

function serializeDoc(doc: ProseMirrorNode): RichDocMap {
const acc: RichAccumulator = { runs: [], value: "", flat: 0, md: 0 };
const blocks: ProseMirrorNode[] = [];
doc.content.forEach((node) => {
Expand Down
Loading