File Template extension with IntelliJ plugin

2019-08-18 03:28发布

问题:

So I want to create a file template in my IntelliJ IDEA plugin and I managed to mine these out from some other plugins, but the template always wants to be a java file and I cannot change the extension of it to be .cqt insteaf of .java
What I figured out:

I need to add these to the plugin.xml

<internalFileTemplate name="Croquette File" />

and I need

<createFromTemplateHandler implementation="...CroquetteCreateFromTemplateHandler" />

with the file creation action

<action
       id="Croquette.NewFile"
       class="...NewCroquetteFileDefinitionAction"
       text="Croquette File"
       description="Create a new Croquette file" >
    <add-to-group group-id="NewGroup" anchor="after" relative-to-action="NewGroup1"/>
</action>

The NewCroquetteFileDefinitionAction contains this:

class NewCroquetteFileDefinitionAction
        extends CreateFileFromTemplateAction(
            NewCroquetteFileDefinitionAction.NEW_CQT_FILE,
            "",
            CroquetteIcons.fileIcon)
        with DumbAware {

    import NewCroquetteFileDefinitionAction._

    override def buildDialog(
            project: Project,
            directory: PsiDirectory,
            builder: CreateFileFromTemplateDialog.Builder): Unit = {
        builder
            .setTitle(NEW_CQT_FILE)
            .addKind("Croquette File", CroquetteIcons.fileIcon, "Croquette File")
            .setValidator(new InputValidatorEx {
                override def getErrorText(inputString: String): String =
                    if (!inputString.isEmpty && !containsFuckyCharacters(inputString))
                        s"'$inputString' is not a valid Croquette file name."
                    else null

                override def checkInput(inputString: String): Boolean = getErrorText(inputString) != null


                override def canClose(inputString: String): Boolean = checkInput(inputString)
            })
    }

    override def getActionName(directory: PsiDirectory, newName: String, templateName: String): String = NEW_CQT_FILE

    override def hashCode(): Int = 0

    override def equals(obj: Any): Boolean = obj.isInstanceOf[NewCroquetteFileDefinitionAction]
}

object NewCroquetteFileDefinitionAction {
    val NEW_CQT_FILE = "New Croquette File"

    def containsFuckyCharacters(strIn: String): Boolean = {
        List("+", "-", "<", ">", "\\", "/", ",", ".", "[", "]", "{", "}", "@", "&", "$", ";", "*").foreach(ch =>
            if (strIn.contains(ch))
                return true
        )
        false
    }
}

And I am guessing I have to do something here in the CroquetteDefaultPropertiesProvider class but not sure what, or even if that guess is correct or not as I cannot find any documentation on how to create file templates with plugins.

class CroquetteDefaultPropertiesProvider extends TemplatePackagePropertyProvider {

    override def fillProperties(directory: PsiDirectory, props: Properties) {
        super.fillProperties(directory, props)
    }
}

回答1:

You need to put some Name.your-lang-extension.ft files under fileTemplates package, like this, and declare <internalFileTemplate name="Name" />, like this (this Name corresponds to the Name in Name.your-lang-extension.ft).
In the template files you may use some variables, there're some predefined ones and you can use your own. The syntax is ${MY_VAR}.
Then you should implement buildDialog like this, the third argument to addKind is the Name in Name.your-lang-extension.ft, the first one is the displayed name.

Then you should create a action class extending CreateFileFromTemplateAction, like this, and create a Properties instance by using FileTemplateManager.getInstance(project).defaultProperties like this and add some properties like this which will be filled in to the variables, like you can properties.add("MY_VAR", yourCodeToGetSomeInformation()) and ${MY_VAR} in your template will the replaced with the return value of yourCodeToGetSomeInformation().

After that you should implement createFileFromTemplate like this, the key part is the call to CreateFromTemplateDialog's create(), just look at my code example and you'll know.

After implementing the action class you should register it into plugin.xml just like what you're doing now.

BTW please remove your dangerously incorrect implementation of equals and hashCode.

You don't need a createFromTemplateHandler.