Undo unavalaible after a replaceString()
Answered
Hello,
I implemented a replace Action, that change a code snippet in a java class. But after I applied my changes, I am not able to do a "undo" action by nor the GUI (the button in the Edit > Undo) nor the shortcut ctrl-z.
I looked up for a solution, and I find out about the CommandProcessor, the Application.runWriteAction and the WriteActionCommand but I did not manage to have the "undo" available after my replace.
Here, an example of implementation of the ReplaceAction that I used:
private class ReplaceAction extends AbstractAction {
private PsiExpression oldExpression;
private PsiStatement newExpression;
ReplaceAction(PsiExpression oldExpression, PsiStatement newExpression) {
super("Replace");
this.oldExpression = oldExpression;
this.newExpression = newExpression;
}
@Override
public void actionPerformed(ActionEvent e) {
PsiClass myClass = JavaPsiFacade.getInstance(project).findClass(selectedPatch.getRootClassName(), new EverythingGlobalScope(project));
OpenFileDescriptor descriptor = new OpenFileDescriptor(project, myClass.getContainingFile().getVirtualFile(), oldExpression.getTextOffset());
Editor editor = FileEditorManager.getInstance(project).openTextEditor(descriptor, true);
Document modifiedDocument = editor.getDocument();
CommandProcessor.getInstance().executeCommand(getProject(), () -> ApplicationManager.getApplication().runWriteAction(() -> {
//replace old by new
modifiedDocument.replaceString(oldExpression.getTextOffset(), oldExpression.getTextOffset() + oldExpression.getTextLength(), newExpression.getText());
//Move caret to modification
editor.getCaretModel().moveToOffset(oldExpression.getTextOffset());
//Select modification
editor.getSelectionModel().setSelection(oldExpression.getTextOffset(), oldExpression.getTextOffset() + oldExpression.getTextLength());
close(0);
}), "Replace", CommandProcessor.getInstance().getCurrentCommandGroupId(), UndoConfirmationPolicy.REQUEST_CONFIRMATION, modifiedDocument);
}
}
Could you please tell what I am doing wrong? This private class is in a class that inherit from DialogWrapper and he is one of its actions customed by the method
Action[] createActions();
Thanks.
Regards, Benjamin.
Please sign in to leave a comment.
Try passing something unique as a groupId to executeCommand method. E.g. DocCommandGroupId.noneGroupId(modifiedDocument).
Hello, thanks.
I tried as you suggest :
Even
with different kind of object in value (e.g. Integer, String, the document itself...) but nothing work, my undo action is still unavailable.
Benjamin.
Try also to invoke 'close' outside of command/write action.
Unfortunately, moving close() results with the same behavior.
Please provide a minimal project where the issue can be reproduced.
Thanks Dmitry for the help, we managed to get this undo available!
I added the commitment of the document after the modification and I used WriteCommandAction, plus the modification you suggest : unique groupId and close() statement out of the action.
Here find my snippet code :
private class ReplaceAction extends AbstractAction {
private PsiExpression oldExpression;
private PsiStatement newExpression;
ReplaceAction(PsiExpression oldExpression, PsiStatement newExpression) {
super("Replace");
this.oldExpression = oldExpression;
this.newExpression = newExpression;
}
@Override
public void actionPerformed(ActionEvent e) {
PsiClass myClass = JavaPsiFacade.getInstance(project).findClass(newExpression.getContainingFile().getName(), new EverythingGlobalScope(project));
OpenFileDescriptor descriptor = new OpenFileDescriptor(project, myClass.getContainingFile().getVirtualFile(), oldExpression.getTextOffset());
Editor editor = FileEditorManager.getInstance(project).openTextEditor(descriptor, true);
Document modifiedDocument = editor.getDocument();
CommandProcessor.getInstance().executeCommand(project, () -> WriteCommandAction.runWriteCommandAction(project, () -> {
//replace old by new
modifiedDocument.replaceString(oldExpression.getTextOffset(), oldExpression.getTextOffset() + oldExpression.getTextLength(), newExpression.getText());
//Move caret to modification
editor.getCaretModel().moveToOffset(oldExpression.getTextOffset());
//Select modification
editor.getSelectionModel().setSelection(oldExpression.getTextOffset(), oldExpression.getTextOffset() + oldExpression.getTextLength());
//Commit to reformat
PsiDocumentManager.getInstance(project).commitDocument(modifiedDocument);
//reformat
CodeStyleManager.getInstance(project).reformat(PsiDocumentManager.getInstance(project).getPsiFile(modifiedDocument), false);
}), "ReplaceAction", DocCommandGroupId.noneGroupId(modifiedDocument));
//Commit to undo
PsiDocumentManager.getInstance(project).commitDocument(modifiedDocument);
//Close frame
close(0);
}
}
Cheers,
Benjamin.