feat: F4.6f2 the text editor on the document's Y.Text, files both ways while the simulation runs
Oracle TextEditorWindowRun uses Java's text editor window and its file dialog as a person does. The open file's text is its Y.Text in the document (plan 7.3): typed is in the file at once, for everyone and for the running engine. Core openText/saveTextAs without Java's mistakes (lost saves after save-as onto a file or a removed file, files named 'ordner/d.txt' or ''); doc files.ts (changeFiles, fileText, nodeFiles, readFilesInto); the room takes a person's files into the engine at once and writes the engine's files back at the tick they changed; the editor's window, Java's dialog, the text area following others' changes with the caret in place, its own undo. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
// Where the caret and the selection go when another changes the open file's
|
||||
// text (textBinding.ts): moved by what was inserted or deleted before them,
|
||||
// left before what another inserts just at them — the deltas as Yjs gives them.
|
||||
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import * as Y from 'yjs';
|
||||
import { mapIndex, type TextDelta } from '../src/desktop/textBinding.js';
|
||||
|
||||
/** The delta of a change to a text that held `before`. */
|
||||
function deltaOf(before: string, change: (text: Y.Text) => void): TextDelta {
|
||||
const doc = new Y.Doc();
|
||||
const text = doc.getText('t');
|
||||
text.insert(0, before);
|
||||
let delta: TextDelta = [];
|
||||
text.observe((event) => (delta = event.delta as TextDelta));
|
||||
change(text);
|
||||
return delta;
|
||||
}
|
||||
|
||||
describe('a place in the text after another’s change', () => {
|
||||
it('moves by what was inserted before it, not by what came after it or just at it', () => {
|
||||
const insert = deltaOf('Hallo Welt', (text) => text.insert(6, 'schöne '));
|
||||
expect([0, 5, 6, 7, 10].map((index) => mapIndex(index, insert))).toEqual([0, 5, 6, 14, 17]);
|
||||
expect(
|
||||
mapIndex(
|
||||
3,
|
||||
deltaOf('abc', (text) => text.insert(0, 'xy')),
|
||||
),
|
||||
).toBe(5);
|
||||
expect(
|
||||
mapIndex(
|
||||
0,
|
||||
deltaOf('abc', (text) => text.insert(0, 'xy')),
|
||||
),
|
||||
).toBe(0);
|
||||
});
|
||||
|
||||
it('moves back by what was deleted before it, to where the deletion began when it lay inside', () => {
|
||||
const removed = deltaOf('Hallo schöne Welt', (text) => text.delete(6, 7));
|
||||
expect([0, 6, 9, 13, 17].map((index) => mapIndex(index, removed))).toEqual([0, 6, 6, 6, 10]);
|
||||
});
|
||||
|
||||
it('takes a replacement as its deletion and then its insertion: a place at the end of what was replaced stays before the new text', () => {
|
||||
const replaced = deltaOf('Erster Stand', (text) => {
|
||||
text.doc!.transact(() => {
|
||||
text.delete(0, 6);
|
||||
text.insert(0, 'Zweiter');
|
||||
});
|
||||
});
|
||||
expect(replaced).toEqual([{ delete: 6 }, { insert: 'Zweiter' }]);
|
||||
expect([0, 3, 6, 7, 12].map((index) => mapIndex(index, replaced))).toEqual([0, 0, 0, 8, 13]);
|
||||
// An embedded object counts as one place.
|
||||
expect(mapIndex(2, [{ insert: { image: 'x' } }])).toBe(3);
|
||||
expect(mapIndex(2, [{ retain: 2 }, { insert: { image: 'x' } }])).toBe(2);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user