Skip to content

Commit b849288

Browse files
authored
Merge pull request #728 from streamich/text-navigation
Text navigation
2 parents 5b6068b + 124810c commit b849288

13 files changed

+1024
-224
lines changed

src/json-crdt-extensions/peritext/__tests__/Peritext.render-block.spec.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -220,17 +220,17 @@ runInlineSlicesTests('text with block split', (editor: Editor) => {
220220
runInlineSlicesTests('text with deletes', (editor: Editor) => {
221221
editor.insert('lmXXXnwYxyz');
222222
editor.cursor.setAt(2, 3);
223-
editor.cursor.delBwd();
223+
editor.cursor.del();
224224
editor.cursor.setAt(3);
225225
editor.insert('opqrstuv');
226226
editor.cursor.setAt(12, 1);
227-
editor.cursor.delBwd();
227+
editor.cursor.del();
228228
editor.cursor.setAt(0);
229229
editor.insert('ab1c3defghijk4444');
230230
editor.cursor.setAt(2, 1);
231-
editor.cursor.delBwd();
231+
editor.cursor.del();
232232
editor.cursor.setAt(3, 1);
233-
editor.cursor.delBwd();
233+
editor.cursor.del();
234234
editor.cursor.setAt(11, 4);
235-
editor.cursor.delBwd();
235+
editor.cursor.del();
236236
});

src/json-crdt-extensions/peritext/__tests__/Peritext.spec.ts

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -229,45 +229,45 @@ const run = (setup: () => Kit) => {
229229
test('does nothing when deleting at the start of a string', () => {
230230
const {peritext} = setup();
231231
const {editor} = peritext;
232-
editor.delBwd();
232+
editor.del();
233233
expect(peritext.str.view()).toBe('hello world');
234234
});
235235

236236
test('can delete one character at the beginning of a string', () => {
237237
const {peritext} = setup();
238238
const {editor} = peritext;
239239
editor.cursor.setAt(1);
240-
editor.delBwd();
240+
editor.del();
241241
expect(peritext.str.view()).toBe('ello world');
242-
editor.delBwd();
242+
editor.del();
243243
expect(peritext.str.view()).toBe('ello world');
244-
editor.delBwd();
244+
editor.del();
245245
expect(peritext.str.view()).toBe('ello world');
246246
});
247247

248248
test('can delete two characters at the beginning of a string', () => {
249249
const {peritext} = setup();
250250
const {editor} = peritext;
251251
editor.cursor.setAt(2);
252-
editor.delBwd();
252+
editor.del();
253253
expect(peritext.str.view()).toBe('hllo world');
254-
editor.delBwd();
254+
editor.del();
255255
expect(peritext.str.view()).toBe('llo world');
256-
editor.delBwd();
256+
editor.del();
257257
expect(peritext.str.view()).toBe('llo world');
258258
});
259259

260260
test('can delete a range selection', () => {
261261
const {peritext} = setup();
262262
const {editor} = peritext;
263263
editor.cursor.setAt(2, 3);
264-
editor.delBwd();
264+
editor.del();
265265
expect(peritext.str.view()).toBe('he world');
266-
editor.delBwd();
266+
editor.del();
267267
expect(peritext.str.view()).toBe('h world');
268-
editor.delBwd();
268+
editor.del();
269269
expect(peritext.str.view()).toBe(' world');
270-
editor.delBwd();
270+
editor.del();
271271
expect(peritext.str.view()).toBe(' world');
272272
});
273273
});

src/json-crdt-extensions/peritext/editor/Cursor.ts

Lines changed: 39 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import {tick} from '../../../json-crdt-patch';
2-
import {Anchor} from '../rga/constants';
32
import {Point} from '../rga/Point';
43
import {CursorAnchor} from '../slice/constants';
54
import {PersistedSlice} from '../slice/PersistedSlice';
@@ -9,6 +8,16 @@ export class Cursor<T = string> extends PersistedSlice<T> {
98
return this.type as CursorAnchor;
109
}
1110

11+
/** @todo Rename to `isStartFocus`. */
12+
public isStartFocused(): boolean {
13+
return this.type === CursorAnchor.End || this.start.cmp(this.end) === 0;
14+
}
15+
16+
/** @todo Rename to `isEndFocus`. */
17+
public isEndFocused(): boolean {
18+
return this.type === CursorAnchor.Start || this.start.cmp(this.end) === 0;
19+
}
20+
1221
// ---------------------------------------------------------------- mutations
1322

1423
public set anchorSide(value: CursorAnchor) {
@@ -36,7 +45,7 @@ export class Cursor<T = string> extends PersistedSlice<T> {
3645
* Move one of the edges of the cursor to a new point.
3746
*
3847
* @param point Point to set the edge to.
39-
* @param endpoint 0 for "focus", 1 for "anchor."
48+
* @param endpoint 0 for "focus", 1 for "anchor".
4049
*/
4150
public setEndpoint(point: Point<T>, endpoint: 0 | 1 = 0): void {
4251
if (this.start === this.end) this.end = this.end.clone();
@@ -50,8 +59,8 @@ export class Cursor<T = string> extends PersistedSlice<T> {
5059

5160
public move(move: number): void {
5261
const {start, end} = this;
53-
start.move(move);
54-
if (start !== end) end.move(move);
62+
start.step(move);
63+
if (start !== end) end.step(move);
5564
this.set(start, end);
5665
}
5766

@@ -66,11 +75,7 @@ export class Cursor<T = string> extends PersistedSlice<T> {
6675
*/
6776
public collapse(): void {
6877
const deleted = this.txt.delStr(this);
69-
if (deleted) {
70-
const {start, rga} = this;
71-
if (start.anchor === Anchor.After) this.setAfter(start.id);
72-
else this.setAfter(start.prevId() || rga.id);
73-
}
78+
if (deleted) this.collapseToStart();
7479
}
7580

7681
/**
@@ -87,14 +92,32 @@ export class Cursor<T = string> extends PersistedSlice<T> {
8792
this.setAfter(shift ? tick(textId, shift) : textId);
8893
}
8994

90-
public delBwd(): void {
91-
const isCollapsed = this.isCollapsed();
92-
if (isCollapsed) {
93-
const range = this.txt.findCharBefore(this.start);
94-
if (!range) return;
95-
this.set(range.start, range.end);
95+
/**
96+
* Deletes the given number of characters from the current caret position.
97+
* Negative values delete backwards. If the cursor selects a range, the
98+
* range is removed and the cursor is set at the start of the range.
99+
*
100+
* @param step Number of characters to delete. Negative values delete
101+
* backwards.
102+
*/
103+
public del(step: number = -1): void {
104+
if (!this.isCollapsed()) {
105+
this.collapse();
106+
return;
96107
}
97-
this.collapse();
108+
const point1 = this.start.clone();
109+
const point2 = point1.clone();
110+
if (step > 0) point2.step(1);
111+
else if (step < 0) point1.step(-1);
112+
else if (step === 0) {
113+
point1.step(-1);
114+
point2.step(1);
115+
}
116+
const txt = this.txt;
117+
const range = txt.range(point1, point2);
118+
txt.delStr(range);
119+
point1.refAfter();
120+
this.set(point1);
98121
}
99122

100123
// ---------------------------------------------------------------- Printable

0 commit comments

Comments
 (0)