Skip to content

Commit 2c82bc6

Browse files
committed
Cut history tests & fugue fixes
* Delete was deleting line block style * Insert was not working properly
1 parent 66d6c5d commit 2c82bc6

File tree

9 files changed

+148
-12
lines changed

9 files changed

+148
-12
lines changed

code/client/package.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,10 @@
3737
},
3838
"devDependencies": {
3939
"@testing-library/dom": "^10.1.0",
40-
"@testing-library/react": "^15.0.5",
40+
"@testing-library/react": "^15.0.6",
4141
"@testing-library/user-event": "^14.5.2",
4242
"@types/lodash": "^4.17.0",
43-
"@types/node": "^20.12.7",
43+
"@types/node": "^20.12.8",
4444
"@types/react": "^18.3.1",
4545
"@types/react-dom": "^18.3.0",
4646
"@types/react-router-dom": "^5.3.3",
@@ -67,5 +67,6 @@
6767
"vite-plugin-qrcode": "^0.2.3",
6868
"vite-tsconfig-paths": "^4.3.2",
6969
"vitest": "^1.5.3"
70-
}
70+
},
71+
"packageManager": "[email protected]+sha256.0624e30eff866cdeb363b15061bdb7fd9425b17bc1bb42c22f5f4efdea21f6b3"
7172
}

