Skip to content

Commit 596e1cf

Browse files
committed
fix #4153 -- Jupyter: focus cell on undo/redo
1 parent b0a3f25 commit 596e1cf

File tree

4 files changed

+71
-8
lines changed

4 files changed

+71
-8
lines changed

src/packages/frontend/frame-editors/jupyter-editor/actions.ts

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -190,14 +190,23 @@ export class JupyterEditorActions extends BaseActions<JupyterEditorState> {
190190

191191
// per-session sync-aware undo
192192
undo(id: string): void {
193-
id = id; // not used yet, since only one thing that can be undone.
194-
this.jupyter_actions.undo();
193+
const actions = this.get_frame_actions(id);
194+
if (actions != null) {
195+
// this properly moves the selection, so prefer if available
196+
actions.undo();
197+
} else {
198+
this.jupyter_actions.undo();
199+
}
195200
}
196201

197202
// per-session sync-aware redo
198203
redo(id: string): void {
199-
id = id; // not used yet
200-
this.jupyter_actions.redo();
204+
const actions = this.get_frame_actions(id);
205+
if (actions != null) {
206+
actions.redo();
207+
} else {
208+
this.jupyter_actions.redo();
209+
}
201210
}
202211

203212
cut(id: string): void {

src/packages/frontend/frame-editors/jupyter-editor/cell-notebook/actions.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1095,5 +1095,50 @@ export class NotebookFrameActions {
10951095
}
10961096
this.jupyter_actions.syncdb.commit();
10971097
};
1098+
1099+
private focusFirstChangedCell = (before) => {
1100+
const store = this.jupyter_actions.store;
1101+
const after = store.get("cells");
1102+
const ids = store.get_cell_list();
1103+
const id = firstChangedCell({ before, after, ids });
1104+
if (id) {
1105+
this.set_cur_id(id);
1106+
this.scroll("cell visible");
1107+
setTimeout(() => this.scroll("cell visible"), 1);
1108+
}
1109+
};
1110+
1111+
undo = () => {
1112+
const before = this.jupyter_actions.store.get("cells");
1113+
this.jupyter_actions.syncdb.undo();
1114+
setTimeout(() => this.focusFirstChangedCell(before), 1);
1115+
};
1116+
1117+
redo = () => {
1118+
const before = this.jupyter_actions.store.get("cells");
1119+
this.jupyter_actions.syncdb.redo();
1120+
setTimeout(() => this.focusFirstChangedCell(before), 1);
1121+
};
10981122
}
10991123

1124+
// This function returns the id of the first (minimal position)
1125+
// cell that changed going from before to after, or
1126+
// null if no cells changed. An annoying subtlety is that if
1127+
// you reorder cells then *all* positions may change (to keep them
1128+
// separated and sane) and then all cells are different. It's
1129+
// an edge case, and handling it in a more expected way would be much
1130+
// more difficult and slower, so we don't.
1131+
function firstChangedCell({ before, after, ids }): string | null {
1132+
// before and after are immutablejs cells maps, from
1133+
// cell id to cell description.
1134+
if (before.equals(after)) {
1135+
// obviously, nothing changed.
1136+
return null;
1137+
}
1138+
for (const id of ids) {
1139+
if (!before.get(id)?.equals(after.get(id))) {
1140+
return id;
1141+
}
1142+
}
1143+
return null;
1144+
}

src/packages/frontend/jupyter/codemirror-editor.tsx

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -411,14 +411,23 @@ export const CodeMirrorEditor: React.FC<CodeMirrorEditorProps> = ({
411411
) {
412412
cm_save();
413413
}
414-
actions.undo();
414+
if (frameActions.current) {
415+
// prefer this, because can update selection
416+
frameActions.current.undo();
417+
} else {
418+
actions.undo();
419+
}
415420
}
416421

417422
function cm_redo(): void {
418423
if (cm.current == null || actions == null) {
419424
return;
420425
}
421-
actions.redo();
426+
if (frameActions.current) {
427+
frameActions.current.redo();
428+
} else {
429+
actions.redo();
430+
}
422431
}
423432

424433
function shift_tab_key(): void {

src/packages/frontend/jupyter/commands.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,7 @@ export function commands(actions: AllActions): {
389389
{ alt: true, mode: "escape", which: 90 },
390390
{ ctrl: true, mode: "escape", which: 90 },
391391
],
392-
f: () => actions.jupyter_actions?.undo(),
392+
f: () => actions.frame_actions?.undo(),
393393
},
394394

395395
"global redo": {
@@ -402,7 +402,7 @@ export function commands(actions: AllActions): {
402402
{ alt: true, mode: "escape", which: 89 },
403403
{ ctrl: true, mode: "escape", which: 89 },
404404
],
405-
f: () => actions.jupyter_actions?.redo(),
405+
f: () => actions.frame_actions?.redo(),
406406
},
407407

408408
"hide all line numbers": {

0 commit comments

Comments
 (0)