Add element to PSI

Hi,

 

I try to add an element to a PSI but I really don't understand yet the PSI system.

A PSI is a tree with PSI element but I don't know how to add/edit/delete an element

For example I have this PHP file:

<?php

class Query {

public function handler()
{

}

}

The file is loaded like this:

URL url = ResourceUtil.getResource(getClass(), "templates", "query.php");
VirtualFile virtualFile = VfsUtil.findFileByURL(url);
PsiFile file = PsiManager.getInstance(e.getProject()).findFile(virtualFile);

After that, I don't know how to manipulate the file variable to add a PSI element and the different open source project what I'm looking seems not using the PSI like I would. Or may be I want to use it wrong.

 

For example if I want a new method I need a PSI for the "public" keyword, the "function" keyword, the method name, and so on?

 

Can you provide a simple example which add for example a method, a constructor, a field, a parameter to a method, just some simple use case and write the file in the opened project (because a PSI file loaded from VfsUtils.findFileByURL is read only)

 

Regards.

0

Hey.

Here are general IntelliJ guidelines on PSI concept http://www.jetbrains.org/intellij/sdk/docs/basics/architectural_overview/psi.html -  it can give you more general picture. 

Also consider using https://plugins.jetbrains.com/plugin/227-psiviewer plugin to discover PHP PSI structure.

 

About you concrete case: to copy content of read only file to the project you can do the following steps:

- Create non-physical file from it's content using com.intellij.psi.PsiFileFactory#createFileFromText

Put this file into some directory via com.intellij.psi.PsiDirectory::add. Directory can be obtained depending on your context, you can get some by invoking PsiElement#getContainingFile#getContainingDirectory

- Obtain the class from file: com.jetbrains.php.lang.psi.PhpPsiUtil#findClass


Create method: com.jetbrains.php.lang.psi.PhpPsiElementFactory#createMethod

Add created method to the class. Naive solution: clazz.addBefore(method, clazz.getLastChild()), you can play with it and make it more smart.

0
Avatar
Permanently deleted user

Thanks.

I already read the psi docs, and the PsiViewer plugin is installed too.

I posting the topic because the docs does not help me.

I already try to use com.intellij.psi.PsiFileFactory#createFileFromText but I don't know how to get the content of a file from my URL object.
File file = new File(url.getFile());

with this code, the file doesn't exists :/

 

0

Where is your file located? Try to use com.intellij.openapi.vfs.VirtualFileSystem#findFileByPath (via com.intellij.openapi.vfs.LocalFileSystem#getInstance) to find it, will it help?

0
Avatar
Permanently deleted user

Yes actually I get the file like this: (see first post)

URL url = ResourceUtil.getResource(getClass(), "templates", "query.php");
VirtualFile virtualFile = VfsUtil.findFileByURL(url);
PsiFile file = PsiManager.getInstance(e.getProject()).findFile(virtualFile);

But you tell me to get a psi file with com.intellij.psi.PsiFileFactory#createFileFromText instead of PsiManager.getInstance(e.getProject()).findFile(virtualFile);

The method createFileFromText can be writable? and the findFile is read only?

0

com.intellij.psi.PsiFileFactory#createFileFromText will create non-physical file which is writable, but yet not present in your project, you have to add it.

PsiManager.getInstance(e.getProject()).findFile(virtualFile); can return writable or non-writable file depending on context

To obtain text of you non-writable file, please try to use com.intellij.openapi.vfs.LocalFileSystem#getInstance#findFileByPath

0
Avatar
Permanently deleted user

Thank you.

How to get the content of a file as CharSequance from a virtualFile?

URL url = ResourceUtil.getResource(getClass(), "templates", "query.php");
VirtualFile virtualFile = VfsUtil.findFileByURL(url);
PsiFile file = PsiFileFactory.getInstance(e.getProject()).createFileFromText(virtualFile.getPath(), PhpFileType.INSTANCE);

I have the virtual file but how to get the content of the file as CharSequence ?

I don't know if my file path is ok for the createFileFromText parameter.
Currently, my file is stored in my plugin resources folder (resources/templates/query.php)

0
Avatar
Permanently deleted user

I finally get the CharSequence with LoadTextUtil.loadText(virtualFile)

 

I'm stucks with the next part :/

