Using Editor with temporary file

Hello,
I have a plugin with which I would like to 'edit' a file, retrieve the contents, then destroy the file. I realize to get full editor functionality (like code reformatting, renaming, etc, etc,) I need the editor bound to a PSI document. It appears that this might be difficult to do. I have created Document and attempted to stream to TemporaryFileSystem, read it back, etc. but this seems quite complex.

The really tricky part is that the read, write activities need to be done with runWrite... and runRead... methods. As the plugin is not always on the UI thread, care must be taken to use runlater() when required.

Does someone have a good example and/or some things to try to make this a little easier? Is there a 'Manager' I can use that is already setup to create, say, a .java file on the fly?

Thanks!

8 comments

Hi Jon,

I'm afraid I'm not 100% sure what exactlyou want to achieve but so far it looks very similar to existing IJ functionality.

Example:

package org.denis;

import java.util.regex.Pattern;

public class SimpleTest {

  public SimpleTest(int i) {
      Pattern p = Pattern.compile(".*");
  }
}


Set caret into regexp string, press Alt+Enter and choose 'Edit Fragment' action:

action.png
It creates a new editor bound to the same document as the initial one:

fragment.png
You can check the processing details at QuickEditAction.

Denis

0

Well, close.

I'm using this code:

String text = "#if(true)#end";

                final Editor editor =
                        EditorFactory.getInstance().createEditor(text, this.project, FileTypeManager.getInstance().getFileTypeByExtension("vm"), false);




The editor does proper syntax highlighting and such (in this case, for a velocity template). However, i want to also apply the 'code reformatter' and some other actions to the right click menu. Since those actions require PSI model and virtual file existance, they don't work (stay greyed out).

How can I back the 'text' with psi model and file so the editor believes the text to be a real file while not including the file in the project?

Thanks!
0

There is an in-memory virtual file representation - LightVirtualFile. Btw, it's used at QuickEditAction as well.

Denis

0

Yes, I see that. in com.intellij.codeInsight.actions.ReformatCodeAction.java , the update(AnActionEvent) method has this code in it:


PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument());
      if (file == null || file.getVirtualFile() == null) {
        presentation.setEnabled(false);
        return;
      }




So the issue is that getVirtualFile() always returns null and thus the action cannot be selected from the menu. I can't figure out how to start with a document and get a virtual file attached to it without actually writing a file to disk and reading it back.

                final Document document = factory.createDocument(entry.getValue() != null ? entry.getValue() : "");

                LightVirtualFile lvf = new LightVirtualFile(entry.getKey() + ".vm",
                        FileTypeManager.getInstance().getFileTypeByExtension("vm"),
                        entry.getValue());
                final Editor editor =
                        factory.createEditor(document, this.project, lvf, false);




The document doesn't ever get woven with the lvf by the createEditor() function.
0
  1. Set a breakpoint at ReformatCodeAction.actionPerformed();
  2. Call 'Edit Fragment' action against the regexp from the code snippet I mentioned below;
  3. Call 'Reformat action' (Ctrl+Alt+L) at the newly opened editor;
  4. Check that all file-document-psi dependencies are correct when the breakpoint is hit;


I advise you to check the processing triggered by 'Edit Fragment' action in order to see how that connections are configured.

Denis

0

Ok, making progress. Thanks so much for your persistance. I discovered  

FileDocumentManagerImpl.registerDocument( document, virtualFile );

Which sets up the user data properly. I now get the menu not greyed out and the action is fired.

In the action (ReformatCodeAction), however, it is expecting to see a list of virtual files for that editor.

    PsiDocumentManager.getInstance(project).commitAllDocuments();
    final Editor editor = PlatformDataKeys.EDITOR.getData(dataContext);
    final VirtualFile[] files = PlatformDataKeys.VIRTUAL_FILE_ARRAY.getData(dataContext);
    if (files == null) {
      return;
    }




I would have thought that since i created the editor using:

                final Editor editor =
                        factory.createEditor(document, this.project, psiFile.getVirtualFile(), false);



That the file would have been added to the list but aparently not. I can't find any usages of PlatformDataKeys.VIRTUAL_FILE_ARRAY where the put statement is issued.

How can i push the virtual file array into the editor and/or get the editor to recognize that the files are there?

Also, i'm doing this as a 'settings' plugin so openFile() and other methods don't work (unless you can tell me how to attach the component to the settings window).

Thanks!

0

The Swing UI component for your editor needs to implement the DataProvider interface and to return the virtual files when the getData(PlatformDataKeys.VIRTUAL_FILE_ARRAY.getName()) is called.

0

Alright! making progress. I was using EditorFactory which isn't really what I should have been using. I changed over to use:

                final TextEditor fileEditor = (TextEditor) TextEditorProvider.getInstance().createEditor(getProject(), psiFile.getVirtualFile());



and everything started to work. I'm guessing that this is probably what I should have been using all along.

Thanks!
0

Please sign in to leave a comment.