Compare commits

..

4 Commits

Author SHA1 Message Date
Kevin Jahns
4f2d13e3ce 13.5.2 2021-03-11 18:54:02 +01:00
Kevin Jahns
e0b76cd2f4 [UndoManager] stop tracking unrelated insertions - yjs/y-monaco#10 2021-03-11 18:52:35 +01:00
Kevin Jahns
d812636c5b Implement doc suggestions - closes #249 2021-03-03 12:20:53 +01:00
Kevin Jahns
21fee0fe96 spelling issue lib0 repetition 2021-02-28 16:09:54 +01:00
4 changed files with 48 additions and 59 deletions

View File

@@ -320,6 +320,8 @@ or any of its children.
<dl>
<b><code>parent:Y.AbstractType|null</code></b>
<dd></dd>
<b><code>size: number</code></b>
<dd>Total number of key/value pairs.</dd>
<b><code>get(key:string):object|boolean|string|number|Uint8Array|Y.Type</code></b>
<dd></dd>
<b><code>set(key:string, value:object|boolean|string|number|Uint8Array|Y.Type)</code></b>
@@ -410,7 +412,7 @@ YTextEvents compute changes as deltas.
<dd></dd>
<b><code>format(index:number, length:number, formattingAttributes:Object&lt;string,string&gt;)</code></b>
<dd>Assign formatting attributes to a range in the text</dd>
<b><code>applyDelta(delta, opts:Object&lt;string,any&gt;)</code></b>
<b><code>applyDelta(delta: Delta, opts:Object&lt;string,any&gt;)</code></b>
<dd>
See <a href="https://quilljs.com/docs/delta/">Quill Delta</a>
Can set options for preventing remove ending newLines, default is true.
@@ -483,6 +485,8 @@ or any of its children.
<dd>Get the XML serialization of all descendants.</dd>
<b><code>toJSON():string</code></b>
<dd>See <code>toString</code>.</dd>
<b><code>createTreeWalker(filter: function(AbstractType&lt;any&gt;):boolean):Iterable</code></b>
<dd>Create an Iterable that walks through the children.</dd>
<b><code>observe(function(YXmlEvent, Transaction):void)</code></b>
<dd>
Adds an event listener to this type that will be called synchronously every time
@@ -540,7 +544,7 @@ content and be actually XML compliant.
<dd></dd>
<b><code>getAttribute(attributeName:string):string</code></b>
<dd></dd>
<b><code>getAttributes(attributeName:string):Object&lt;string,string&gt;</code></b>
<b><code>getAttributes():Object&lt;string,string&gt;</code></b>
<dd></dd>
<b><code>get(i:number):Y.XmlElement|Y.XmlText</code></b>
<dd>Retrieve the i-th element.</dd>
@@ -609,7 +613,10 @@ parameter that is stored on <code>transaction.origin</code> and
</dd>
<b><code>toJSON():any</code></b>
<dd>
Converts the entire document into a js object, recursively traversing each yjs type.
Deprecated: It is recommended to call toJSON directly on the shared types.
Converts the entire document into a js object, recursively traversing each yjs
type. Doesn't log types that have not been defined (using
<code>ydoc.getType(..)</code>).
</dd>
<b><code>get(string, Y.[TypeClass]):[Type]</code></b>
<dd>Define a shared type.</dd>

2
package-lock.json generated
View File