code/client/src/domain/editor/operations/markdown/operations.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,9 @@ export default (fugue: Fugue, { socket }: Communication): MarkdownDomainOperatio
6868
function deleteBlockStyles(selection: Selection) {
6969
if (isSelectionEmpty(selection)) return;
7070
const { start, end } = selection;
71-
if (start.column === 0 || start.line !== end.line) {
71+
72+
// Remove block styles if the selection is single position at beginning of a line or multi-line selection
73+
if((start === end && start.column === 0) || start.line !== end.line) {
7274
const newSelection = start.column !== 0 ? { start: { line: start.line + 1, column: 0 }, end } : selection;
7375
const operations = fugue.updateBlockStylesLocalBySelection('paragraph', newSelection);
7476
socket.emit('operation', operations);

code/client/src/domain/editor/slate/utils/selection.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Editor, Node, Point, Range } from 'slate';
1+
import {Editor, Node, Path, Point, Range} from 'slate';
22
import { Cursor, emptyCursor, emptySelection, Selection } from '@notespace/shared/types/cursor';
33
import { first, isEqual } from 'lodash';
44

@@ -45,7 +45,11 @@ export function pointToCursor(editor: Editor, point: Point): Cursor {
4545
const children = Node.children(editor, [line]);
4646
const cursor: Cursor = { line, column: point.offset };
4747
for (const entry of children) {
48-
if (entry[1][0] === point.path[0]) break;
48+
// If path has only one element and it is the same as the first element of the point path - same line
49+
if (point.path.length === 1 && point.path[0] === entry[1][0]) break;
50+
// Else verify if the path is the same
51+
if(Path.equals(entry[1], point.path)) break;
52+
4953
cursor.column += first(entry).text.length;
5054
}
5155
return cursor;

code/client/tests/editor/slate/handlers/history/cut-test.ts

Whitespace-only changes.
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
import {describe, test, expect, beforeEach} from "vitest";
2+
import {BaseRemoveTextOperation, Editor} from "slate";
3+
import {Fugue} from "@domain/editor/crdt/fugue";
4+
import {
5+
removeText,
6+
mockEditor,
7+
toBatch,
8+
applyBatch,
9+
getUndoOperations, getRedoOperations, removeNode
10+
} from "@tests/editor/slate/handlers/history/utils";
11+
import {toSlate} from "@domain/editor/slate/utils/slate";
12+
import {InsertTextOperation, RemoveTextOperation} from "@domain/editor/operations/history/types";
13+
import {pointToCursor} from "@domain/editor/slate/utils/selection";
14+
import {nodeInsert} from "@domain/editor/crdt/utils";
15+
16+
17+
let editor: Editor
18+
let fugue : Fugue
19+
20+
beforeEach(() => {
21+
editor = mockEditor();
22+
fugue = new Fugue();
23+
});
24+
25+
describe('Single line', () => {
26+
27+
describe('Single style', () => {
28+
29+
const cutSingleLine = () => {
30+
fugue.insertLocal({line: 0, column: 0}, ...'abcdef'.split(''));
31+
editor.children = toSlate(fugue);
32+
33+
const batch = toBatch(
34+
removeText('abcdef', [0,0], 0)
35+
);
36+
applyBatch(editor, batch);
37+
}
38+
39+
beforeEach(cutSingleLine);
40+
41+
test('Should undo cut', () => {
42+
const {operations} = getUndoOperations(editor, 1)
43+
44+
const operation = operations[0] as InsertTextOperation;
45+
46+
expect(operation.text).toStrictEqual('abcdef'.split(''));
47+
expect(operation.cursor).toEqual({line: 0, column: 0});
48+
49+
});
50+
51+
test('Should redo cut', () => {
52+
53+
const {operations, editorBatch} = getRedoOperations(editor, 1)
54+
55+
const operation = operations[0] as RemoveTextOperation;
56+
const editorOperation = editorBatch!.operations[0] as BaseRemoveTextOperation;
57+
58+
expect(operation.selection).toEqual(
59+
{
60+
start: pointToCursor(editor, {path: editorOperation.path, offset: 0}),
61+
end: pointToCursor(editor, {path: editorOperation.path, offset: editorOperation.offset + editorOperation.text.length - 1})
62+
}
63+
)
64+
});
65+
});
66+
67+
describe('Multiple styles', () => {
68+
const cutMultipleStyles = () => {
69+
fugue.insertLocal({line: 0, column: 0}, ...'abc'.split(''));
70+
fugue.insertLocal({line: 0, column: 3},
71+
nodeInsert('text', ['bold']),
72+
nodeInsert('text', ['italic']),
73+
);
74+
editor.children = toSlate(fugue);
75+
76+
const batch = toBatch(
77+
removeText('abc', [0, 0], 0),
78+
removeText('text', [0, 1], 0),
79+
removeNode({text: ''}, [0, 1]),
80+
removeText('text', [0, 2], 0),
81+
removeNode({text: ''}, [0, 2]),
82+
);
83+
editor.history.undos = [batch];
84+
}
85+
86+
beforeEach(cutMultipleStyles);
87+
88+
test('Should undo cut', () => {
89+
const {operations, editorBatch} = getUndoOperations(editor, 3); // remove node op. with empty text are ignored
90+
91+
const editorOperations = editorBatch!.operations.filter(op =>
92+
op.type === 'remove_text') as BaseRemoveTextOperation[];
93+
94+
95+
for (const i in operations) {
96+
const operation = operations[i] as InsertTextOperation;
97+
const editorOperation = editorOperations[i];
98+
99+
expect(operation.text).toStrictEqual(editorOperation.text.split(''));
100+
expect(operation.cursor).toEqual(pointToCursor(editor, {path: editorOperation.path, offset: editorOperation.offset}));
101+
}
102+
});
103+
104+
test('Should redo cut', () => {
105+
const {operations, editorBatch} = getRedoOperations(editor, 3);
106+
107+
const editorOperations = editorBatch!.operations.filter(op =>
108+
op.type === 'remove_text') as BaseRemoveTextOperation[];
109+
110+
for (const i in operations) {
111+
const operation = operations[i] as RemoveTextOperation;
112+
const editorOperation = editorOperations[i];
113+
114+
expect(operation.selection).toEqual({
115+
start: pointToCursor(editor, {path: editorOperation.path, offset: editorOperation.offset}),
116+
end: pointToCursor(editor, {path: editorOperation.path, offset: editorOperation.offset + editorOperation.text.length - 1})
117+
});
118+
}
119+
});
120+
});
121+
});
122+
123+
// describe('Multiple lines', () => {
124+
//
125+
//
126+
// });

code/client/tests/editor/slate/handlers/history/delete-text.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { BaseInsertTextOperation, BaseSetNodeOperation, Editor } from 'slate';
33
import { Fugue } from '@domain/editor/crdt/fugue';
44
import {
55
applyBatch,
6-
deleteText,
6+
removeText,
77
getRedoOperations,
88
getUndoOperations,
99
mockEditor,
@@ -34,7 +34,7 @@ describe('No style', () => {
3434
fugue.insertLocal({ line: 0, column: 0 }, ...'abc'.split(''));
3535
editor.children = toSlate(fugue);
3636

37-
const batch = toBatch(deleteText('a', [0, 0], 0));
37+
const batch = toBatch(removeText('a', [0, 0], 0));
3838

3939
applyBatch(editor, batch);
4040
};
@@ -109,7 +109,7 @@ describe('Inline Style', () => {
109109
fugue.insertLocal({ line: 0, column: 0 }, 'a');
110110
editor.children = toSlate(fugue);
111111

112-
const batch = toBatch(deleteText('b', [0, 1], 0), removeNode({ text: '', bold: true }, [0, 1]));
112+
const batch = toBatch(removeText('b', [0, 1], 0), removeNode({ text: '', bold: true }, [0, 1]));
113113
editor.history.undos = [batch];
114114
};
115115

code/client/tests/editor/slate/handlers/history/utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ export const insertText = (text: string, path: Path, offset: number): InsertText
3939
return { type: 'insert_text', path, offset, text };
4040
};
4141

42-
export const deleteText = (text: string, path: Path, offset: number): RemoveTextOperation => ({
42+
export const removeText = (text: string, path: Path, offset: number): RemoveTextOperation => ({
4343
type: 'remove_text',
4444
path,
4545
offset,

code/server/package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
"@types/express": "^4.17.21",
3030
"@types/jest": "^29.5.12",
3131
"@types/lodash": "^4.17.0",
32-
"@types/node": "^20.12.7",
32+
"@types/node": "^20.12.8",
3333
"@types/supertest": "^6.0.2",
3434
"@types/uuid": "^9.0.8",
3535
"@typescript-eslint/eslint-plugin": "^7.8.0",
@@ -46,5 +46,6 @@
4646
"tsconfig-paths": "^4.2.0",
4747
"tsx": "^4.8.2",
4848
"typescript": "^5.4.5"
49-
}
49+
},
50+
"packageManager": "[email protected]+sha256.0624e30eff866cdeb363b15061bdb7fd9425b17bc1bb42c22f5f4efdea21f6b3"
5051
}

code/server/src/controllers/ws/document/onOperation.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import { ForbiddenError, InvalidParameterError } from '@domain/errors/errors';
66

77
function onOperation(service: DocumentService) {
88
return async (socket: Socket, operations: Operation[]) => {
9+
10+
console.log('onOperation:', operations)
911
if (!operations) {
1012
throw new InvalidParameterError('Operations are required');
1113
}

0 commit comments

Comments
 (0)