Skip to content
Snippets Groups Projects
Commit 07c27d52 authored by Loïc Correnson's avatar Loïc Correnson
Browse files

[dome/richtext] diff incremental updates

parent 9c68927c
No related branches found
No related tags found
No related merge requests found
...@@ -24,7 +24,7 @@ import React, { CSSProperties } from 'react'; ...@@ -24,7 +24,7 @@ import React, { CSSProperties } from 'react';
import { classes } from 'dome/misc/utils'; import { classes } from 'dome/misc/utils';
import * as CS from '@codemirror/state'; import * as CS from '@codemirror/state';
import * as CM from '@codemirror/view'; import * as CM from '@codemirror/view';
// import { diffLines } from 'diff'; import { Change, diffLines } from 'diff';
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
/* --- Basic Definitions --- */ /* --- Basic Definitions --- */
...@@ -50,11 +50,50 @@ function appendContents(view: CM.EditorView, text: string): void { ...@@ -50,11 +50,50 @@ function appendContents(view: CM.EditorView, text: string): void {
view.dispatch({ changes: { from: length, insert: text } }); view.dispatch({ changes: { from: length, insert: text } });
} }
function dispatchContents(view: CM.EditorView, text: string): void { function dispatchContents(view: CM.EditorView, text: string | CS.Text): void {
const length = view.state.doc.length; const length = view.state.doc.length;
view.dispatch({ changes: { from: 0, to: length, insert: text } }); view.dispatch({ changes: { from: 0, to: length, insert: text } });
} }
class DiffBuffer {
private readonly changes : CS.ChangeSpec[] = [];
private offset = 0;
private added = '';
private removed = 0;
constructor() { this.add = this.add.bind(this); }
private commit(forward=0): void {
const { changes, offset, added, removed } = this;
if (added || removed) {
const nextOffset = offset + removed;
changes.push({ from: offset, to: nextOffset, insert: added });
this.offset = nextOffset + forward;
this.added = '';
this.removed = 0;
} else
if (forward) this.offset += forward;
}
add(c : Change): void {
if (c.added) this.added += c.value;
if (c.removed) this.removed += c.value.length;
if (!c.added && !c.removed) this.commit(c.value.length);
}
flush(): CS.ChangeSpec {
this.commit();
return this.changes;
}
}
function updateContents(view: CM.EditorView, newText: string): void {
const buffer = new DiffBuffer();
diffLines(view.state.doc.toString(), newText).forEach(buffer.add);
view.dispatch({ changes: buffer.flush() });
}
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
/* --- Text Proxy --- */ /* --- Text Proxy --- */
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
...@@ -89,7 +128,7 @@ export class TextProxy { ...@@ -89,7 +128,7 @@ export class TextProxy {
clear(): void { clear(): void {
const view = this.proxy; const view = this.proxy;
if (view) dispatchContents(view, ''); if (view) dispatchContents(view, CS.Text.empty);
} }
toString(): string { toString(): string {
...@@ -107,6 +146,12 @@ export class TextProxy { ...@@ -107,6 +146,12 @@ export class TextProxy {
if (view) dispatchContents(view, data); if (view) dispatchContents(view, data);
} }
/** Uses diff changes instead of replacing the entire view's contents. */
updateContents(data: string): void {
const view = this.proxy;
if (view) updateContents(view, data);
}
} }
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
...@@ -145,11 +190,12 @@ export class TextBuffer extends TextProxy { ...@@ -145,11 +190,12 @@ export class TextBuffer extends TextProxy {
// invariant preserved // invariant preserved
} }
if (newView) { if (newView) {
dispatchContents(newView, this.toString()); const newData = this.contents ?? this.text;
this.proxy = newView; this.proxy = newView;
this.text = CS.Text.empty; this.text = CS.Text.empty;
this.contents = undefined; this.contents = undefined;
// invariant established // invariant established
dispatchContents(newView, newData);
} }
} }
...@@ -157,7 +203,7 @@ export class TextBuffer extends TextProxy { ...@@ -157,7 +203,7 @@ export class TextBuffer extends TextProxy {
clear(): void { clear(): void {
const view = this.proxy; const view = this.proxy;
if (view) dispatchContents(view, ''); if (view) dispatchContents(view, CS.Text.empty);
else { else {
this.text = CS.Text.empty; this.text = CS.Text.empty;
this.contents = undefined; this.contents = undefined;
...@@ -191,6 +237,17 @@ export class TextBuffer extends TextProxy { ...@@ -191,6 +237,17 @@ export class TextBuffer extends TextProxy {
} }
} }
/** Uses diff changes instead of replacing the entire view's contents. */
updateContents(data: string): void {
const view = this.proxy;
if (view) updateContents(view, data);
else {
this.contents = data;
this.text = CS.Text.empty;
// invariant established
}
}
} }
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment