mirror of
https://github.com/xibyte/jsketcher
synced 2025-12-16 05:23:19 +01:00
131 lines
3.4 KiB
JavaScript
131 lines
3.4 KiB
JavaScript
import {addModification, stepOverriding} from './craftHistoryUtils';
|
|
import {state, stream} from 'lstream';
|
|
import {MShell} from '../model/mshell';
|
|
import {MDatum} from '../model/mdatum';
|
|
import materializeParams from './materializeParams';
|
|
import CadError from '../../utils/errors';
|
|
import {MObjectIdGenerator} from '../model/mobject';
|
|
|
|
export function activate({streams, services}) {
|
|
|
|
streams.craft = {
|
|
modifications: state({
|
|
history: [],
|
|
pointer: -1
|
|
}),
|
|
models: state([]),
|
|
update: stream()
|
|
};
|
|
|
|
let preRun = null;
|
|
|
|
function modifyWithPreRun(request, modificationsUpdater, onAccepted) {
|
|
preRun = {
|
|
request
|
|
};
|
|
try {
|
|
preRun.result = runRequest(request);
|
|
if (onAccepted) {
|
|
onAccepted();
|
|
}
|
|
modificationsUpdater(request);
|
|
} finally {
|
|
preRun = null;
|
|
}
|
|
}
|
|
|
|
function modify(request, onAccepted) {
|
|
modifyWithPreRun(request,
|
|
request => streams.craft.modifications.update(modifications => addModification(modifications, request)), onAccepted);
|
|
}
|
|
|
|
function modifyInHistoryAndStep(request, onAccepted) {
|
|
modifyWithPreRun(request,
|
|
request => streams.craft.modifications.update(modifications => stepOverriding(modifications, request)), onAccepted);
|
|
}
|
|
|
|
function reset(modifications) {
|
|
streams.craft.modifications.next({
|
|
history: modifications,
|
|
pointer: modifications.length - 1
|
|
});
|
|
}
|
|
|
|
function runRequest(request) {
|
|
let op = services.operation.get(request.type);
|
|
if (!op) {
|
|
throw(`unknown operation ${request.type}`);
|
|
}
|
|
|
|
let params = {};
|
|
let errors = [];
|
|
materializeParams(services, request.params, op.schema, params, errors);
|
|
if (errors.length) {
|
|
throw new CadError({
|
|
kind: CadError.KIND.INVALID_PARAMS,
|
|
userMessage: errors.map(err => `${err.path.join('.')}: ${err.message}`).join('\n')
|
|
});
|
|
}
|
|
|
|
return op.run(params, services);
|
|
}
|
|
|
|
function runOrGetPreRunResults(request) {
|
|
if (preRun !== null && preRun.request === request) {
|
|
return preRun.result;
|
|
} else {
|
|
return runRequest(request);
|
|
}
|
|
}
|
|
|
|
services.craft = {
|
|
modify, modifyInHistoryAndStep, reset, runRequest
|
|
};
|
|
|
|
streams.craft.modifications.pairwise().attach(([prev, curr]) => {
|
|
let models;
|
|
let beginIndex;
|
|
if (isAdditiveChange(prev, curr)) {
|
|
beginIndex = prev.pointer + 1;
|
|
} else {
|
|
MObjectIdGenerator.reset();
|
|
beginIndex = 0;
|
|
streams.craft.models.next([]);
|
|
}
|
|
|
|
models = new Set(streams.craft.models.value);
|
|
let {history, pointer} = curr;
|
|
for (let i = beginIndex; i <= pointer; i++) {
|
|
let request = history[i];
|
|
try {
|
|
let {consumed, created} = runOrGetPreRunResults(request);
|
|
consumed.forEach(m => models.delete(m));
|
|
created.forEach(m => models.add(m));
|
|
streams.craft.models.next(Array.from(models).sort(m => m.id));
|
|
} catch(e) {
|
|
console.error(e);
|
|
//TODO: need to find a way to propagate the error to the wizard.
|
|
setTimeout(() => streams.craft.modifications.next({
|
|
...curr,
|
|
pointer: i-1
|
|
}));
|
|
break;
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
function isAdditiveChange({history:oldHistory, pointer:oldPointer}, {history, pointer}) {
|
|
if (pointer < oldPointer) {
|
|
return false;
|
|
}
|
|
|
|
for (let i = 0; i <= oldPointer; i++) {
|
|
let modCurr = history[i];
|
|
let modPrev = oldHistory[i];
|
|
if (modCurr !== modPrev) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|