Skip to content

Commit

Permalink
Support document forking
Browse files Browse the repository at this point in the history
  • Loading branch information
davidbrochart committed Feb 23, 2024
1 parent 803631d commit 39c2489
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 2 deletions.
37 changes: 36 additions & 1 deletion javascript/src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import type {
JSONValue,
PartialJSONValue
} from '@lumino/coreutils';
import type { IObservableDisposable } from '@lumino/disposable';
import type { IDisposable, IObservableDisposable } from '@lumino/disposable';
import type { ISignal } from '@lumino/signaling';

/**
Expand Down Expand Up @@ -80,6 +80,19 @@ export interface ISharedBase extends IObservableDisposable {
transact(f: () => void, undoable?: boolean): void;
}

/**
* An interface for a document provider.
*/
export interface IDocumentProvider extends IDisposable {
/**
* Returns a Promise that resolves when the document provider is ready.
*/
readonly ready: Promise<void>;

fork(): Promise<void>;
connectFork(providerId: string, sharedDocument: ISharedDocument): IDocumentProvider;
}

/**
* Implement an API for Context information on the shared information.
* This is used by, for example, docregistry to share the file-path of the edited content.
Expand Down Expand Up @@ -114,6 +127,28 @@ export interface ISharedDocument extends ISharedBase {
* The changed signal.
*/
readonly changed: ISignal<this, DocumentChange>;

/**
* Get a provider with a given ID
*
* @param providerId The provider ID
*/
getProvider(providerId: string, sharedModel?: ISharedDocument): IDocumentProvider;

/**
* Set a provider for this document
*
* @param providerId Provider ID (either 'root' or a UUID)
* @param provider The document provider
*/
setProvider(providerId: string, provider: IDocumentProvider): void;

/**
* Add a fork ID to the document's ystate, as a new key 'fork_{forkId}'
*
* @param forkId The fork ID to add to the document
*/
addFork(forkId: string): void;
}

/**
Expand Down
27 changes: 26 additions & 1 deletion javascript/src/ydocument.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { JSONExt, JSONObject, JSONValue } from '@lumino/coreutils';
import { ISignal, Signal } from '@lumino/signaling';
import { Awareness } from 'y-protocols/awareness';
import * as Y from 'yjs';
import type { DocumentChange, ISharedDocument, StateChange } from './api.js';
import type { DocumentChange, IDocumentProvider, ISharedDocument, StateChange } from './api';

/**
* Generic shareable document.
Expand All @@ -28,13 +28,37 @@ export abstract class YDocument<T extends DocumentChange>
this._awareness = new Awareness(this._ydoc);

this._ystate.observe(this.onStateChanged);

this._providers = {};
}

/**
* Document version
*/
abstract readonly version: string;

addFork(forkId: string) {
this.ystate.set(`fork_${forkId}`, 'new');
}

getProvider(providerId: string, sharedModel?: ISharedDocument): IDocumentProvider {
if (!(providerId in this._providers)) {
if (providerId === 'root') {
throw new Error('Cannot get a new provider for root document');
}
if (sharedModel === undefined) {
throw new Error('New provider needs a shared document');
}
const root_provider = this._providers['root'];
this._providers[providerId] = root_provider.connectFork(providerId, sharedModel!);
}
return this._providers[providerId];
}

setProvider(providerId: string, provider: IDocumentProvider) {
this._providers[providerId] = provider;
}

/**
* YJS document.
*/
Expand Down Expand Up @@ -200,6 +224,7 @@ export abstract class YDocument<T extends DocumentChange>
private _awareness: Awareness;
private _isDisposed = false;
private _disposed = new Signal<this, void>(this);
private _providers: { [key: string]: IDocumentProvider };
}

/**
Expand Down

0 comments on commit 39c2489

Please sign in to comment.