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.

6 comments
Comment actions Permalink

Try passing something unique as a groupId to executeCommand method. E.g. DocCommandGroupId.noneGroupId(modifiedDocument).

0
Comment actions Permalink

Hello, thanks.

I tried as you suggest :

DocCommandGroupId.noneGroupId(modifiedDocument)

Even

DocCommandGroupId.wtihGroupId(modifiedDocument, value)

with different kind of object in value (e.g. Integer, String, the document itself...) but nothing work, my undo action is still unavailable.

Benjamin.

 

 

0
Comment actions Permalink

Try also to invoke 'close' outside of command/write action.

0
Comment actions Permalink

Unfortunately, moving close() results with the same behavior.

0
Comment actions Permalink

Please provide a minimal project where the issue can be reproduced.

0
Comment actions Permalink

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.

0

Please sign in to leave a comment.