Divec has uploaded a new change for review. https://gerrit.wikimedia.org/r/319522
Change subject: WIP: Partial change rebasing in the case of conflicts ...................................................................... WIP: Partial change rebasing in the case of conflicts Change-Id: Ice73a863008c41078c2d931cd1f84a2a4661a9c2 --- M src/dm/ve.dm.Change.js M tests/dm/ve.dm.Change.test.js 2 files changed, 35 insertions(+), 19 deletions(-) git pull ssh://gerrit.wikimedia.org:29418/VisualEditor/VisualEditor refs/changes/22/319522/1 diff --git a/src/dm/ve.dm.Change.js b/src/dm/ve.dm.Change.js index 10dd578..f224d3c 100644 --- a/src/dm/ve.dm.Change.js +++ b/src/dm/ve.dm.Change.js @@ -193,8 +193,8 @@ * rebased onto a1 * ... * aN . Iteratively we can take the same approach to rebase over * b2,...,bM, giving both rebased lists as required. * - * If any of the transaction rebases conflict, then we immediately return a conflict for the - * whole change rebase. + * If any of the transaction rebases conflict, then we return all of a1,...,aN rebased onto + * the largest non-conflicting initial segment b1,...,bK (where clearly K < M). * * If ordering is ambiguous (two inserts at the same location), the insert for the transaction * with the highest author ID is put first (Javascript less-than is used, so comparisons with @@ -203,11 +203,14 @@ * * @param {ve.dm.Change} changeA A change * @param {ve.dm.Change} changeB Another change - * @return {ve.dm.Change[]} [ changeAOnChangeB, changeBOnChangeA ], or [ null, null ] if conflict - * @throws {Error} If changeA and changeB have different starts + * @return {Object} Rebased changeA and (the largest non-conflicting initial segment of) changeB + * @return {ve.dm.Change} return.a All of changeA rebased onto an initial segment of changeB + * @return {ve.dm.Change} return.b An initial segment of changeB rebased onto all of changeA + * @return {boolean} return.conflict Whether part of changeB was rejected due to conflict */ ve.dm.Change.static.rebaseChanges = function ( changeA, changeB ) { - var i, iLen, b, j, jLen, a, rebases, + var i, iLen, b, j, jLen, a, rebases, rebasedTransactionsA, + conflict = false, transactionsA = changeA.transactions.slice(), transactionsB = changeB.transactions.slice(); @@ -234,9 +237,11 @@ // // These identities hold if all the rebases work; if any of them fail, the entire // rebase fails and we return null values. + bLoop: for ( i = 0, iLen = transactionsB.length; i < iLen; i++ ) { b = transactionsB[ i ]; // Rebase transactions list onto otherTx + rebasedTransactionsA = []; for ( j = 0, jLen = transactionsA.length; j < jLen; j++ ) { a = transactionsA[ j ]; if ( a.author < b.author ) { @@ -244,30 +249,34 @@ } else { rebases = ve.dm.Transaction.rebaseTransactions( a, b ); } - transactionsA[ j ] = rebases[ 0 ]; - b = rebases[ 1 ]; - if ( b === null ) { - return [ null, null ]; + if ( rebases[ 0 ] === null ) { + conflict = true; + transactionsB.length = i; + break bLoop; } + rebasedTransactionsA[ j ] = rebases[ 0 ]; + b = rebases[ 1 ]; } + transactionsA = rebasedTransactionsA; transactionsB[ i ] = b; } - return [ + return { // These length calculations assume no removal of empty rebased transactions - new ve.dm.Change( - changeA.transactionStart + changeB.transactions.length, + a: new ve.dm.Change( + changeA.transactionStart + transactionsB.length, transactionsA, changeB.storeStart + changeB.store.getLength(), changeA.store.difference( changeB.store ) ), - new ve.dm.Change( - changeB.transactionStart + changeA.transactions.length, + b: new ve.dm.Change( + changeB.transactionStart + transactionsA.length, transactionsB, changeA.storeStart + changeA.store.getLength(), changeB.store.difference( changeA.store ) - ) - ]; + ), + conflict: conflict + }; }; /* Methods */ @@ -312,10 +321,13 @@ * @throws {Error} If this change and other have different starts */ ve.dm.Change.prototype.rebasedOnto = function ( other, startmost ) { + var rebases; if ( startmost ) { - return this.constructor.static.rebaseChanges( this, other )[ 0 ]; + rebases = this.constructor.static.rebaseChanges( this, other ); + return rebases.conflict ? null : rebases.a; } else { - return this.constructor.static.rebaseChanges( other, this )[ 1 ]; + rebases = this.constructor.static.rebaseChanges( other, this ); + return rebases.conflict ? null : rebases.b; } }; diff --git a/tests/dm/ve.dm.Change.test.js b/tests/dm/ve.dm.Change.test.js index 48b3afe..dea7150 100644 --- a/tests/dm/ve.dm.Change.test.js +++ b/tests/dm/ve.dm.Change.test.js @@ -120,7 +120,11 @@ 'Apply (insert1 then insert2*replace2 then underline3) reversed' ); - assert.strictEqual( replace2.rebasedOnto( remove2 ), null, 'Rebase replace2 onto remove2' ); + assert.deepEqual( + ve.dm.Change.static.rebaseChanges( remove2, replace2 ).b.transactions, + [], + 'Conflict rebasing replace2 onto remove2' + ); } ); QUnit.test( 'Serialize/deserialize', 4, function ( assert ) { -- To view, visit https://gerrit.wikimedia.org/r/319522 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Ice73a863008c41078c2d931cd1f84a2a4661a9c2 Gerrit-PatchSet: 1 Gerrit-Project: VisualEditor/VisualEditor Gerrit-Branch: master Gerrit-Owner: Divec <da...@troi.org> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits