diff --git a/README.md b/README.md index e4412c5..3a61d0f 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,7 @@ Undo-Redo history. Basic features: * [`H.init({[maxCount, pushEquals, replacePeriod]}, value) ~> history`](#H-init) v0.1.0 * [Present](#present) * [`H.present ~> valueLens`](#H-present) v0.2.0 + * [`H.presentReplace ~> valueLens`](#H-presentReplace) v1.3.0 * [Undo](#undo) * [`H.undoForget(history) ~> history`](#H-undoForget) v0.1.0 * [`H.undoIndex ~> numberLens`](#H-undoIndex) v0.2.0 @@ -285,6 +286,26 @@ thru( Note that modifications through `H.present` are not referentially transparent operations, because setting through `H.present` takes a timestamp underneath. +#### [≡](#contents) [▶](https://calmm-js.github.io/partial.lenses.history/index.html#H-presentReplace) [`H.presentReplace ~> valueLens`](#H-presentReplace) v1.3.0 + +`H.presentReplace` is a +[lens](https://github.com/calmm-js/partial.lenses/#partial-lenses) that focuses +on the present value of history. When read it behaves exactly as [`H.present`](#H-present). When written it does *not* create a new history entry but instead replaces the current one. This might be useful for applying multiple changes in squence without polluting the history. + +For example: + +```js +thru( + H.init({}, 42), + L.modify(H.presentReplace, x => -x), + L.get(H.undoIndex) +) +// 0 +``` + +Note that modifications through `H.presentReplace` are not referentially transparent +operations, because setting through `H.presentReplace` takes a timestamp underneath. + ### [≡](#contents) [▶](https://calmm-js.github.io/partial.lenses.history/index.html#undo) [Undo](#undo) #### [≡](#contents) [▶](https://calmm-js.github.io/partial.lenses.history/index.html#H-undoForget) [`H.undoForget(history) ~> history`](#H-undoForget) v0.1.0 diff --git a/package.json b/package.json index 14b234a..6b5e8f9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "partial.lenses.history", - "version": "1.2.0", + "version": "1.3.0", "description": "Partial Lenses History is a JavaScript library for Undo-Redo", "module": "dist/partial.lenses.history.es.js", "main": "dist/partial.lenses.history.cjs.js", diff --git a/src/core.js b/src/core.js index 326ad68..dc5638d 100644 --- a/src/core.js +++ b/src/core.js @@ -33,6 +33,26 @@ function setPresentU(value, history) { ) } +function setPresentReplaceU(value, history) { + const v = history.v + const i = history.i + const c = history.c + if (c.e) { + if (I.acyclicEqualsU(S.nth(i, v), value)) { + return history + } + } + const t = history.t + const now = Date.now() + const j0 = Math.max(0, i - c.m) + return construct( + i - j0, + S.append(now, S.slice(j0, i, t)), + S.append(value, S.slice(j0, i, v)), + c + ) +} + const setIndexU = (index, history) => construct( Math.max(0, Math.min(index, indexMax(history))), @@ -69,6 +89,10 @@ export const present = L.lens(function present(history) { return S.nth(history.i, history.v) }, setPresentU) +export const presentReplace = L.lens(function presentReplace(history) { + return S.nth(history.i, history.v) +}, setPresentReplaceU) + // Undo export {index as undoIndex} diff --git a/src/partial.lenses.history.js b/src/partial.lenses.history.js index 4c0ca79..d1ad9b7 100644 --- a/src/partial.lenses.history.js +++ b/src/partial.lenses.history.js @@ -45,6 +45,7 @@ export const init = C( // Present export const present = C(H.present, lens(history, V.any)) +export const presentReplace = C(H.presentReplace, lens(history, V.any)) // Undo diff --git a/test/tests.js b/test/tests.js index 2ca5d6f..23997fa 100644 --- a/test/tests.js +++ b/test/tests.js @@ -113,6 +113,19 @@ describe('History', () => { ) }) + testEq([1, 2, 5, 6], async () => { + let h = H.init({pushEquals: true}, 1) + h = L.set(H.present, 2, h) + h = L.set(H.present, 3, h) + h = L.set(H.presentReplace, 4, h) + h = L.set(H.presentReplace, 5, h) + h = L.set(H.present, 6, h) + return R.map( + i => L.get(H.present, L.set(H.index, i, h)), + R.range(0, H.count(h)) + ) + }) + testEq(16000, () => { let h = H.init({maxCount: 5000}, 1) for (let i = 2; i < 20000; ++i) h = L.set(H.present, i, h)