Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support linked undo operations #101789

Closed
jrieken opened this issue Jul 6, 2020 · 12 comments
Closed

Support linked undo operations #101789

jrieken opened this issue Jul 6, 2020 · 12 comments
Assignees
Labels
feature-request Request for new features or functionality insiders-released Patch has been released in VS Code Insiders on-testplan undo-redo Issues around undo/redo

Comments

@jrieken
Copy link
Member

jrieken commented Jul 6, 2020

This is left-over work from composite undo and describes the problem that you cannot undo a Java class rename in one operation but need two undo's.

@jrieken jrieken added this to the July 2020 milestone Jul 6, 2020
@jrieken jrieken added feature-request Request for new features or functionality undo-redo Issues around undo/redo labels Jul 6, 2020
@joaomoreno
Copy link
Member

Pushing out to August.

@rebornix
Copy link
Member

One use case from notebook, to split a cell by cursor position, what we do now is

  • delete content after the cursor in the cell
  • insert new cells into the notebook document

right now when performing above two operations, we explicitly ask them not to push undo elements into the stack, and we create a custom undo element instead. It would be simpler with linking two undo operations.

@rebornix
Copy link
Member

@alexdima @jrieken it seems there is an issue with edits with the same undo/redo comparison key in the same group, I tried to apply bulk edits like

await this._bulkEditService.apply(
	[
		new ResourceTextEdit(cell.uri, { range: textModel.getFullModelRange(), text: newLinesContents[0] }),
		new ResourceNotebookCellEdit(this._notebook.uri,
			{
				editType: CellEditType.Replace,
				index: index + 1,
				count: 0,
				cells: newLinesContents.slice(1).map(line => ({
					cellKind: kind,
					language,
					source: line,
					outputs: [],
					metadata: {}
				}))
			}
		)
	],
	{ quotableLabel: 'Split Notebook Cell' }
);

The first edit is happening on file:///.../api.github-issues#00001 and the second edit is on file:///.../api.github-issues, and their comparison key is the same. When performing Undo, it seems it will only undo edit one by one instead of undoing them all.

@rebornix
Copy link
Member

Undo with above setup will not run into this code path

const [matchedElement, matchedStrResource] = this._findClosestUndoElementInGroup(element.groupId);
if (element !== matchedElement && matchedStrResource) {
// there is an element in the same group that should be undone before this one
return this.undo(matchedStrResource);
}

@alexdima
Copy link
Member

@rebornix I did not adopt the undo redo grouping for ResourceNotebookCellEdit, basically the call to IUndoRedoService,pushUndo must also pass in the exact same UndoRedoGroup instance.

@rebornix
Copy link
Member

rebornix commented Sep 25, 2020

@alexdima I did that (passing the undoRedoGroup created by the BulkEdit service to ResourceNotebookCellEdit at the end) 3222df5 but still saw this issue.

@alexdima
Copy link
Member

I can try debugging if you could tell me the exact repro steps or you can try debugging by using const DEBUG = true in src/vs/platform/undoRedo/common/undoRedoService.ts

@rebornix
Copy link
Member

rebornix commented Sep 28, 2020

@alexdima thanks, DEBUG helps me figure out why these edits are in two different groups. The bulk edit (#101789 (comment)) includes a text edit and a notebook edit, and we pass in the same undoRedo group. However when applying the text edit, since tasks.length === 1, it does not use the undoRedo group passed in (if there are more than one text edit, they then are put in the same group).

const validation = this._validateTasks(tasks);
if (!validation.canApply) {
throw new Error(`${validation.reason.toString()} has changed in the meantime`);
}
if (tasks.length === 1) {
// This edit touches a single model => keep things simple
for (const task of tasks) {
task.model.pushStackElement();
task.apply();
task.model.pushStackElement();
this._progress.report(undefined);
}
} else {
// prepare multi model undo element
const multiModelEditStackElement = new MultiModelEditStackElement(
this._label,
tasks.map(t => new SingleModelEditStackElement(t.model, t.getBeforeCursorState()))
);
this._undoRedoService.pushElement(multiModelEditStackElement, this._undoRedoGroup);
for (const task of tasks) {
task.apply();
this._progress.report(undefined);
}
multiModelEditStackElement.close();
}

I'm wondering if we should allow pass in undoRedoGroup in task.model.pushStackElement() (and all its inner pushStackElement call)

@alexdima
Copy link
Member

@jrieken Can you please help here? I think this is something specific about bulkTextEdits.ts , like in this very special case it should behave as a cross file edit and not as a single file edit.

@jrieken
Copy link
Member Author

jrieken commented Sep 29, 2020

@alexdima Is there any harm if the simple path (task.length === 1) is being removed and we always go through the service?

@alexdima
Copy link
Member

@jrieken I think it should be fine, but I suggest we do it in the debt week, and test it out a bit. Maybe you have a way to find out this special use-case where the text edit is a part of a larger bulk edit and only do it then?

I think many extensions use some vscode API that ends up here with a single file (e.g. liveshare that I know about), and pushing multi edit stack elements with a single buffer will work, but it might end up always prompting in the undo case ("undo across all files?" even if it is a single file).

@jrieken
Copy link
Member Author

jrieken commented Sep 29, 2020

created #107677 for the follow-up work

@github-actions github-actions bot locked and limited conversation to collaborators Dec 4, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
feature-request Request for new features or functionality insiders-released Patch has been released in VS Code Insiders on-testplan undo-redo Issues around undo/redo
Projects
None yet
Development

No branches or pull requests

5 participants
@joaomoreno @rebornix @jrieken @alexdima and others