jupyterlab-ipyflow 0.0.176 → 0.0.178
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/index.js +526 -156
- package/package.json +1 -1
- package/style/index.css +23 -0
package/lib/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ICommandPalette } from '@jupyterlab/apputils';
|
|
2
2
|
import { CodeCell } from '@jupyterlab/cells';
|
|
3
|
-
import { INotebookTracker } from '@jupyterlab/notebook';
|
|
3
|
+
import { INotebookTracker, NotebookActions, } from '@jupyterlab/notebook';
|
|
4
4
|
import _ from 'lodash';
|
|
5
5
|
const waitingClass = 'waiting-cell';
|
|
6
6
|
const readyClass = 'ready-cell';
|
|
@@ -8,34 +8,148 @@ const readyMakingClass = 'ready-making-cell';
|
|
|
8
8
|
const readyMakingInputClass = 'ready-making-input-cell';
|
|
9
9
|
const linkedWaitingClass = 'linked-waiting';
|
|
10
10
|
const linkedReadyMakerClass = 'linked-ready-maker';
|
|
11
|
+
const selfSliceClass = 'ipyflow-slice-self';
|
|
12
|
+
const directSliceClass = 'ipyflow-slice-direct';
|
|
13
|
+
const sliceClass = 'ipyflow-slice';
|
|
11
14
|
const cleanup = new Event('cleanup');
|
|
15
|
+
// ipyflow frontend state
|
|
16
|
+
class IpyflowSessionState {
|
|
17
|
+
constructor() {
|
|
18
|
+
this.comm = null;
|
|
19
|
+
this.notebook = null;
|
|
20
|
+
this.session = null;
|
|
21
|
+
this.isIpyflowCommConnected = false;
|
|
22
|
+
this.executionScheduledCells = [];
|
|
23
|
+
this.selectedCells = [];
|
|
24
|
+
this.dirtyCells = new Set();
|
|
25
|
+
this.waitingCells = new Set();
|
|
26
|
+
this.readyCells = new Set();
|
|
27
|
+
this.waiterLinks = {};
|
|
28
|
+
this.readyMakerLinks = {};
|
|
29
|
+
this.prevActiveCell = null;
|
|
30
|
+
this.activeCell = null;
|
|
31
|
+
this.cellsById = {};
|
|
32
|
+
this.orderIdxById = {};
|
|
33
|
+
this.cellPendingExecution = null;
|
|
34
|
+
this.isReactivelyExecuting = false;
|
|
35
|
+
this.numAltModeExecutes = 0;
|
|
36
|
+
this.altModeExecuteCells = null;
|
|
37
|
+
this.lastExecutionHighlights = null;
|
|
38
|
+
this.executedReactiveReadyCells = new Set();
|
|
39
|
+
this.newReadyCells = new Set();
|
|
40
|
+
this.forcedReactiveCells = new Set();
|
|
41
|
+
this.forcedCascadingReactiveCells = new Set();
|
|
42
|
+
this.numPendingForcedReactiveCounterBumps = 0;
|
|
43
|
+
this.cellParents = {};
|
|
44
|
+
this.cellChildren = {};
|
|
45
|
+
this.settings = {};
|
|
46
|
+
}
|
|
47
|
+
gatherCellMetadataAndContent() {
|
|
48
|
+
const cell_metadata_by_id = {};
|
|
49
|
+
this.notebook.widgets.forEach((itercell, idx) => {
|
|
50
|
+
const model = itercell.model;
|
|
51
|
+
cell_metadata_by_id[model.id] = {
|
|
52
|
+
index: idx,
|
|
53
|
+
content: model.sharedModel.getSource(),
|
|
54
|
+
type: model.type,
|
|
55
|
+
};
|
|
56
|
+
});
|
|
57
|
+
return cell_metadata_by_id;
|
|
58
|
+
}
|
|
59
|
+
requestComputeExecSchedule() {
|
|
60
|
+
this.comm.send({
|
|
61
|
+
type: 'compute_exec_schedule',
|
|
62
|
+
cell_metadata_by_id: this.gatherCellMetadataAndContent(),
|
|
63
|
+
is_reactively_executing: this.isReactivelyExecuting,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
executeCells(cells) {
|
|
67
|
+
if (cells.length === 0) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
let numFinished = 0;
|
|
71
|
+
for (const cell of cells) {
|
|
72
|
+
// if any of them fail, change the [*] to [ ] on subsequent cells
|
|
73
|
+
CodeCell.execute(cell, this.session).then((msg) => {
|
|
74
|
+
var _a, _b, _c;
|
|
75
|
+
if (((_b = (_a = msg) === null || _a === void 0 ? void 0 : _a.content) === null || _b === void 0 ? void 0 : _b.status) === 'error') {
|
|
76
|
+
numFinished = cells.length;
|
|
77
|
+
for (const cell of cells) {
|
|
78
|
+
if ((_c = cell.promptNode.textContent) === null || _c === void 0 ? void 0 : _c.includes('[*]')) {
|
|
79
|
+
cell.setPrompt('');
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
numFinished++;
|
|
85
|
+
}
|
|
86
|
+
if (numFinished === cells.length) {
|
|
87
|
+
this.requestComputeExecSchedule();
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
toggleReactivity() {
|
|
93
|
+
if (this.settings.exec_mode === 'reactive') {
|
|
94
|
+
this.settings.exec_mode = 'normal';
|
|
95
|
+
}
|
|
96
|
+
else if (this.settings.exec_mode === 'normal') {
|
|
97
|
+
this.settings.exec_mode = 'reactive';
|
|
98
|
+
}
|
|
99
|
+
return this.session.session.kernel.requestExecute({
|
|
100
|
+
code: '%flow toggle-reactivity',
|
|
101
|
+
silent: true,
|
|
102
|
+
store_history: false,
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
bumpForcedReactiveCounter() {
|
|
106
|
+
this.numPendingForcedReactiveCounterBumps--;
|
|
107
|
+
return this.session.session.kernel.requestExecute({
|
|
108
|
+
code: '%flow bump-min-forced-reactive-counter',
|
|
109
|
+
silent: true,
|
|
110
|
+
store_history: false,
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
computeTransitiveClosure(cellIds, inclusive = true, parents = false) {
|
|
114
|
+
const closure = new Set();
|
|
115
|
+
for (const cellId of cellIds) {
|
|
116
|
+
if (parents) {
|
|
117
|
+
computeTransitiveClosureHelper(closure, cellId, this.cellParents);
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
computeTransitiveClosureHelper(closure, cellId, this.cellChildren);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
if (!inclusive) {
|
|
124
|
+
for (const cellId of cellIds) {
|
|
125
|
+
closure.delete(cellId);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return Array.from(closure)
|
|
129
|
+
.filter((id) => this.cellsById[id] !== undefined)
|
|
130
|
+
.filter((id) => this.orderIdxById[id] !== undefined)
|
|
131
|
+
.sort((a, b) => this.orderIdxById[a] - this.orderIdxById[b])
|
|
132
|
+
.map((id) => this.cellsById[id]);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
12
135
|
const ipyflowState = {};
|
|
13
136
|
function initSessionState(session_id) {
|
|
14
|
-
ipyflowState[session_id] =
|
|
15
|
-
isIpyflowCommConnected: false,
|
|
16
|
-
dirtyCells: new Set(),
|
|
17
|
-
waitingCells: new Set(),
|
|
18
|
-
readyCells: new Set(),
|
|
19
|
-
waiterLinks: {},
|
|
20
|
-
readyMakerLinks: {},
|
|
21
|
-
activeCell: null,
|
|
22
|
-
activeCellId: null,
|
|
23
|
-
cellsById: {},
|
|
24
|
-
cellModelsById: {},
|
|
25
|
-
orderIdxById: {},
|
|
26
|
-
cellPendingExecution: null,
|
|
27
|
-
lastExecutionMode: null,
|
|
28
|
-
isReactivelyExecuting: false,
|
|
29
|
-
isAltModeExecuting: false,
|
|
30
|
-
lastExecutionHighlights: null,
|
|
31
|
-
executedReactiveReadyCells: new Set(),
|
|
32
|
-
newReadyCells: new Set(),
|
|
33
|
-
forcedReactiveCells: new Set(),
|
|
34
|
-
};
|
|
137
|
+
ipyflowState[session_id] = new IpyflowSessionState();
|
|
35
138
|
}
|
|
36
139
|
function resetSessionState(session_id) {
|
|
37
140
|
delete ipyflowState[session_id];
|
|
38
141
|
}
|
|
142
|
+
function computeTransitiveClosureHelper(closure, cellId, edges) {
|
|
143
|
+
if (closure.has(cellId)) {
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
closure.add(cellId);
|
|
147
|
+
const children = edges[cellId];
|
|
148
|
+
if (children === undefined) {
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
children.forEach((child) => computeTransitiveClosureHelper(closure, child, edges));
|
|
152
|
+
}
|
|
39
153
|
/**
|
|
40
154
|
* Initialization data for the jupyterlab-ipyflow extension.
|
|
41
155
|
*/
|
|
@@ -55,46 +169,52 @@ const extension = {
|
|
|
55
169
|
if (!session.isReady) {
|
|
56
170
|
return;
|
|
57
171
|
}
|
|
172
|
+
app.commands.execute('notebook:enter-command-mode');
|
|
58
173
|
const state = ((_a = ipyflowState[session.session.id]) !== null && _a !== void 0 ? _a : {});
|
|
174
|
+
const altModeExecuteCells = state.altModeExecuteCells;
|
|
175
|
+
state.altModeExecuteCells = null;
|
|
59
176
|
if (!((_b = state.isIpyflowCommConnected) !== null && _b !== void 0 ? _b : false)) {
|
|
60
|
-
app.commands.execute('notebook:enter-command-mode');
|
|
61
177
|
CodeCell.execute(notebooks.activeCell, session);
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
if (state.settings.reactivity_mode !== 'batch' &&
|
|
181
|
+
altModeExecuteCells !== null) {
|
|
182
|
+
return;
|
|
62
183
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
})
|
|
73
|
-
.done.then(() => {
|
|
74
|
-
session.session.kernel
|
|
75
|
-
.requestExecute({
|
|
76
|
-
code: '%flow toggle-reactivity-until-next-reset',
|
|
77
|
-
silent: true,
|
|
78
|
-
store_history: false,
|
|
79
|
-
})
|
|
80
|
-
.done.then(() => {
|
|
81
|
-
CodeCell.execute(notebooks.activeCell, session);
|
|
82
|
-
});
|
|
83
|
-
});
|
|
184
|
+
if (notebooks.activeCell.model.type !== 'code') {
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
state.numAltModeExecutes++;
|
|
188
|
+
if (state.settings.reactivity_mode === 'incremental') {
|
|
189
|
+
if (state.numAltModeExecutes === 1) {
|
|
190
|
+
state
|
|
191
|
+
.toggleReactivity()
|
|
192
|
+
.done.then(() => CodeCell.execute(notebooks.activeCell, session));
|
|
84
193
|
}
|
|
85
194
|
else {
|
|
86
|
-
|
|
87
|
-
session.session.kernel
|
|
88
|
-
.requestExecute({
|
|
89
|
-
code: '%flow toggle-reactivity-until-next-reset',
|
|
90
|
-
silent: true,
|
|
91
|
-
store_history: false,
|
|
92
|
-
})
|
|
93
|
-
.done.then(() => {
|
|
94
|
-
CodeCell.execute(notebooks.activeCell, session);
|
|
95
|
-
});
|
|
195
|
+
CodeCell.execute(notebooks.activeCell, session);
|
|
96
196
|
}
|
|
97
197
|
}
|
|
198
|
+
else if (state.settings.reactivity_mode === 'batch') {
|
|
199
|
+
let closure = altModeExecuteCells !== null && altModeExecuteCells !== void 0 ? altModeExecuteCells : [notebooks.activeCell];
|
|
200
|
+
if (state.settings.exec_mode === 'normal' &&
|
|
201
|
+
altModeExecuteCells === null) {
|
|
202
|
+
closure = state.computeTransitiveClosure([
|
|
203
|
+
notebooks.activeCell.model.id,
|
|
204
|
+
]);
|
|
205
|
+
}
|
|
206
|
+
if (state.numAltModeExecutes === 1) {
|
|
207
|
+
state
|
|
208
|
+
.toggleReactivity()
|
|
209
|
+
.done.then(() => state.executeCells(closure));
|
|
210
|
+
}
|
|
211
|
+
else {
|
|
212
|
+
state.executeCells(closure);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
else {
|
|
216
|
+
console.error(`Unknown reactivity mode: ${state.settings.reactivity_mode}`);
|
|
217
|
+
}
|
|
98
218
|
},
|
|
99
219
|
});
|
|
100
220
|
app.commands.addKeyBinding({
|
|
@@ -112,24 +232,148 @@ const extension = {
|
|
|
112
232
|
category: 'execution',
|
|
113
233
|
args: {},
|
|
114
234
|
});
|
|
115
|
-
|
|
116
|
-
|
|
235
|
+
const executeSlice = (isBackward) => {
|
|
236
|
+
var _a, _b;
|
|
237
|
+
const session = notebooks.currentWidget.sessionContext;
|
|
238
|
+
if (!session.isReady) {
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
const state = ((_a = ipyflowState[session.session.id]) !== null && _a !== void 0 ? _a : {});
|
|
242
|
+
if (!((_b = state.isIpyflowCommConnected) !== null && _b !== void 0 ? _b : false)) {
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
app.commands.execute('notebook:enter-command-mode');
|
|
246
|
+
const closure = state.computeTransitiveClosure([state.activeCell.model.id], true, isBackward);
|
|
247
|
+
state.numPendingForcedReactiveCounterBumps++;
|
|
248
|
+
if (state.settings.exec_mode === 'normal') {
|
|
249
|
+
state.executeCells(closure);
|
|
250
|
+
}
|
|
251
|
+
else {
|
|
252
|
+
state.altModeExecuteCells = closure;
|
|
253
|
+
app.commands.execute('alt-mode-execute');
|
|
254
|
+
}
|
|
255
|
+
};
|
|
256
|
+
app.commands.addCommand('execute-forward-slice', {
|
|
257
|
+
label: 'Execute Forward Slice',
|
|
117
258
|
isEnabled: () => true,
|
|
118
259
|
isVisible: () => true,
|
|
119
260
|
isToggled: () => false,
|
|
120
|
-
execute: () =>
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
},
|
|
261
|
+
execute: () => executeSlice(false),
|
|
262
|
+
});
|
|
263
|
+
app.commands.addKeyBinding({
|
|
264
|
+
command: 'execute-forward-slice',
|
|
265
|
+
keys: ['Accel J'],
|
|
266
|
+
selector: '.jp-Notebook',
|
|
127
267
|
});
|
|
128
268
|
app.commands.addKeyBinding({
|
|
129
|
-
command: '
|
|
130
|
-
keys: ['Accel
|
|
269
|
+
command: 'execute-forward-slice',
|
|
270
|
+
keys: ['Accel ArrowDown'],
|
|
131
271
|
selector: '.jp-Notebook',
|
|
132
272
|
});
|
|
273
|
+
app.commands.addCommand('execute-backward-slice', {
|
|
274
|
+
label: 'Execute Backward Slice',
|
|
275
|
+
isEnabled: () => true,
|
|
276
|
+
isVisible: () => true,
|
|
277
|
+
isToggled: () => false,
|
|
278
|
+
execute: () => executeSlice(true),
|
|
279
|
+
});
|
|
280
|
+
app.commands.addKeyBinding({
|
|
281
|
+
command: 'execute-backward-slice',
|
|
282
|
+
keys: ['Accel K'],
|
|
283
|
+
selector: '.jp-Notebook',
|
|
284
|
+
});
|
|
285
|
+
app.commands.addKeyBinding({
|
|
286
|
+
command: 'execute-backward-slice',
|
|
287
|
+
keys: ['Accel ArrowUp'],
|
|
288
|
+
selector: '.jp-Notebook',
|
|
289
|
+
});
|
|
290
|
+
const executeRemaining = () => {
|
|
291
|
+
var _a, _b;
|
|
292
|
+
const session = notebooks.currentWidget.sessionContext;
|
|
293
|
+
if (!session.isReady) {
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
const state = ((_a = ipyflowState[session.session.id]) !== null && _a !== void 0 ? _a : {});
|
|
297
|
+
if ((_b = state.isIpyflowCommConnected) !== null && _b !== void 0 ? _b : false) {
|
|
298
|
+
let closureCellIds = state.executionScheduledCells;
|
|
299
|
+
state.executionScheduledCells = [];
|
|
300
|
+
if (closureCellIds.length === 0) {
|
|
301
|
+
closureCellIds = [state.activeCell.model.id];
|
|
302
|
+
}
|
|
303
|
+
const closure = state.computeTransitiveClosure(closureCellIds, false);
|
|
304
|
+
if (closure.length > 0) {
|
|
305
|
+
state.executeCells(closure);
|
|
306
|
+
}
|
|
307
|
+
else {
|
|
308
|
+
state.requestComputeExecSchedule();
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
};
|
|
312
|
+
NotebookActions.executionScheduled.connect((_, args) => {
|
|
313
|
+
var _a, _b, _c;
|
|
314
|
+
const notebook = notebooks === null || notebooks === void 0 ? void 0 : notebooks.currentWidget;
|
|
315
|
+
if ((notebook === null || notebook === void 0 ? void 0 : notebook.content) !== args.notebook) {
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
const session = notebook === null || notebook === void 0 ? void 0 : notebook.sessionContext;
|
|
319
|
+
if (!((_a = session === null || session === void 0 ? void 0 : session.isReady) !== null && _a !== void 0 ? _a : false)) {
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
const state = ((_b = ipyflowState[session.session.id]) !== null && _b !== void 0 ? _b : {});
|
|
323
|
+
if (!((_c = state.isIpyflowCommConnected) !== null && _c !== void 0 ? _c : false)) {
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
const settings = state.settings;
|
|
327
|
+
const isBatch = (settings === null || settings === void 0 ? void 0 : settings.reactivity_mode) === 'batch';
|
|
328
|
+
const isReactive = (settings === null || settings === void 0 ? void 0 : settings.exec_mode) === 'reactive';
|
|
329
|
+
if (!isBatch || !isReactive) {
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
if (args.cell.model.type === 'code') {
|
|
333
|
+
state.executionScheduledCells.push(args.cell.model.id);
|
|
334
|
+
}
|
|
335
|
+
});
|
|
336
|
+
app.commands.commandExecuted.connect((_, args) => {
|
|
337
|
+
var _a, _b, _c;
|
|
338
|
+
const notebook = notebooks === null || notebooks === void 0 ? void 0 : notebooks.currentWidget;
|
|
339
|
+
const session = notebook === null || notebook === void 0 ? void 0 : notebook.sessionContext;
|
|
340
|
+
if (!((_a = session === null || session === void 0 ? void 0 : session.isReady) !== null && _a !== void 0 ? _a : false)) {
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
const state = ((_b = ipyflowState[session.session.id]) !== null && _b !== void 0 ? _b : {});
|
|
344
|
+
if (!((_c = state.isIpyflowCommConnected) !== null && _c !== void 0 ? _c : false)) {
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
const settings = state.settings;
|
|
348
|
+
const isBatch = (settings === null || settings === void 0 ? void 0 : settings.reactivity_mode) === 'batch';
|
|
349
|
+
const isReactive = (settings === null || settings === void 0 ? void 0 : settings.exec_mode) === 'reactive';
|
|
350
|
+
if (!isBatch) {
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
353
|
+
if (args.id === 'notebook:run-cell') {
|
|
354
|
+
if (isReactive) {
|
|
355
|
+
executeRemaining();
|
|
356
|
+
}
|
|
357
|
+
else {
|
|
358
|
+
state.requestComputeExecSchedule();
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
else if (args.id === 'notebook:run-cell-and-select-next') {
|
|
362
|
+
const origActiveCell = state.activeCell;
|
|
363
|
+
try {
|
|
364
|
+
state.activeCell = state.prevActiveCell;
|
|
365
|
+
if (isReactive) {
|
|
366
|
+
executeRemaining();
|
|
367
|
+
}
|
|
368
|
+
else {
|
|
369
|
+
state.requestComputeExecSchedule();
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
finally {
|
|
373
|
+
state.activeCell = origActiveCell;
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
});
|
|
133
377
|
notebooks.widgetAdded.connect((sender, nbPanel) => {
|
|
134
378
|
const session = nbPanel.sessionContext;
|
|
135
379
|
let commDisconnectHandler = () => resetSessionState(session.session.id);
|
|
@@ -146,18 +390,18 @@ const extension = {
|
|
|
146
390
|
}
|
|
147
391
|
else if (payload.type === 'establish') {
|
|
148
392
|
commDisconnectHandler();
|
|
149
|
-
commDisconnectHandler = connectToComm(session, nbPanel.content);
|
|
393
|
+
commDisconnectHandler = connectToComm(session, notebooks, nbPanel.content);
|
|
150
394
|
}
|
|
151
395
|
};
|
|
152
396
|
commDisconnectHandler();
|
|
153
|
-
commDisconnectHandler = connectToComm(session, nbPanel.content);
|
|
397
|
+
commDisconnectHandler = connectToComm(session, notebooks, nbPanel.content);
|
|
154
398
|
});
|
|
155
399
|
};
|
|
156
400
|
session.ready.then(() => {
|
|
157
401
|
clearCellState(nbPanel.content);
|
|
158
402
|
registerCommTarget();
|
|
159
403
|
commDisconnectHandler();
|
|
160
|
-
commDisconnectHandler = connectToComm(session, nbPanel.content);
|
|
404
|
+
commDisconnectHandler = connectToComm(session, notebooks, nbPanel.content);
|
|
161
405
|
session.kernelChanged.connect((_, args) => {
|
|
162
406
|
if (args.newValue == null) {
|
|
163
407
|
return;
|
|
@@ -168,7 +412,7 @@ const extension = {
|
|
|
168
412
|
commDisconnectHandler = () => resetSessionState(session.session.id);
|
|
169
413
|
session.ready.then(() => {
|
|
170
414
|
registerCommTarget();
|
|
171
|
-
commDisconnectHandler = connectToComm(session, nbPanel.content);
|
|
415
|
+
commDisconnectHandler = connectToComm(session, notebooks, nbPanel.content);
|
|
172
416
|
});
|
|
173
417
|
});
|
|
174
418
|
});
|
|
@@ -224,6 +468,9 @@ const clearCellState = (notebook) => {
|
|
|
224
468
|
cell.node.classList.remove(readyMakingClass);
|
|
225
469
|
cell.node.classList.remove(readyClass);
|
|
226
470
|
cell.node.classList.remove(readyMakingInputClass);
|
|
471
|
+
cell.node.classList.remove(selfSliceClass);
|
|
472
|
+
cell.node.classList.remove(directSliceClass);
|
|
473
|
+
cell.node.classList.remove(sliceClass);
|
|
227
474
|
// clear any old event listeners
|
|
228
475
|
const inputCollapser = getJpInputCollapser(cell.node);
|
|
229
476
|
if (inputCollapser !== null) {
|
|
@@ -249,7 +496,7 @@ const addUnsafeCellInteraction = (elem, linkedElems, cellsById, collapserFun, ev
|
|
|
249
496
|
if (waitingCells.has(linkedId)) {
|
|
250
497
|
css = linkedWaitingClass;
|
|
251
498
|
}
|
|
252
|
-
const collapser = collapserFun(cellsById[linkedId]);
|
|
499
|
+
const collapser = collapserFun(cellsById[linkedId].node);
|
|
253
500
|
if (collapser === null || collapser.firstElementChild === null) {
|
|
254
501
|
return;
|
|
255
502
|
}
|
|
@@ -259,44 +506,36 @@ const addUnsafeCellInteraction = (elem, linkedElems, cellsById, collapserFun, ev
|
|
|
259
506
|
elem.addEventListener(evt, listener);
|
|
260
507
|
attachCleanupListener(elem, evt, listener);
|
|
261
508
|
};
|
|
262
|
-
const connectToComm = (session, notebook) => {
|
|
509
|
+
const connectToComm = (session, notebooks, notebook) => {
|
|
263
510
|
initSessionState(session.session.id);
|
|
264
511
|
const state = ipyflowState[session.session.id];
|
|
265
512
|
state.activeCell = notebook.activeCell;
|
|
266
|
-
|
|
267
|
-
|
|
513
|
+
const comm = session.session.kernel.createComm('ipyflow', 'ipyflow');
|
|
514
|
+
state.comm = comm;
|
|
515
|
+
state.notebook = notebook;
|
|
516
|
+
state.session = session;
|
|
268
517
|
let disconnected = false;
|
|
269
|
-
const
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
});
|
|
279
|
-
return cell_metadata_by_id;
|
|
518
|
+
const syncDirtiness = (cell) => {
|
|
519
|
+
if (cell !== null && cell.model !== null) {
|
|
520
|
+
if (cell.model.isDirty) {
|
|
521
|
+
state.dirtyCells.add(cell.model.id);
|
|
522
|
+
}
|
|
523
|
+
else {
|
|
524
|
+
state.dirtyCells.delete(cell.model.id);
|
|
525
|
+
}
|
|
526
|
+
}
|
|
280
527
|
};
|
|
281
528
|
const onContentChanged = _.debounce(() => {
|
|
282
529
|
if (disconnected) {
|
|
283
530
|
notebook.model.contentChanged.disconnect(onContentChanged);
|
|
284
531
|
return;
|
|
285
532
|
}
|
|
533
|
+
notebook.widgets.forEach(syncDirtiness);
|
|
286
534
|
comm.send({
|
|
287
535
|
type: 'notify_content_changed',
|
|
288
|
-
cell_metadata_by_id: gatherCellMetadataAndContent(),
|
|
536
|
+
cell_metadata_by_id: state.gatherCellMetadataAndContent(),
|
|
289
537
|
});
|
|
290
538
|
}, 500);
|
|
291
|
-
const requestComputeExecSchedule = (cell) => {
|
|
292
|
-
const cell_metadata_by_id = gatherCellMetadataAndContent();
|
|
293
|
-
comm.send({
|
|
294
|
-
type: 'compute_exec_schedule',
|
|
295
|
-
executed_cell_id: cell === null || cell === void 0 ? void 0 : cell.id,
|
|
296
|
-
cell_metadata_by_id,
|
|
297
|
-
is_reactively_executing: state.isReactivelyExecuting,
|
|
298
|
-
});
|
|
299
|
-
};
|
|
300
539
|
const onExecution = (cell, args) => {
|
|
301
540
|
if (disconnected) {
|
|
302
541
|
cell.stateChanged.disconnect(onExecution);
|
|
@@ -305,14 +544,37 @@ const connectToComm = (session, notebook) => {
|
|
|
305
544
|
if (args.name !== 'executionCount' || args.newValue === null) {
|
|
306
545
|
return;
|
|
307
546
|
}
|
|
547
|
+
state.dirtyCells.delete(cell.id);
|
|
308
548
|
notebook.widgets.forEach((itercell) => {
|
|
309
549
|
if (itercell.model.id === cell.id) {
|
|
310
550
|
itercell.node.classList.remove(readyClass);
|
|
311
551
|
itercell.node.classList.remove(readyMakingInputClass);
|
|
312
552
|
}
|
|
313
553
|
});
|
|
314
|
-
|
|
554
|
+
if (state.settings.reactivity_mode === 'incremental') {
|
|
555
|
+
state.requestComputeExecSchedule();
|
|
556
|
+
}
|
|
557
|
+
};
|
|
558
|
+
for (const cell of notebook.widgets) {
|
|
559
|
+
cell.model.stateChanged.connect(onExecution);
|
|
560
|
+
}
|
|
561
|
+
const onCellsAdded = (_, change) => {
|
|
562
|
+
if (disconnected) {
|
|
563
|
+
notebook.model.cells.changed.disconnect(onCellsAdded);
|
|
564
|
+
return;
|
|
565
|
+
}
|
|
566
|
+
if (change.type === 'add') {
|
|
567
|
+
for (const cell of change.newValues) {
|
|
568
|
+
cell === null || cell === void 0 ? void 0 : cell.stateChanged.connect(onExecution);
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
else if (change.type === 'remove') {
|
|
572
|
+
for (const cell of change.oldValues) {
|
|
573
|
+
cell === null || cell === void 0 ? void 0 : cell.stateChanged.disconnect(onExecution);
|
|
574
|
+
}
|
|
575
|
+
}
|
|
315
576
|
};
|
|
577
|
+
notebook.model.cells.changed.connect(onCellsAdded);
|
|
316
578
|
const notifyActiveCell = (newActiveCell) => {
|
|
317
579
|
let newActiveCellOrderIdx = -1;
|
|
318
580
|
notebook.widgets.forEach((itercell, idx) => {
|
|
@@ -329,15 +591,14 @@ const connectToComm = (session, notebook) => {
|
|
|
329
591
|
};
|
|
330
592
|
const refreshNodeMapping = (notebook) => {
|
|
331
593
|
state.cellsById = {};
|
|
332
|
-
state.cellModelsById = {};
|
|
333
594
|
state.orderIdxById = {};
|
|
334
595
|
notebook.widgets.forEach((cell, idx) => {
|
|
335
|
-
state.cellsById[cell.model.id] = cell
|
|
336
|
-
state.cellModelsById[cell.model.id] = cell.model;
|
|
596
|
+
state.cellsById[cell.model.id] = cell;
|
|
337
597
|
state.orderIdxById[cell.model.id] = idx;
|
|
338
598
|
});
|
|
339
599
|
};
|
|
340
600
|
const onActiveCellChange = (nb, cell) => {
|
|
601
|
+
var _a, _b;
|
|
341
602
|
if (notebook !== nb) {
|
|
342
603
|
return;
|
|
343
604
|
}
|
|
@@ -346,32 +607,18 @@ const connectToComm = (session, notebook) => {
|
|
|
346
607
|
return;
|
|
347
608
|
}
|
|
348
609
|
notifyActiveCell(cell.model);
|
|
349
|
-
|
|
350
|
-
if (state.activeCell.model.isDirty) {
|
|
351
|
-
state.dirtyCells.add(state.activeCellId);
|
|
352
|
-
}
|
|
353
|
-
else {
|
|
354
|
-
state.dirtyCells.delete(state.activeCellId);
|
|
355
|
-
}
|
|
356
|
-
state.activeCell.model.stateChanged.disconnect(onExecution, state.activeCell.model.stateChanged);
|
|
357
|
-
}
|
|
610
|
+
state.prevActiveCell = state.activeCell;
|
|
358
611
|
state.activeCell = cell;
|
|
359
|
-
state.activeCellId = cell.model.id;
|
|
360
612
|
if (state.activeCell === null ||
|
|
361
613
|
state.activeCell.model === null ||
|
|
362
614
|
state.activeCell.model.type !== 'code') {
|
|
363
615
|
return;
|
|
364
616
|
}
|
|
365
|
-
state.activeCell.model.stateChanged.connect(onExecution);
|
|
366
617
|
notifyActiveCell(state.activeCell.model);
|
|
367
|
-
if (state.dirtyCells.has(state.
|
|
368
|
-
|
|
369
|
-
if (activeCellModel._setDirty !== undefined) {
|
|
370
|
-
activeCellModel._setDirty(true);
|
|
371
|
-
}
|
|
618
|
+
if (state.dirtyCells.has(state.activeCell.model.id)) {
|
|
619
|
+
(_b = (_a = state.activeCell.model)._setDirty) === null || _b === void 0 ? void 0 : _b.call(_a, true);
|
|
372
620
|
}
|
|
373
|
-
|
|
374
|
-
updateOneCellUI(state.activeCellId);
|
|
621
|
+
updateUI(notebook);
|
|
375
622
|
};
|
|
376
623
|
const actionUpdatePairs = [
|
|
377
624
|
{
|
|
@@ -383,8 +630,8 @@ const connectToComm = (session, notebook) => {
|
|
|
383
630
|
update: 'remove',
|
|
384
631
|
},
|
|
385
632
|
];
|
|
386
|
-
const updateOneCellUI = (id) => {
|
|
387
|
-
const model = state.
|
|
633
|
+
const updateOneCellUI = (id, isSelf, inDirectSlice, inSlice, showCollapserHighlights) => {
|
|
634
|
+
const model = state.cellsById[id].model;
|
|
388
635
|
if (model.type !== 'code') {
|
|
389
636
|
return;
|
|
390
637
|
}
|
|
@@ -392,7 +639,28 @@ const connectToComm = (session, notebook) => {
|
|
|
392
639
|
if (codeModel.executionCount == null) {
|
|
393
640
|
return;
|
|
394
641
|
}
|
|
395
|
-
const elem = state.cellsById[id];
|
|
642
|
+
const elem = state.cellsById[id].node;
|
|
643
|
+
if (isSelf) {
|
|
644
|
+
elem.classList.add(selfSliceClass);
|
|
645
|
+
}
|
|
646
|
+
else {
|
|
647
|
+
elem.classList.remove(selfSliceClass);
|
|
648
|
+
}
|
|
649
|
+
if (inDirectSlice && !isSelf) {
|
|
650
|
+
elem.classList.add(directSliceClass);
|
|
651
|
+
}
|
|
652
|
+
else {
|
|
653
|
+
elem.classList.remove(directSliceClass);
|
|
654
|
+
}
|
|
655
|
+
if (inSlice && !inDirectSlice && !isSelf) {
|
|
656
|
+
elem.classList.add(sliceClass);
|
|
657
|
+
}
|
|
658
|
+
else {
|
|
659
|
+
elem.classList.remove(sliceClass);
|
|
660
|
+
}
|
|
661
|
+
if (!showCollapserHighlights) {
|
|
662
|
+
return;
|
|
663
|
+
}
|
|
396
664
|
if (state.waitingCells.has(id)) {
|
|
397
665
|
elem.classList.add(waitingClass);
|
|
398
666
|
elem.classList.add(readyClass);
|
|
@@ -404,16 +672,16 @@ const connectToComm = (session, notebook) => {
|
|
|
404
672
|
elem.classList.add(readyClass);
|
|
405
673
|
addWaitingOutputInteractions(elem, linkedReadyMakerClass);
|
|
406
674
|
}
|
|
407
|
-
if (state.
|
|
675
|
+
if (state.settings.exec_mode === 'reactive') {
|
|
408
676
|
return;
|
|
409
677
|
}
|
|
410
|
-
if (
|
|
678
|
+
if (state.waiterLinks[id] !== undefined) {
|
|
411
679
|
actionUpdatePairs.forEach(({ action, update }) => {
|
|
412
680
|
addUnsafeCellInteraction(getJpInputCollapser(elem), state.waiterLinks[id], state.cellsById, getJpInputCollapser, action, update, state.waitingCells);
|
|
413
681
|
addUnsafeCellInteraction(getJpOutputCollapser(elem), state.waiterLinks[id], state.cellsById, getJpInputCollapser, action, update, state.waitingCells);
|
|
414
682
|
});
|
|
415
683
|
}
|
|
416
|
-
if (
|
|
684
|
+
if (state.readyMakerLinks[id] !== undefined) {
|
|
417
685
|
if (!state.waitingCells.has(id)) {
|
|
418
686
|
elem.classList.add(readyMakingClass);
|
|
419
687
|
elem.classList.add(readyClass);
|
|
@@ -426,14 +694,52 @@ const connectToComm = (session, notebook) => {
|
|
|
426
694
|
};
|
|
427
695
|
const updateUI = (notebook) => {
|
|
428
696
|
clearCellState(notebook);
|
|
429
|
-
if (state.lastExecutionHighlights === 'none') {
|
|
430
|
-
return;
|
|
431
|
-
}
|
|
432
697
|
refreshNodeMapping(notebook);
|
|
698
|
+
const slice = new Set();
|
|
699
|
+
let directSlice = new Set();
|
|
700
|
+
let closureCellIds = state.selectedCells;
|
|
701
|
+
if (closureCellIds.length === 0) {
|
|
702
|
+
closureCellIds = [state.activeCell.model.id];
|
|
703
|
+
}
|
|
704
|
+
for (const cellId of closureCellIds) {
|
|
705
|
+
if (state.cellChildren[cellId] !== undefined ||
|
|
706
|
+
state.cellParents[cellId] !== undefined) {
|
|
707
|
+
directSlice = new Set([
|
|
708
|
+
cellId,
|
|
709
|
+
...directSlice,
|
|
710
|
+
...state.cellChildren[cellId],
|
|
711
|
+
...state.cellParents[cellId],
|
|
712
|
+
]);
|
|
713
|
+
computeTransitiveClosureHelper(slice, cellId, state.cellChildren);
|
|
714
|
+
slice.delete(cellId);
|
|
715
|
+
computeTransitiveClosureHelper(slice, cellId, state.cellParents);
|
|
716
|
+
}
|
|
717
|
+
}
|
|
433
718
|
for (const [id] of Object.entries(state.cellsById)) {
|
|
434
|
-
updateOneCellUI(id);
|
|
719
|
+
updateOneCellUI(id, id === state.activeCell.model.id && directSlice.has(id), directSlice.has(id), slice.has(id), state.lastExecutionHighlights !== 'none');
|
|
720
|
+
}
|
|
721
|
+
};
|
|
722
|
+
const onSelectionChanged = () => {
|
|
723
|
+
var _a, _b, _c;
|
|
724
|
+
if (disconnected) {
|
|
725
|
+
notebooks.selectionChanged.disconnect(onSelectionChanged);
|
|
726
|
+
}
|
|
727
|
+
const nbPanel = notebooks === null || notebooks === void 0 ? void 0 : notebooks.currentWidget;
|
|
728
|
+
const session = nbPanel === null || nbPanel === void 0 ? void 0 : nbPanel.sessionContext;
|
|
729
|
+
if (!((_a = session === null || session === void 0 ? void 0 : session.isReady) !== null && _a !== void 0 ? _a : false)) {
|
|
730
|
+
return;
|
|
435
731
|
}
|
|
732
|
+
const state = ((_b = ipyflowState[session.session.id]) !== null && _b !== void 0 ? _b : {});
|
|
733
|
+
if (!((_c = state.isIpyflowCommConnected) !== null && _c !== void 0 ? _c : false)) {
|
|
734
|
+
return;
|
|
735
|
+
}
|
|
736
|
+
const notebook = nbPanel.content;
|
|
737
|
+
state.selectedCells = notebook.widgets
|
|
738
|
+
.filter((cell) => cell.model.type === 'code' && notebook.isSelected(cell))
|
|
739
|
+
.map((cell) => cell.model.id);
|
|
740
|
+
updateUI(notebook);
|
|
436
741
|
};
|
|
742
|
+
notebooks.selectionChanged.connect(onSelectionChanged);
|
|
437
743
|
comm.onMsg = (msg) => {
|
|
438
744
|
var _a, _b;
|
|
439
745
|
const payload = msg.content.data;
|
|
@@ -446,38 +752,97 @@ const connectToComm = (session, notebook) => {
|
|
|
446
752
|
notebook.activeCell.model.stateChanged.connect(onExecution);
|
|
447
753
|
notifyActiveCell(notebook.activeCell.model);
|
|
448
754
|
notebook.model.contentChanged.connect(onContentChanged);
|
|
449
|
-
requestComputeExecSchedule();
|
|
755
|
+
state.requestComputeExecSchedule();
|
|
450
756
|
}
|
|
451
757
|
else if (payload.type === 'set_exec_mode') {
|
|
452
|
-
state.
|
|
453
|
-
state.
|
|
758
|
+
state.numAltModeExecutes = 0;
|
|
759
|
+
state.settings.exec_mode = payload.exec_mode;
|
|
454
760
|
}
|
|
455
761
|
else if (payload.type === 'compute_exec_schedule') {
|
|
762
|
+
state.settings = payload.settings;
|
|
763
|
+
state.cellParents = payload.cell_parents;
|
|
764
|
+
state.cellChildren = payload.cell_children;
|
|
456
765
|
state.waitingCells = new Set(payload.waiting_cells);
|
|
457
766
|
state.readyCells = new Set(payload.ready_cells);
|
|
458
|
-
state.
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
767
|
+
if (state.numPendingForcedReactiveCounterBumps === 0) {
|
|
768
|
+
state.forcedReactiveCells = new Set([
|
|
769
|
+
...state.forcedReactiveCells,
|
|
770
|
+
...payload.forced_reactive_cells,
|
|
771
|
+
]);
|
|
772
|
+
state.forcedCascadingReactiveCells = new Set([
|
|
773
|
+
...state.forcedCascadingReactiveCells,
|
|
774
|
+
...payload.forced_cascading_reactive_cells,
|
|
775
|
+
]);
|
|
776
|
+
}
|
|
777
|
+
else {
|
|
778
|
+
state.forcedReactiveCells = new Set();
|
|
779
|
+
state.forcedCascadingReactiveCells = new Set();
|
|
780
|
+
}
|
|
466
781
|
state.waiterLinks = payload.waiter_links;
|
|
467
782
|
state.readyMakerLinks = payload.ready_maker_links;
|
|
468
783
|
state.cellPendingExecution = null;
|
|
469
784
|
const exec_mode = payload.exec_mode;
|
|
470
785
|
state.isReactivelyExecuting =
|
|
471
786
|
state.isReactivelyExecuting ||
|
|
472
|
-
((_b = payload === null || payload === void 0 ? void 0 : payload.is_reactively_executing) !== null && _b !== void 0 ? _b : false)
|
|
787
|
+
((_b = payload === null || payload === void 0 ? void 0 : payload.is_reactively_executing) !== null && _b !== void 0 ? _b : false) ||
|
|
788
|
+
exec_mode === 'reactive';
|
|
789
|
+
if (exec_mode === 'reactive') {
|
|
790
|
+
state.newReadyCells = new Set([
|
|
791
|
+
...state.newReadyCells,
|
|
792
|
+
...payload.new_ready_cells,
|
|
793
|
+
]);
|
|
794
|
+
}
|
|
795
|
+
else {
|
|
796
|
+
state.newReadyCells = new Set();
|
|
797
|
+
}
|
|
473
798
|
const flow_order = payload.flow_order;
|
|
474
799
|
const exec_schedule = payload.exec_schedule;
|
|
475
|
-
state.lastExecutionMode = exec_mode;
|
|
476
800
|
state.lastExecutionHighlights = payload.highlights;
|
|
477
801
|
const lastExecutedCellId = payload.last_executed_cell_id;
|
|
478
802
|
state.executedReactiveReadyCells.add(lastExecutedCellId);
|
|
479
803
|
const last_execution_was_error = payload.last_execution_was_error;
|
|
480
|
-
|
|
804
|
+
let doneReactivelyExecuting = false;
|
|
805
|
+
if (last_execution_was_error) {
|
|
806
|
+
doneReactivelyExecuting = true;
|
|
807
|
+
}
|
|
808
|
+
else if (state.settings.reactivity_mode === 'batch') {
|
|
809
|
+
const cascadingReactiveCellIds = state
|
|
810
|
+
.computeTransitiveClosure(Array.from(state.forcedCascadingReactiveCells).filter((id) => !state.executedReactiveReadyCells.has(id)))
|
|
811
|
+
.map((cell) => cell.model.id);
|
|
812
|
+
let reactiveCells;
|
|
813
|
+
if (exec_mode === 'reactive') {
|
|
814
|
+
reactiveCells = state
|
|
815
|
+
.computeTransitiveClosure([
|
|
816
|
+
...state.newReadyCells,
|
|
817
|
+
...state.forcedReactiveCells,
|
|
818
|
+
...cascadingReactiveCellIds,
|
|
819
|
+
].filter((id) => !state.executedReactiveReadyCells.has(id)))
|
|
820
|
+
.filter((cell) => !state.executedReactiveReadyCells.has(cell.model.id));
|
|
821
|
+
}
|
|
822
|
+
else {
|
|
823
|
+
reactiveCells = [
|
|
824
|
+
...state.forcedReactiveCells,
|
|
825
|
+
...cascadingReactiveCellIds,
|
|
826
|
+
]
|
|
827
|
+
.filter((id) => !state.executedReactiveReadyCells.has(id) &&
|
|
828
|
+
state.cellsById[id] !== undefined &&
|
|
829
|
+
state.orderIdxById[id] !== undefined)
|
|
830
|
+
.sort((a, b) => state.orderIdxById[a] - state.orderIdxById[b])
|
|
831
|
+
.map((id) => state.cellsById[id]);
|
|
832
|
+
}
|
|
833
|
+
if (reactiveCells.length === 0) {
|
|
834
|
+
doneReactivelyExecuting = true;
|
|
835
|
+
}
|
|
836
|
+
else {
|
|
837
|
+
state.isReactivelyExecuting = true;
|
|
838
|
+
state.executedReactiveReadyCells = new Set([
|
|
839
|
+
...state.executedReactiveReadyCells,
|
|
840
|
+
...reactiveCells.map((cell) => cell.model.id),
|
|
841
|
+
]);
|
|
842
|
+
state.executeCells(reactiveCells);
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
else if (state.settings.reactivity_mode === 'incremental') {
|
|
481
846
|
let lastExecutedCellIdSeen = false;
|
|
482
847
|
for (const cell of notebook.widgets) {
|
|
483
848
|
if (!lastExecutedCellIdSeen) {
|
|
@@ -490,12 +855,11 @@ const connectToComm = (session, notebook) => {
|
|
|
490
855
|
state.executedReactiveReadyCells.has(cell.model.id)) {
|
|
491
856
|
continue;
|
|
492
857
|
}
|
|
493
|
-
if (!state.
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
continue;
|
|
858
|
+
if (!state.forcedReactiveCells.has(cell.model.id)) {
|
|
859
|
+
if (!state.newReadyCells.has(cell.model.id) ||
|
|
860
|
+
exec_mode !== 'reactive') {
|
|
861
|
+
continue;
|
|
862
|
+
}
|
|
499
863
|
}
|
|
500
864
|
const codeCell = cell;
|
|
501
865
|
if (state.cellPendingExecution === null) {
|
|
@@ -514,8 +878,15 @@ const connectToComm = (session, notebook) => {
|
|
|
514
878
|
state.cellPendingExecution = codeCell;
|
|
515
879
|
}
|
|
516
880
|
}
|
|
881
|
+
if (state.cellPendingExecution === null) {
|
|
882
|
+
doneReactivelyExecuting = true;
|
|
883
|
+
}
|
|
884
|
+
else {
|
|
885
|
+
state.isReactivelyExecuting = true;
|
|
886
|
+
CodeCell.execute(state.cellPendingExecution, session);
|
|
887
|
+
}
|
|
517
888
|
}
|
|
518
|
-
if (
|
|
889
|
+
if (doneReactivelyExecuting) {
|
|
519
890
|
if (state.isReactivelyExecuting) {
|
|
520
891
|
if (state.lastExecutionHighlights === 'reactive') {
|
|
521
892
|
state.readyCells = state.executedReactiveReadyCells;
|
|
@@ -524,19 +895,18 @@ const connectToComm = (session, notebook) => {
|
|
|
524
895
|
type: 'reactivity_cleanup',
|
|
525
896
|
});
|
|
526
897
|
}
|
|
898
|
+
if (state.numAltModeExecutes > 0 && --state.numAltModeExecutes === 0) {
|
|
899
|
+
state.toggleReactivity();
|
|
900
|
+
}
|
|
901
|
+
if (state.numPendingForcedReactiveCounterBumps > 0) {
|
|
902
|
+
state.bumpForcedReactiveCounter();
|
|
903
|
+
}
|
|
527
904
|
state.forcedReactiveCells = new Set();
|
|
905
|
+
state.forcedCascadingReactiveCells = new Set();
|
|
528
906
|
state.newReadyCells = new Set();
|
|
529
907
|
state.executedReactiveReadyCells = new Set();
|
|
530
|
-
updateUI(notebook);
|
|
531
908
|
state.isReactivelyExecuting = false;
|
|
532
|
-
|
|
533
|
-
state.isAltModeExecuting = false;
|
|
534
|
-
}
|
|
535
|
-
}
|
|
536
|
-
else {
|
|
537
|
-
state.isReactivelyExecuting = true;
|
|
538
|
-
onActiveCellChange(notebook, state.cellPendingExecution);
|
|
539
|
-
CodeCell.execute(state.cellPendingExecution, session);
|
|
909
|
+
updateUI(notebook);
|
|
540
910
|
}
|
|
541
911
|
}
|
|
542
912
|
};
|
package/package.json
CHANGED
package/style/index.css
CHANGED
|
@@ -62,3 +62,26 @@
|
|
|
62
62
|
.ready-making-input-cell .jp-InputCollapser:hover > .jp-Collapser-child {
|
|
63
63
|
background-color: var(--ready-making-color);
|
|
64
64
|
}
|
|
65
|
+
|
|
66
|
+
/* get rid of the '.' in the dirty indicator since we have appropriated it */
|
|
67
|
+
.jp-Notebook .jp-Cell.jp-mod-dirty .jp-InputPrompt::before {
|
|
68
|
+
color: var(--jp-warn-color1);
|
|
69
|
+
content: '';
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.jp-Notebook .jp-Cell.ipyflow-slice-self .jp-InputPrompt::before {
|
|
73
|
+
color: var(--jp-brand-color1);
|
|
74
|
+
content: '•';
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.jp-Notebook .jp-Cell.ipyflow-slice-direct .jp-InputPrompt::before {
|
|
78
|
+
color: var(--ready-making-color);
|
|
79
|
+
content: '•';
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.jp-Notebook .jp-Cell.ipyflow-slice .jp-InputPrompt::before {
|
|
83
|
+
/* color: var(--waiting-color); */
|
|
84
|
+
/* just use the same color as direct for now */
|
|
85
|
+
color: var(--ready-making-color);
|
|
86
|
+
content: '•';
|
|
87
|
+
}
|