diff --git a/java/java-tests/testSrc/com/intellij/ide/fileTemplates/FileTemplatesTest.groovy b/java/java-tests/testSrc/com/intellij/ide/fileTemplates/FileTemplatesTest.groovy index b1c9ce16a6b2..7096384ada98 100644 --- a/java/java-tests/testSrc/com/intellij/ide/fileTemplates/FileTemplatesTest.groovy +++ b/java/java-tests/testSrc/com/intellij/ide/fileTemplates/FileTemplatesTest.groovy @@ -36,7 +36,7 @@ public class FileTemplatesTest extends IdeaTestCase { final File customInclude = new File(testsDir, customIncludeFileName); final String includeText = FileUtil.loadFile(customInclude, FileTemplate.ourEncoding); - final FileTemplateManager templateManager = FileTemplateManager.getDefaultInstance(); + final FileTemplateManager templateManager = FileTemplateManager.getInstance(getProject()); final ArrayList originalIncludes = new ArrayList(Arrays.asList(templateManager.getAllPatterns())); try { // configure custom include @@ -67,9 +67,10 @@ public class FileTemplatesTest extends IdeaTestCase { EncodingAwareProperties properties = new EncodingAwareProperties(); properties.load(propFile, FileTemplate.ourEncoding); + properties.put(FileTemplateManager.PROJECT_NAME_VARIABLE, getProject().getName()) System.out.println(resultFile.getName()); - doTestTemplate(inputText, properties, outputText, resultFile.getParent()); + doTestTemplate(inputText, properties, outputText); } } finally { @@ -77,19 +78,19 @@ public class FileTemplatesTest extends IdeaTestCase { } } - private static void doTestTemplate(String inputString, Properties properties, String expected, String dir) throws Exception { + private void doTestTemplate(String inputString, Properties properties, String expected) throws Exception { inputString = StringUtil.convertLineSeparators(inputString); expected = StringUtil.convertLineSeparators(expected); final String result = FileTemplateUtil.mergeTemplate(properties, inputString, false); assertEquals(expected, result); - List attrs = Arrays.asList(FileTemplateUtil.calculateAttributes(inputString, new Properties(), false)); - assertTrue(properties.size() <= attrs.size()); + List attrs = Arrays.asList(FileTemplateUtil.calculateAttributes(inputString, new Properties(), false, getProject())); + assertTrue(properties.size() - 1 <= attrs.size()); Enumeration e = properties.propertyNames(); while (e.hasMoreElements()) { String s = (String)e.nextElement(); - assertTrue("Attribute '" + s + "' not found in properties", attrs.contains(s)); + assertTrue("Attribute '" + s + "' not found in properties", attrs.contains(s) || FileTemplateManager.PROJECT_NAME_VARIABLE.equals(s)); } } @@ -102,7 +103,7 @@ public class FileTemplatesTest extends IdeaTestCase { FileTemplate template = addTestTemplate("myclass", '${ABC} ${DEF} ${NAME}') Properties properties = new Properties() properties.NAME = 'zzz' - assert template.getUnsetAttributes(properties) as Set == ['ABC', 'DEF'] as Set + assert template.getUnsetAttributes(properties, project) as Set == ['ABC', 'DEF'] as Set } public void "test collect undefined attribute names from included templates"() { @@ -112,7 +113,7 @@ public class FileTemplatesTest extends IdeaTestCase { FileTemplate template = addTestTemplate("myclass", '#parse("included.java") ${DEF} ${NAME}') Properties properties = new Properties() properties.NAME = 'zzz' - assert template.getUnsetAttributes(properties) as Set == ['ABC', 'DEF'] as Set + assert template.getUnsetAttributes(properties, project) as Set == ['ABC', 'DEF'] as Set } public void testDefaultPackage() throws Exception { diff --git a/platform/lang-impl/src/com/intellij/ide/fileTemplates/FileTemplate.java b/platform/lang-impl/src/com/intellij/ide/fileTemplates/FileTemplate.java index 80dd1470f5d4..95c53d95c5e5 100644 --- a/platform/lang-impl/src/com/intellij/ide/fileTemplates/FileTemplate.java +++ b/platform/lang-impl/src/com/intellij/ide/fileTemplates/FileTemplate.java @@ -17,6 +17,7 @@ package com.intellij.ide.fileTemplates; import com.intellij.openapi.fileTypes.FileType; +import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.CharsetToolkit; import org.apache.velocity.runtime.parser.ParseException; import org.jetbrains.annotations.NotNull; @@ -49,8 +50,6 @@ public interface FileTemplate extends Cloneable { String ATTRIBUTE_NAME = "NAME"; String ATTRIBUTE_FILE_NAME = "FILE_NAME"; - @NotNull String[] getUnsetAttributes(@NotNull Properties properties) throws ParseException; - /** Name without extension */ @NotNull String getName(); @@ -83,4 +82,6 @@ public interface FileTemplate extends Cloneable { void setReformatCode(boolean reformat); FileTemplate clone(); + + @NotNull String[] getUnsetAttributes(@NotNull Properties properties, Project project) throws ParseException; } diff --git a/platform/lang-impl/src/com/intellij/ide/fileTemplates/FileTemplateManager.java b/platform/lang-impl/src/com/intellij/ide/fileTemplates/FileTemplateManager.java index 576a22766485..d8228a2650e5 100644 --- a/platform/lang-impl/src/com/intellij/ide/fileTemplates/FileTemplateManager.java +++ b/platform/lang-impl/src/com/intellij/ide/fileTemplates/FileTemplateManager.java @@ -50,6 +50,8 @@ public abstract class FileTemplateManager{ public static final String CODE_TEMPLATES_CATEGORY = "Code"; public static final String J2EE_TEMPLATES_CATEGORY = "J2EE"; + public static final String PROJECT_NAME_VARIABLE = "PROJECT_NAME"; + public static FileTemplateManager getInstance(@NotNull Project project){ return ServiceManager.getService(project, FileTemplateManager.class); } @@ -89,7 +91,7 @@ public abstract class FileTemplateManager{ @NotNull public Properties getDefaultProperties(@NotNull Project project) { Properties properties = getDefaultProperties(); - properties.setProperty("PROJECT_NAME", project.getName()); + properties.setProperty(PROJECT_NAME_VARIABLE, project.getName()); return properties; } diff --git a/platform/lang-impl/src/com/intellij/ide/fileTemplates/FileTemplateUtil.java b/platform/lang-impl/src/com/intellij/ide/fileTemplates/FileTemplateUtil.java index 11a4cd195a6a..3e94b0af1500 100644 --- a/platform/lang-impl/src/com/intellij/ide/fileTemplates/FileTemplateUtil.java +++ b/platform/lang-impl/src/com/intellij/ide/fileTemplates/FileTemplateUtil.java @@ -31,12 +31,14 @@ import com.intellij.openapi.project.ProjectManager; import com.intellij.openapi.project.ex.ProjectManagerEx; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.ClassLoaderUtil; +import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.ThrowableComputable; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiDirectory; import com.intellij.psi.PsiElement; import com.intellij.psi.codeStyle.CodeStyleSettingsManager; import com.intellij.util.ArrayUtil; +import com.intellij.util.containers.ContainerUtil; import org.apache.commons.collections.ExtendedProperties; import org.apache.velocity.VelocityContext; import org.apache.velocity.app.Velocity; @@ -66,6 +68,7 @@ import java.util.*; public class FileTemplateUtil{ private static final Logger LOG = Logger.getInstance("#com.intellij.ide.fileTemplates.FileTemplateUtil"); private static final CreateFromTemplateHandler ourDefaultCreateFromTemplateHandler = new DefaultCreateFromTemplateHandler(); + private static final ThreadLocal ourTemplateManager = new ThreadLocal(); @NonNls public static final String INTERNAL_PACKAGE_INFO_TEMPLATE_NAME = "package-info"; @@ -74,8 +77,6 @@ public class FileTemplateUtil{ static { try{ - final FileTemplateManager templateManager = FileTemplateManager.getInstance(ProjectManager.getInstance().getDefaultProject()); - LogSystem emptyLogSystem = new LogSystem() { @Override public void init(RuntimeServices runtimeServices) throws Exception { @@ -97,6 +98,8 @@ public class FileTemplateUtil{ @Override public InputStream getResourceStream(String resourceName) throws ResourceNotFoundException { + FileTemplateManager templateManager = ourTemplateManager.get(); + if (templateManager == null) templateManager = FileTemplateManager.getDefaultInstance(); final FileTemplate include = templateManager.getPattern(resourceName); if (include == null) { throw new ResourceNotFoundException("Template not found: " + resourceName); @@ -127,36 +130,42 @@ public class FileTemplateUtil{ } } - public static String[] calculateAttributes(String templateContent, Properties properties, boolean includeDummies) throws ParseException { + public static String[] calculateAttributes(String templateContent, Properties properties, boolean includeDummies, Project project) throws ParseException { Set propertiesNames = new HashSet(); for (Enumeration e = properties.propertyNames(); e.hasMoreElements(); ) { propertiesNames.add((String)e.nextElement()); } - return calculateAttributes(templateContent, propertiesNames, includeDummies); + return calculateAttributes(templateContent, propertiesNames, includeDummies, project); } - public static String[] calculateAttributes(String templateContent, Map properties, boolean includeDummies) throws ParseException { - return calculateAttributes(templateContent, properties.keySet(), includeDummies); + public static String[] calculateAttributes(String templateContent, Map properties, boolean includeDummies, Project project) throws ParseException { + return calculateAttributes(templateContent, properties.keySet(), includeDummies, project); } - public static String[] calculateAttributes(String templateContent, Set propertiesNames, boolean includeDummies) throws ParseException { + private static String[] calculateAttributes(String templateContent, Set propertiesNames, boolean includeDummies, Project project) throws ParseException { final Set unsetAttributes = new LinkedHashSet(); final Set definedAttributes = new HashSet(); //noinspection HardCodedStringLiteral SimpleNode template = RuntimeSingleton.parse(new StringReader(templateContent), "MyTemplate"); - collectAttributes(unsetAttributes, definedAttributes, template, propertiesNames, includeDummies, new HashSet()); + collectAttributes(unsetAttributes, definedAttributes, template, propertiesNames, includeDummies, new HashSet(), project); for (String definedAttribute : definedAttributes) { unsetAttributes.remove(definedAttribute); } return ArrayUtil.toStringArray(unsetAttributes); } - private static void collectAttributes(Set referenced, Set defined, Node apacheNode, final Set propertiesNames, final boolean includeDummies, Set visitedIncludes) + private static void collectAttributes(Set referenced, + Set defined, + Node apacheNode, + final Set propertiesNames, + final boolean includeDummies, + Set visitedIncludes, + Project project) throws ParseException { int childCount = apacheNode.jjtGetNumChildren(); for(int i = 0; i < childCount; i++){ Node apacheChild = apacheNode.jjtGetChild(i); - collectAttributes(referenced, defined, apacheChild, propertiesNames, includeDummies, visitedIncludes); + collectAttributes(referenced, defined, apacheChild, propertiesNames, includeDummies, visitedIncludes, project); if (apacheChild instanceof ASTReference){ ASTReference apacheReference = (ASTReference)apacheChild; String s = apacheReference.literal(); @@ -178,10 +187,10 @@ public class FileTemplateUtil{ Token firstToken = literal.getFirstToken(); if (firstToken != null) { String s = StringUtil.unquoteString(firstToken.toString()); - final FileTemplate includedTemplate = FileTemplateManager.getDefaultInstance().getTemplate(s); + final FileTemplate includedTemplate = FileTemplateManager.getInstance(project).getTemplate(s); if (includedTemplate != null && visitedIncludes.add(s)) { SimpleNode template = RuntimeSingleton.parse(new StringReader(includedTemplate.getText()), "MyTemplate"); - collectAttributes(referenced, defined, template, propertiesNames, includeDummies, visitedIncludes); + collectAttributes(referenced, defined, template, propertiesNames, includeDummies, visitedIncludes, project); } } } @@ -270,7 +279,24 @@ public class FileTemplateUtil{ private static String mergeTemplate(String templateContent, final VelocityContext context, boolean useSystemLineSeparators) throws IOException { final StringWriter stringWriter = new StringWriter(); try { - Velocity.evaluate(context, stringWriter, "", templateContent); + Project project = null; + final Object projectName = context.get(FileTemplateManager.PROJECT_NAME_VARIABLE); + if (projectName instanceof String) { + Project[] projects = ProjectManager.getInstance().getOpenProjects(); + project = ContainerUtil.find(projects, new Condition() { + @Override + public boolean value(Project project) { + return projectName.equals(project.getName()); + } + }); + } + try { + ourTemplateManager.set(project == null ? FileTemplateManager.getDefaultInstance() : FileTemplateManager.getInstance(project)); + Velocity.evaluate(context, stringWriter, "", templateContent); + } + finally { + ourTemplateManager.set(null); + } } catch (final VelocityException e) { if (ApplicationManager.getApplication().isUnitTestMode()) { @@ -356,7 +382,7 @@ public class FileTemplateUtil{ } //Set escaped references to dummy values to remove leading "\" (if not already explicitly set) - String[] dummyRefs = calculateAttributes(template.getText(), propsMap, true); + String[] dummyRefs = calculateAttributes(template.getText(), propsMap, true, directory.getProject()); for (String dummyRef : dummyRefs) { propsMap.put(dummyRef, ""); } diff --git a/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/FileTemplateBase.java b/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/FileTemplateBase.java index 73ee43594f87..6662bd0a4d65 100644 --- a/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/FileTemplateBase.java +++ b/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/FileTemplateBase.java @@ -19,6 +19,7 @@ import com.intellij.ide.fileTemplates.FileTemplate; import com.intellij.ide.fileTemplates.FileTemplateUtil; import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.fileTypes.ex.FileTypeManagerEx; +import com.intellij.openapi.project.Project; import com.intellij.openapi.util.text.StringUtil; import org.apache.velocity.runtime.parser.ParseException; import org.jetbrains.annotations.NotNull; @@ -94,8 +95,8 @@ public abstract class FileTemplateBase implements FileTemplate { @Override @NotNull - public final String[] getUnsetAttributes(@NotNull Properties properties) throws ParseException { - return FileTemplateUtil.calculateAttributes(getText(), properties, false); + public final String[] getUnsetAttributes(@NotNull Properties properties, Project project) throws ParseException { + return FileTemplateUtil.calculateAttributes(getText(), properties, false, project); } @Override diff --git a/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/FileTemplateManagerImpl.java b/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/FileTemplateManagerImpl.java index b8dc54299fd8..cf6f4d19d616 100644 --- a/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/FileTemplateManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/FileTemplateManagerImpl.java @@ -210,7 +210,7 @@ public class FileTemplateManagerImpl extends FileTemplateManager implements Pers props.setProperty("DS", "$"); // Dollar sign, strongly needed for PHP, JS, etc. See WI-8979 - props.setProperty("PROJECT_NAME", myProject.getName()); + props.setProperty(PROJECT_NAME_VARIABLE, myProject.getName()); return props; } diff --git a/platform/lang-impl/src/com/intellij/ide/fileTemplates/ui/CreateFromTemplateDialog.java b/platform/lang-impl/src/com/intellij/ide/fileTemplates/ui/CreateFromTemplateDialog.java index 937873efb02b..8eec7b714cec 100644 --- a/platform/lang-impl/src/com/intellij/ide/fileTemplates/ui/CreateFromTemplateDialog.java +++ b/platform/lang-impl/src/com/intellij/ide/fileTemplates/ui/CreateFromTemplateDialog.java @@ -72,7 +72,7 @@ public class CreateFromTemplateDialog extends DialogWrapper { String[] unsetAttributes = null; try { - unsetAttributes = myTemplate.getUnsetAttributes(myDefaultProperties); + unsetAttributes = myTemplate.getUnsetAttributes(myDefaultProperties, project); } catch (ParseException e) { showErrorDialog(e);