feat: undo/redo

This commit is contained in:
cha0s 2022-04-08 17:15:23 -05:00
parent 025ecb72c6
commit 71d53095fb
4 changed files with 77 additions and 18 deletions

View File

@ -51,8 +51,8 @@
show: false show: false
quitOnClosed: false quitOnClosed: false
window: window:
- '@persea/core'
- '...' - '...'
- '@persea/core'
'@flecks/governor': {} '@flecks/governor': {}
'@flecks/react': '@flecks/react':
providers: providers:

View File

@ -1,4 +1,9 @@
import {patchJsonResource, replaceResource} from '@avocado/resource/persea'; import {
patchJsonResource,
redo,
replaceResource,
undo,
} from '@avocado/resource/persea';
import {Hooks} from '@flecks/core'; import {Hooks} from '@flecks/core';
import Persea from './components/persea'; import Persea from './components/persea';
@ -17,14 +22,23 @@ export default {
'@flecks/react.roots': () => Persea, '@flecks/react.roots': () => Persea,
'@flecks/redux.effects': (flecks) => { '@flecks/redux.effects': (flecks) => {
const withSocket = (fn) => (...args) => fn(...args.concat(flecks.get('$flecks/socket.socket'))); const withSocket = (fn) => (...args) => fn(...args.concat(flecks.get('$flecks/socket.socket')));
return { return Object.fromEntries(
[patchJsonResource]: withSocket((store, action, socket) => { [
socket.send(['Action', action]); patchJsonResource,
}), redo,
[replaceResource]: withSocket((store, action, socket) => { replaceResource,
socket.send(['Action', action]); undo,
}), ]
}; .map((action) => [
action,
withSocket((store, action, socket) => {
if (action.meta?.isRemote) {
return;
}
socket.send(['Action', action]);
}),
]),
);
}, },
'@flecks/redux.slices': () => ({ '@flecks/redux.slices': () => ({
project, project,

View File

@ -1,4 +1,13 @@
import {patchJsonResource, replaceResource} from '@avocado/resource/persea'; import {readFile, writeFile} from 'fs/promises';
import {join} from 'path';
import {
patchJsonResource,
redo,
replaceResource,
undo,
} from '@avocado/resource/persea';
import {applyPatch, compare} from 'fast-json-patch';
export default (Action, flecks) => class ProjectAction extends Action { export default (Action, flecks) => class ProjectAction extends Action {
@ -9,10 +18,44 @@ export default (Action, flecks) => class ProjectAction extends Action {
flecks.get('$persea/core.patches').push(payload); flecks.get('$persea/core.patches').push(payload);
break; break;
} }
case redo.toString(): {
const {project, uri} = payload;
const path = join(process.cwd(), 'projects', project, uri);
const {toBuffer, fromBuffer} = flecks.get('$avocado/resource/persea.controllers')
.find(({matcher}) => uri.match(matcher));
const buffer = await readFile(path);
const json = fromBuffer(buffer, flecks);
if (json.history?.redo?.length) {
const patch = json.history.redo[json.history.redo.length - 1];
socket.send(['Action', patchJsonResource({patch, project, uri}, true)]);
applyPatch(json, patch);
json.history.undo.push(compare(json, fromBuffer(buffer, flecks)));
json.history.redo.pop();
await writeFile(path, toBuffer(json, flecks));
}
break;
}
case replaceResource.toString(): { case replaceResource.toString(): {
flecks.get('$persea/core.replacements').push(payload); flecks.get('$persea/core.replacements').push(payload);
break; break;
} }
case undo.toString(): {
const {project, uri} = payload;
const path = join(process.cwd(), 'projects', project, uri);
const {toBuffer, fromBuffer} = flecks.get('$avocado/resource/persea.controllers')
.find(({matcher}) => uri.match(matcher));
const buffer = await readFile(path);
const json = fromBuffer(buffer, flecks);
if (json.history?.undo?.length) {
const patch = json.history.undo[json.history.undo.length - 1];
socket.send(['Action', patchJsonResource({patch, project, uri}, true)]);
applyPatch(json, patch);
json.history.redo.push(compare(json, fromBuffer(buffer, flecks)));
json.history.undo.pop();
await writeFile(path, toBuffer(json, flecks));
}
break;
}
default: default:
} }
return super.respond(packet, socket); return super.respond(packet, socket);

View File

@ -1,11 +1,7 @@
import fs from 'fs'; import {readFile, writeFile} from 'fs/promises';
import {join} from 'path'; import {join} from 'path';
import {promisify} from 'util';
import {applyPatch} from 'fast-json-patch'; import {applyPatch, compare} from 'fast-json-patch';
const readFile = promisify(fs.readFile);
const writeFile = promisify(fs.writeFile);
const startFlush = (flecks) => { const startFlush = (flecks) => {
const flushPatches = async () => { const flushPatches = async () => {
@ -21,6 +17,7 @@ const startFlush = (flecks) => {
patching[path] = new Promise((resolve) => { patching[path] = new Promise((resolve) => {
readFile(path).then((buffer) => { readFile(path).then((buffer) => {
resolve({ resolve({
fromBuffer,
toBuffer, toBuffer,
json: fromBuffer(buffer, flecks), json: fromBuffer(buffer, flecks),
}); });
@ -34,7 +31,12 @@ const startFlush = (flecks) => {
await Promise.all( await Promise.all(
Object.entries(patching) Object.entries(patching)
.map(async ([path, promise]) => { .map(async ([path, promise]) => {
const {toBuffer, json} = await promise; const {fromBuffer, toBuffer, json} = await promise;
const buffer = await readFile(path);
const undo = compare(json, fromBuffer(buffer, flecks));
json.history = json.history || {redo: [], undo: []};
json.history.redo = [];
json.history.undo.push(undo);
return writeFile(path, toBuffer(json, flecks)); return writeFile(path, toBuffer(json, flecks));
}), }),
); );