In your steps, you add the file to a PsiDirectory but I don't know how to get the PsiDirectory from my action.

URL url = ResourceUtil.getResource(getClass(), "templates", "query.php");
VirtualFile virtualFile = VfsUtil.findFileByURL(url);
assert virtualFile != null;
ZendGeneratorProjectComponent.getLogger().info(virtualFile.exists() ? "true" : "false");

PsiFile file = PsiFileFactory.getInstance(e.getProject()).createFileFromText(
virtualFile.getPath(),
PhpFileType.INSTANCE,
LoadTextUtil.loadText(virtualFile)
);

Could you provide a simple exemple from my code because I don't understand yet the process.

0

Please provide full code of your action class.

0
Avatar
Permanently deleted user

Here is my current code:

package fr.florent.idea.zendgenerator.action.NewGroup;

import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.fileEditor.impl.LoadTextUtil;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiFileFactory;
import com.intellij.util.ResourceUtil;
import com.jetbrains.php.lang.PhpFileType;
import fr.florent.idea.zendgenerator.ZendGeneratorProjectComponent;
import icons.PhpIcons;
import org.jetbrains.annotations.NotNull;

import java.net.URL;

public class CreateQueryAction extends AnAction {

public CreateQueryAction() {
super("Query", "Create query", PhpIcons.Php_icon);
}

@Override
public void actionPerformed(@NotNull AnActionEvent e) {
URL url = ResourceUtil.getResource(getClass(), "templates", "query.php");
VirtualFile virtualFile = VfsUtil.findFileByURL(url);

PsiFile file = PsiFileFactory.getInstance(e.getProject()).createFileFromText(
virtualFile.getPath(),
PhpFileType.INSTANCE,
LoadTextUtil.loadText(virtualFile)
);

// add method, construct, field, rename class from thé psi file

// optional: create a sub folder "factory" if it doesn't exists in the tree view project from my action

// create query.php file on the disk and refresh the project tree view to show the new file

System.out.println("Create query");
}
}
0
Avatar
Permanently deleted user

Do you have a simple example to show the different process?

0

If you invoke your action on selected folder/directory you can obtain it from event via com.intellij.openapi.actionSystem.LangDataKeys.IDE_VIEW.getData(e.getDataContext()).getOrChooseDirectory()

After that you can follow the steps that was described, please try this approach.

0
Avatar
Permanently deleted user

Thank you but I'm still stuck :/

 

I can create an empty file with the PSI directory but I can't create a file from a psi. I have an error Cannot copy non-physical file, but how to convert a PSI file to a physical file?

package fr.florent.idea.zendgenerator.action.NewGroup;

import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.LangDataKeys;
import com.intellij.openapi.fileEditor.impl.LoadTextUtil;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiFileFactory;
import com.intellij.util.ResourceUtil;
import com.jetbrains.php.lang.PhpFileType;
import fr.florent.idea.zendgenerator.ZendGeneratorProjectComponent;
import icons.PhpIcons;
import org.jetbrains.annotations.NotNull;

import java.net.URL;

public class CreateQueryAction extends AnAction {

public CreateQueryAction() {
super("Query", "Create query", PhpIcons.Php_icon);
}

@Override
public void actionPerformed(@NotNull AnActionEvent e) {
URL url = ResourceUtil.getResource(getClass(), "templates", "query.php");
VirtualFile virtualFile = VfsUtil.findFileByURL(url);
assert virtualFile != null;
ZendGeneratorProjectComponent.getLogger().info(virtualFile.exists() ? "true" : "false");

PsiFile file = PsiFileFactory.getInstance(e.getProject()).createFileFromText(
virtualFile.getPath(),
PhpFileType.INSTANCE,
LoadTextUtil.loadText(virtualFile)
);

PsiDirectory directory = LangDataKeys.IDE_VIEW.getData(e.getDataContext()).getOrChooseDirectory();

directory.copyFileFrom("test.php", file); // com.intellij.util.IncorrectOperationException: Cannot copy non-physical file: PHP file

directory.createFile("test.php"); // It's works but it's an empty file

}
}

If someone can give me a full example how to rename class name to my query.php file and write it into the PSI Directory I would be greatful because I can find a simple example.

Thank you.

0

请先登录再写评论。