Skip to content
This repository was archived by the owner on May 5, 2021. It is now read-only.

Commit d76c369

Browse files
committed
memory devtools
1 parent 8bd598b commit d76c369

File tree

4 files changed

+559
-7
lines changed

4 files changed

+559
-7
lines changed

packages/core/src/JWEditor.ts

+45-7
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@ import { AtomicNode } from './VNodes/AtomicNode';
1212
import { SeparatorNode } from './VNodes/SeparatorNode';
1313
import { ModeIdentifier, ModeDefinition, Mode, RuleProperty } from './Mode';
1414
import { Memory, ChangesLocations } from './Memory/Memory';
15-
import { makeVersionable } from './Memory/Versionable';
15+
import { makeVersionable, markNotVersionable } from './Memory/Versionable';
1616
import { VersionableArray } from './Memory/VersionableArray';
17+
import { VersionableSet } from './Memory/VersionableSet';
18+
import { MemoryOrigin } from '../../plugin-devtools/src/components/MemoryComponent';
1719
import { Point, VNode } from './VNodes/VNode';
1820

1921
export enum EditorStage {
@@ -85,6 +87,10 @@ export interface PluginMap extends Map<typeof JWPlugin, JWPlugin> {
8587
get<T extends typeof JWPlugin>(constructor: T): InstanceType<T>;
8688
}
8789

90+
interface MemoryInfo extends MemoryOrigin {
91+
uiCommand: boolean;
92+
}
93+
8894
export class JWEditor {
8995
private _stage: EditorStage = EditorStage.CONFIGURATION;
9096
dispatcher: Dispatcher;
@@ -101,7 +107,7 @@ export class JWEditor {
101107
deadlockTimeout: 10000,
102108
};
103109
memory: Memory;
104-
memoryInfo: { commandNames: string[]; uiCommand: boolean };
110+
memoryInfo: MemoryInfo;
105111
private _memoryID = 0;
106112
selection: VSelection;
107113
loaders: Record<string, Loader> = {};
@@ -161,7 +167,18 @@ export class JWEditor {
161167
this.memory = new Memory();
162168
this.memory.attach(this.selection.range.start);
163169
this.memory.attach(this.selection.range.end);
164-
this.memoryInfo = makeVersionable({ commandNames: [], uiCommand: false });
170+
this.memoryInfo = makeVersionable({
171+
// for dev tools and plugin's values merge
172+
commandNames: [],
173+
uiCommand: false,
174+
layers: new Set([]),
175+
actionID: '',
176+
actionArgs: {} as object,
177+
base: '',
178+
current: this._memoryID.toString(),
179+
isMaster: true,
180+
error: null,
181+
});
165182
this.memory.attach(this.memoryInfo);
166183
this.memory.create(this._memoryID.toString());
167184

@@ -500,7 +517,10 @@ export class JWEditor {
500517
const origin = this.memory.sliceKey;
501518
const memorySlice = this._memoryID.toString();
502519
this.memory.switchTo(memorySlice);
520+
this.memoryInfo.isMaster = false;
521+
this.memoryInfo.layers = new VersionableSet([memorySlice]);
503522
this.memoryInfo.commandNames = new VersionableArray();
523+
this.memoryInfo.actionID = null;
504524
this.memoryInfo.uiCommand = false;
505525
let commandNames = this.memoryInfo.commandNames;
506526

@@ -510,13 +530,16 @@ export class JWEditor {
510530
if (typeof commandName === 'function') {
511531
const name = '@custom' + (commandName.name ? ':' + commandName.name : '');
512532
this.memoryInfo.commandNames.push(name);
533+
this.memoryInfo.actionID = name;
513534
await commandName(this.contextManager.defaultContext);
514535
if (this.memory.sliceKey !== memorySlice) {
515536
// Override by the current commandName if the slice changed.
516537
commandNames = [name];
517538
}
518539
} else {
519540
this.memoryInfo.commandNames.push(commandName);
541+
if (params) markNotVersionable(params);
542+
this.memoryInfo.actionID = commandName;
520543
await this.dispatcher.dispatch(commandName, params);
521544
if (this.memory.sliceKey !== memorySlice) {
522545
// Override by the current commandName if the slice changed.
@@ -538,7 +561,14 @@ export class JWEditor {
538561
exec().then(resolve, reject);
539562
});
540563

541-
// Prepare nex slice and freeze the memory.
564+
// The running memory slice becomes a master slice.
565+
if (!this.memory.isFrozen()) {
566+
this.memoryInfo.isMaster = true;
567+
this.memoryInfo.base = memorySlice;
568+
this.memoryInfo.current = this._memoryID.toString();
569+
}
570+
571+
// Prepare next slice and freeze the memory.
542572
this._memoryID++;
543573
const nextMemorySlice = this._memoryID.toString();
544574
this.memory.create(nextMemorySlice);
@@ -567,6 +597,12 @@ export class JWEditor {
567597

568598
const failedSlice = this.memory.sliceKey;
569599

600+
// The failed memory slice becomes a master slice.
601+
this.memory.create(failedSlice + '-fail').switchTo(failedSlice + '-fail');
602+
this.memoryInfo.isMaster = false;
603+
this.memoryInfo.base = memorySlice;
604+
this.memoryInfo.error = error.message;
605+
570606
// When an error occurs, we go back to part of the functional memory.
571607
this.memory.switchTo(origin);
572608

@@ -609,12 +645,14 @@ export class JWEditor {
609645
params?: CommandParamsType<P, C>,
610646
): Promise<void> {
611647
if (typeof commandName === 'function') {
612-
this.memoryInfo.commandNames.push(
613-
'@custom' + (commandName.name ? ':' + commandName.name : ''),
614-
);
648+
const name = '@custom' + (commandName.name ? ':' + commandName.name : '');
649+
this.memoryInfo.commandNames.push(name);
650+
this.memoryInfo.actionID = name;
615651
await commandName(this.contextManager.defaultContext);
616652
} else {
617653
this.memoryInfo.commandNames.push(commandName);
654+
if (params) markNotVersionable(params);
655+
this.memoryInfo.actionID = commandName;
618656
await this.dispatcher.dispatch(commandName, params);
619657
}
620658
}

packages/plugin-devtools/assets/DevTools.xml

+129
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,131 @@
468468
</devtools-contents>
469469
</devtools-panel>
470470

471+
<!-- MEMORY SVG COMPONENT -->
472+
<g t-name="MemoryIntermediateLayout" t-attf-transform="translate(0, {{props.intermediate.offsetY * props.heigth}})" class="MemoryIntermediateLayout">
473+
<g t-if="props.intermediate.nexts.length" t-attf-transform="translate({{props.width}}, 0)">
474+
<MemoryIntermediateLayout
475+
t-foreach="props.intermediate.nexts" t-as="next"
476+
activeSlice="props.activeSlice"
477+
selectedSlice="props.selectedSlice"
478+
intermediate="next"
479+
width="props.width"
480+
heigth="props.heigth"/>
481+
<line x1="0" t-att-y1="props.heigth" x2="0" t-att-y2="props.intermediate.height * props.heigth" stroke="black"/>
482+
</g>
483+
<g>
484+
<text t-on-click="selectAction" x="6" y="28" fill="red" stroke="none"
485+
style="font-size: 10px;font-family: arial; cursor: pointer;"><t t-esc="props.intermediate.origin.actionID"/></text>
486+
<line x1="0" t-att-y1="props.heigth" t-att-x2="props.width" t-att-y2="props.heigth" stroke="black"/>
487+
<circle
488+
t-on-click="selectMemory"
489+
t-att-cx="props.width" t-att-cy="props.heigth" r="5"
490+
stroke-width="1"
491+
t-att-fill="props.activeSlice === props.intermediate.key ? 'green' : (props.selectedSlice === props.intermediate.key ? 'yellow' : '#dddddd')"
492+
style="cursor: pointer;"/>
493+
</g>
494+
</g>
495+
<g t-name="MemoryIntermediateFluxLayout" class="MemoryIntermediateFluxLayout" transform="translate(12, 0)">
496+
<!-- <rect t-att-width="props.flux.width * props.width - 24" t-att-height="props.flux.height * props.heigth" fill="transparent" stroke="#dddddd" stroke-width="1"/> -->
497+
<line t-foreach="props.flux.origins" t-as="origin"
498+
t-att-x1="origin.offsetX * props.width" t-att-y1="origin.offsetY * props.heigth"
499+
t-att-x2="flux.width * props.width - 24" t-att-y2="origin.offsetY * props.heigth" stroke="green"/>
500+
<line t-if="props.flux.origins.length"
501+
t-att-x1="flux.width * props.width - 24" t-att-y1="flux.origins[flux.origins.length - 1].offsetY * props.heigth"
502+
t-att-x2="flux.width * props.width - 24" y2="0" stroke="green"/>
503+
<MemoryIntermediateLayout
504+
t-foreach="flux.intermediates" t-as="intermediate"
505+
activeSlice="props.activeSlice"
506+
selectedSlice="props.selectedSlice"
507+
intermediate="intermediate"
508+
width="props.width"
509+
heigth="props.heigth"/>
510+
<line x1="0" y1="0" x2="0" t-att-y2="props.flux.height * props.heigth" stroke="black"/>
511+
</g>
512+
<g t-name="MemoryMasterLayout" class="MemoryMasterLayout" t-attf-transform="translate(0, {{props.master.offsetY * props.heigth}})">
513+
<MemoryIntermediateFluxLayout
514+
activeSlice="props.activeSlice"
515+
selectedSlice="props.selectedSlice"
516+
flux="props.master.flux"
517+
width="props.width"
518+
heigth="props.heigth"/>
519+
<g t-if="!props.master.finished &amp;&amp; props.master.nexts.length" t-attf-transform="translate({{props.master.flux.width * props.width}},0)">
520+
<MemoryMasterLayout
521+
t-foreach="props.master.nexts" t-as="next"
522+
activeSlice="props.activeSlice"
523+
selectedSlice="props.selectedSlice"
524+
master="next"
525+
width="props.width"
526+
heigth="props.heigth"/>
527+
<line t-if="props.master.nexts.length > 1" x1="0" y1="0" x2="0" t-att-y2="props.master.nexts[props.master.nexts.length - 1].offsetY * props.heigth" stroke="black" stroke-width="2"/>
528+
</g>
529+
<line t-if="!props.master.finished &amp;&amp; !props.master.nexts.length"
530+
t-attf-x1="{{props.master.flux.width * props.width}}" y1="0" y2="0" t-attf-x2="{{(props.master.flux.width + 1) * props.width}}" stroke="black" stroke-width="2"/>
531+
<g>
532+
<text t-if="!props.firstItem"
533+
t-on-click="selectAction" x="12" y="-6" fill="red" stroke="none"
534+
style="font-size: 10px;font-family: arial; cursor: pointer;"><t t-esc="props.master.origin.actionID"/></text>
535+
<line x1="0" y1="0" y2="0" t-attf-x2="{{props.master.flux.width * props.width}}" stroke="black" stroke-width="2"/>
536+
<circle
537+
t-on-click="selectMemory"
538+
t-on-dblclick="switchMemory"
539+
t-att-cx="props.master.flux.width * props.width" cy="0" r="8"
540+
stroke-width="1"
541+
t-att-fill="props.activeSlice === props.master.key ? 'green' : (props.selectedSlice === props.master.key ? 'yellow' : '#dddddd')"
542+
style="cursor: pointer;"/>
543+
</g>
544+
</g>
545+
<svg t-name="MemoryFluxLayout" t-att-width="props.flux.width * 105 + 40" t-att-height="(props.flux.height + 1) * 30 + 20">
546+
<g t-attf-transform="translate(0, 20)">
547+
<MemoryMasterLayout
548+
activeSlice="props.activeSlice"
549+
selectedSlice="props.selectedSlice"
550+
master="props.flux.first"
551+
firstItem="true"
552+
width="100"
553+
heigth="30"/>
554+
</g>
555+
</svg>
556+
557+
<!-- MEMORY -->
558+
<devtools-panel t-name="MemoryComponent"
559+
t-on-memory-selected="onSelectMemory"
560+
t-on-memory-switch="onSwitchMemory"
561+
class="active" tabindex="2">
562+
<devtools-contents>
563+
<devtools-mainpane>
564+
<MemoryFluxLayout t-if="state.flux" flux="state.flux" activeSlice="state.activeSlice" selectedSlice="state.selectedSlice"/>
565+
<MemoryFluxLayout t-if="state.flux2" flux="state.flux2" activeSlice="state.activeSlice" selectedSlice="state.selectedSlice"/>
566+
</devtools-mainpane>
567+
<devtools-sidepane>
568+
<div class="about">
569+
<span class="type">Memory Slice</span> <t t-esc="state.selected.current"/>
570+
</div>
571+
<div class="properties">
572+
<div style="cursor: pointer;"
573+
t-if="state.selected.parent"
574+
t-on-click="selectMemory(state.selected.parent)" class="divider">👤 Parent (<t t-esc="state.selected.parent"/>)</div>
575+
<div class="divider">👪 Children</div>
576+
<table>
577+
<tbody>
578+
<tr t-foreach="state.selected.children" t-as="name" t-key="index">
579+
<td><span style="cursor: pointer;" t-on-click="selectMemory(name)"> <t t-esc="name"/> </span></td>
580+
</tr>
581+
</tbody>
582+
</table>
583+
<devtools-infotitle>📖 Commands</devtools-infotitle>
584+
<table>
585+
<tbody>
586+
<tr t-foreach="state.selected.commandNames" t-as="commandName" t-key="index">
587+
<td><t t-esc="commandName"/></td>
588+
</tr>
589+
</tbody>
590+
</table>
591+
</div>
592+
</devtools-sidepane>
593+
</devtools-contents>
594+
</devtools-panel>
595+
471596
<!-- MAIN -->
472597
<jw-devtools t-name="devtools"
473598
t-att-class="{
@@ -494,6 +619,9 @@
494619
<devtools-button t-on-click="openTab('modes')" t-att-class="{
495620
selected: state.currentTab == 'modes',
496621
}">Modes</devtools-button>
622+
<devtools-button t-on-click="openTab('memory')" t-att-class="{
623+
selected: state.currentTab == 'memory',
624+
}">Memory</devtools-button>
497625
<devtools-button t-on-click="inspectDom()">&#128269;</devtools-button>
498626
</devtools-navbar>
499627
<t t-if="!state.closed">
@@ -503,6 +631,7 @@
503631
<ShortcutsComponent isOpen="state.currentTab == 'shortcuts'"/>
504632
<PluginsComponent isOpen="state.currentTab == 'plugins'"/>
505633
<ModesComponent isOpen="state.currentTab == 'modes'"/>
634+
<MemoryComponent t-if="state.currentTab == 'memory'" actions="state.actions"/>
506635
</t>
507636
</jw-devtools>
508637

packages/plugin-devtools/src/components/DevToolsComponent.ts

+2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { CommandsComponent } from './CommandsComponent';
22
import { InspectorComponent } from './InspectorComponent';
3+
import { MemoryComponent } from './MemoryComponent';
34
import { ShortcutsComponent } from './ShortcutsComponent';
45
import { PluginsComponent } from './PluginsComponent';
56
import { ModesComponent } from './ModesComponent';
@@ -21,6 +22,7 @@ export class DevToolsComponent<T = {}> extends OwlComponent<T> {
2122
static components = {
2223
CommandsComponent: CommandsComponent,
2324
InspectorComponent,
25+
MemoryComponent,
2426
ShortcutsComponent,
2527
PluginsComponent,
2628
ModesComponent,

0 commit comments

Comments
 (0)