@@ -1,6 +1,6 @@
{
"name": "yjs",
"version": "13.5.1",
"version": "13.5.2",
"lockfileVersion": 1,
"requires": true,
"dependencies": {

View File

@@ -1,6 +1,6 @@
{
"name": "yjs",
"version": "13.5.1",
"version": "13.5.2",
"description": "Shared Editing Library",
"main": "./dist/yjs.cjs",
"module": "./dist/yjs.mjs",
@@ -12,14 +12,14 @@
"url": "https://github.com/sponsors/dmonad"
},
"scripts": {
"test": "npm run dist && node ./dist/tests.cjs --repitition-time 50",
"test-extensive": "npm run lint && npm run dist && node ./dist/tests.cjs --production --repitition-time 10000",
"test": "npm run dist && node ./dist/tests.cjs --repetition-time 50",
"test-extensive": "npm run lint && npm run dist && node ./dist/tests.cjs --production --repetition-time 10000",
"dist": "rm -rf dist && rollup -c && tsc",
"watch": "rollup -wc",
"lint": "markdownlint README.md && standard && tsc",
"docs": "rm -rf docs; jsdoc --configure ./.jsdoc.json --verbose --readme ./README.md --package ./package.json || true",
"serve-docs": "npm run docs && http-server ./docs/",
"preversion": "npm run lint && PRODUCTION=1 npm run dist && npm run docs && node ./dist/tests.cjs --repitition-time 1000 && test -e dist/src/index.d.ts && test -e dist/yjs.cjs && test -e dist/yjs.cjs",
"preversion": "npm run lint && PRODUCTION=1 npm run dist && npm run docs && node ./dist/tests.cjs --repetition-time 1000 && test -e dist/src/index.d.ts && test -e dist/yjs.cjs && test -e dist/yjs.cjs",
"debug": "concurrently 'http-server -o test.html' 'npm run watch'",
"trace-deopt": "clear && rollup -c && node --trace-deopt dist/test.cjs",
"trace-opt": "clear && rollup -c && node --trace-opt dist/test.cjs",

View File

@@ -5,11 +5,11 @@ import {
transact,
createID,
redoItem,
iterateStructs,
isParentOf,
followRedone,
getItemCleanStart,
getState,
isDeleted,
addToDeleteSet,
Transaction, Doc, Item, GC, DeleteSet, AbstractType, YEvent // eslint-disable-line
} from '../internals.js'
@@ -18,14 +18,12 @@ import { Observable } from 'lib0/observable.js'
class StackItem {
/**
* @param {DeleteSet} ds
* @param {Map<number,number>} beforeState
* @param {Map<number,number>} afterState
* @param {DeleteSet} deletions
* @param {DeleteSet} insertions
*/
constructor (ds, beforeState, afterState) {
this.ds = ds
this.beforeState = beforeState
this.afterState = afterState
constructor (deletions, insertions) {
this.insertions = insertions
this.deletions = deletions
/**
* Use this to save and restore metadata like selection range
*/
@@ -65,48 +63,26 @@ const popStackItem = (undoManager, stack, eventType) => {
*/
const itemsToDelete = []
let performedChange = false
stackItem.afterState.forEach((endClock, client) => {
const startClock = stackItem.beforeState.get(client) || 0
const len = endClock - startClock
// @todo iterateStructs should not need the structs parameter
const structs = /** @type {Array<GC|Item>} */ (store.clients.get(client))
if (startClock !== endClock) {
// make sure structs don't overlap with the range of created operations [stackItem.start, stackItem.start + stackItem.end)
// this must be executed before deleted structs are iterated.
getItemCleanStart(transaction, createID(client, startClock))
if (endClock < getState(doc.store, client)) {
getItemCleanStart(transaction, createID(client, endClock))
}
iterateStructs(transaction, structs, startClock, len, struct => {
if (struct instanceof Item) {
if (struct.redone !== null) {
let { item, diff } = followRedone(store, struct.id)
if (diff > 0) {
item = getItemCleanStart(transaction, createID(item.id.client, item.id.clock + diff))
}
if (item.length > len) {
getItemCleanStart(transaction, createID(item.id.client, endClock))
}
struct = item
}
if (!struct.deleted && scope.some(type => isParentOf(type, /** @type {Item} */ (struct)))) {
itemsToDelete.push(struct)
}
iterateDeletedStructs(transaction, stackItem.insertions, struct => {
if (struct instanceof Item) {
if (struct.redone !== null) {
let { item, diff } = followRedone(store, struct.id)
if (diff > 0) {
item = getItemCleanStart(transaction, createID(item.id.client, item.id.clock + diff))
}
})
struct = item
}
if (!struct.deleted && scope.some(type => isParentOf(type, /** @type {Item} */ (struct)))) {
itemsToDelete.push(struct)
}
}
})
iterateDeletedStructs(transaction, stackItem.ds, struct => {
const id = struct.id
const clock = id.clock
const client = id.client
const startClock = stackItem.beforeState.get(client) || 0
const endClock = stackItem.afterState.get(client) || 0
iterateDeletedStructs(transaction, stackItem.deletions, struct => {
if (
struct instanceof Item &&
scope.some(type => isParentOf(type, struct)) &&
// Never redo structs in [stackItem.start, stackItem.start + stackItem.end) because they were created and deleted in the same capture interval.
!(clock >= startClock && clock < endClock)
// Never redo structs in stackItem.insertions because they were created and deleted in the same capture interval.
!isDeleted(stackItem.insertions, struct.id)
) {
itemsToRedo.add(struct)
}
@@ -201,17 +177,23 @@ export class UndoManager extends Observable {
// neither undoing nor redoing: delete redoStack
this.redoStack = []
}
const beforeState = transaction.beforeState
const afterState = transaction.afterState
const insertions = new DeleteSet()
transaction.afterState.forEach((endClock, client) => {
const startClock = transaction.beforeState.get(client) || 0
const len = endClock - startClock
if (len > 0) {
addToDeleteSet(insertions, client, startClock, len)
}
})
const now = time.getUnixTime()
if (now - this.lastChange < captureTimeout && stack.length > 0 && !undoing && !redoing) {
// append change to last stack op
const lastOp = stack[stack.length - 1]
lastOp.ds = mergeDeleteSets([lastOp.ds, transaction.deleteSet])
lastOp.afterState = afterState
lastOp.deletions = mergeDeleteSets([lastOp.deletions, transaction.deleteSet])
lastOp.insertions = mergeDeleteSets([lastOp.insertions, insertions])
} else {
// create a new stack op
stack.push(new StackItem(transaction.deleteSet, beforeState, afterState))
stack.push(new StackItem(transaction.deleteSet, insertions))
}
if (!undoing && !redoing) {
this.lastChange = now
@@ -232,7 +214,7 @@ export class UndoManager extends Observable {
* @param {StackItem} stackItem
*/
const clearItem = stackItem => {
iterateDeletedStructs(transaction, stackItem.ds, item => {
iterateDeletedStructs(transaction, stackItem.deletions, item => {
if (item instanceof Item && this.scope.some(type => isParentOf(type, item))) {
keepItem(item, false)
}