Skip to content

Commit 5c7b94e

Browse files
authored
Fix dirty state not matching save button state (#9993)
* Fix dirty state not matching save button state * Fix modify to update UI too Make a 'save' point for the undo count. Looks like this is what the editor is doing.
1 parent 597275c commit 5c7b94e

File tree

4 files changed

+33
-8
lines changed

4 files changed

+33
-8
lines changed

src/client/datascience/interactive-ipynb/nativeEditor.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ import {
4545
WebViewViewChangeEventArgs
4646
} from '../types';
4747

48+
// tslint:disable-next-line: no-require-imports
49+
import cloneDeep = require('lodash/cloneDeep');
50+
4851
const nativeEditorDir = path.join(EXTENSION_ROOT_DIR, 'out', 'datascience-ui', 'notebook');
4952
@injectable()
5053
export class NativeEditor extends InteractiveBase implements INotebookEditor {
@@ -345,7 +348,7 @@ export class NativeEditor extends InteractiveBase implements INotebookEditor {
345348
source: 'user',
346349
kind: 'modify',
347350
newCells: modified,
348-
oldCells: unmodified,
351+
oldCells: cloneDeep(unmodified),
349352
oldDirty: this._model.isDirty,
350353
newDirty: true
351354
});

src/client/datascience/interactive-ipynb/nativeEditorProvider.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,12 @@ export class NativeEditorProvider implements INotebookEditorProvider, WebviewCus
197197

198198
private closedEditor(editor: INotebookEditor): void {
199199
this.openedEditors.delete(editor);
200+
// If last editor, dispose of the storage
201+
const key = editor.file.toString();
202+
if (![...this.openedEditors].find(e => e.file.toString() === key)) {
203+
this.modelChangedHandlers.delete(key);
204+
this.models.delete(key);
205+
}
200206
this._onDidCloseNotebookEditor.fire(editor);
201207
}
202208

src/client/datascience/interactive-ipynb/nativeEditorStorage.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,15 @@ const NotebookTransferKey = 'notebook-transfered';
2626
interface INativeEditorStorageState {
2727
file: Uri;
2828
cells: ICell[];
29-
changeCountSinceSave: number;
29+
changeCount: number;
30+
saveChangeCount: number;
3031
notebookJson: Partial<nbformat.INotebookContent>;
3132
}
3233

3334
@injectable()
3435
export class NativeEditorStorage implements INotebookModel, INotebookStorage {
3536
public get isDirty(): boolean {
36-
return this._state.changeCountSinceSave > 0;
37+
return this._state.changeCount !== this._state.saveChangeCount && this._state.changeCount !== 0;
3738
}
3839
public get changed(): Event<NotebookModelChange> {
3940
return this._changedEmitter.event;
@@ -49,7 +50,7 @@ export class NativeEditorStorage implements INotebookModel, INotebookStorage {
4950
return this._state.cells;
5051
}
5152
private _changedEmitter = new EventEmitter<NotebookModelChange>();
52-
private _state: INativeEditorStorageState = { file: Uri.file(''), changeCountSinceSave: 0, cells: [], notebookJson: {} };
53+
private _state: INativeEditorStorageState = { file: Uri.file(''), changeCount: 0, saveChangeCount: 0, cells: [], notebookJson: {} };
5354
private indentAmount: string = ' ';
5455

5556
constructor(
@@ -145,7 +146,7 @@ export class NativeEditorStorage implements INotebookModel, INotebookStorage {
145146
case 'file':
146147
changed = !this.fileSystem.arePathsSame(this._state.file.fsPath, change.newFile.fsPath);
147148
this._state.file = change.newFile;
148-
this._state.changeCountSinceSave = 0;
149+
this._state.saveChangeCount = this._state.changeCount;
149150
break;
150151
default:
151152
break;
@@ -154,7 +155,7 @@ export class NativeEditorStorage implements INotebookModel, INotebookStorage {
154155
// Dirty state comes from undo. At least VS code will track it that way. However
155156
// skip version and file changes as we don't forward those to VS code
156157
if (change.kind !== 'file' && change.kind !== 'version') {
157-
this._state.changeCountSinceSave += 1;
158+
this._state.changeCount += 1;
158159
}
159160

160161
return changed;
@@ -194,7 +195,7 @@ export class NativeEditorStorage implements INotebookModel, INotebookStorage {
194195
// Dirty state comes from undo. At least VS code will track it that way.
195196
// Note unlike redo, 'file' and 'version' are not possible on undo as
196197
// we don't send them to VS code.
197-
this._state.changeCountSinceSave -= 1;
198+
this._state.changeCount -= 1;
198199

199200
return changed;
200201
}

src/datascience-ui/native-editor/redux/reducers/creation.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -278,8 +278,16 @@ export namespace Creation {
278278
...disabledQueueArg,
279279
payload: { ...arg.payload, data: { firstCellId: arg.payload.data.secondCellId, secondCellId: arg.payload.data.firstCellId } }
280280
});
281+
case 'modify':
282+
// Undo for modify should reapply the outputs. Go through each and apply the update
283+
let result = arg.prevState;
284+
arg.payload.data.oldCells.forEach(c => {
285+
result = updateCell({ ...disabledQueueArg, prevState: result, payload: { ...arg.payload, data: c } });
286+
});
287+
return result;
288+
281289
default:
282-
// Modify, file, version can all be ignored.
290+
// File, version can be ignored.
283291
break;
284292
}
285293

@@ -307,6 +315,13 @@ export namespace Creation {
307315
...disabledQueueArg,
308316
payload: { ...arg.payload, data: { firstCellId: arg.payload.data.secondCellId, secondCellId: arg.payload.data.firstCellId } }
309317
});
318+
case 'modify':
319+
// Redo for modify should reapply the outputs. Go through each and apply the update
320+
let result = arg.prevState;
321+
arg.payload.data.newCells.forEach(c => {
322+
result = updateCell({ ...disabledQueueArg, prevState: result, payload: { ...arg.payload, data: c } });
323+
});
324+
return result;
310325
default:
311326
// Modify, file, version can all be ignored.
312327
break;

0 commit comments

Comments
 (0)