From 555c34b6d16df97da15213f5e165f12c3e866d50 Mon Sep 17 00:00:00 2001 From: Dmitry Avdeev Date: Thu, 17 Sep 2015 16:08:11 +0300 Subject: [PATCH] IDEA-45030 Add ability to specify cursor position in File Templates (e.g. special macros as for Live Templates) --- .../ide/actions/CreatePackageInfoAction.java | 9 +-- .../EmbeddedLiveTemplatesTest.java | 58 +++++++++++++++++++ .../ide/fileTemplates/FileTemplate.java | 4 ++ .../actions/CreateFromTemplateAction.java | 8 --- .../actions/CreateFromTemplateActionBase.java | 36 +++++++++++- .../fileTemplates/impl/FileTemplateBase.java | 11 ++++ .../ui/CreateFromTemplateDialog.java | 6 ++ .../impl/CodeInsightTestFixtureImpl.java | 1 - 8 files changed, 114 insertions(+), 19 deletions(-) create mode 100644 java/java-tests/testSrc/com/intellij/ide/fileTemplates/EmbeddedLiveTemplatesTest.java diff --git a/java/java-impl/src/com/intellij/ide/actions/CreatePackageInfoAction.java b/java/java-impl/src/com/intellij/ide/actions/CreatePackageInfoAction.java index be70cc8a5d8a..7d93a1233dae 100644 --- a/java/java-impl/src/com/intellij/ide/actions/CreatePackageInfoAction.java +++ b/java/java-impl/src/com/intellij/ide/actions/CreatePackageInfoAction.java @@ -30,6 +30,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ProjectFileIndex; import com.intellij.openapi.roots.ProjectRootManager; import com.intellij.openapi.ui.Messages; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.util.PsiUtil; import org.jetbrains.annotations.Nullable; @@ -98,7 +99,7 @@ public class CreatePackageInfoAction extends CreateFromTemplateActionBase implem final PsiPackage aPackage = directoryService.getPackage(directory); if (aPackage != null) { final String qualifiedName = aPackage.getQualifiedName(); - if (com.intellij.openapi.util.text.StringUtil.isEmpty(qualifiedName) || nameHelper.isQualifiedName(qualifiedName)) { + if (StringUtil.isEmpty(qualifiedName) || nameHelper.isQualifiedName(qualifiedName)) { return true; } } @@ -114,12 +115,6 @@ public class CreatePackageInfoAction extends CreateFromTemplateActionBase implem return new AttributesDefaults(FileTemplateUtil.INTERNAL_PACKAGE_INFO_TEMPLATE_NAME).withFixedName(true); } - @Nullable - @Override - protected AnAction getReplacedAction(FileTemplate selectedTemplate) { - return null; - } - @Override protected FileTemplate getTemplate(Project project, PsiDirectory dir) { return FileTemplateManager.getInstance(project).getInternalTemplate(FileTemplateUtil.INTERNAL_PACKAGE_INFO_TEMPLATE_NAME); diff --git a/java/java-tests/testSrc/com/intellij/ide/fileTemplates/EmbeddedLiveTemplatesTest.java b/java/java-tests/testSrc/com/intellij/ide/fileTemplates/EmbeddedLiveTemplatesTest.java new file mode 100644 index 000000000000..33774c346967 --- /dev/null +++ b/java/java-tests/testSrc/com/intellij/ide/fileTemplates/EmbeddedLiveTemplatesTest.java @@ -0,0 +1,58 @@ +/* + * Copyright 2000-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.ide.fileTemplates; + +import com.intellij.ide.fileTemplates.actions.CreateFromTemplateActionBase; +import com.intellij.ide.fileTemplates.impl.CustomFileTemplate; +import com.intellij.openapi.fileEditor.FileEditorManager; +import com.intellij.openapi.fileTypes.PlainTextFileType; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.PsiDirectory; +import com.intellij.testFramework.fixtures.LightPlatformCodeInsightFixtureTestCase; + +/** + * @author Dmitry Avdeev + */ +public class EmbeddedLiveTemplatesTest extends LightPlatformCodeInsightFixtureTestCase { + + public void testCreateFromTemplateAction() throws Exception { + + myFixture.configureByText(PlainTextFileType.INSTANCE, ""); + CustomFileTemplate template = new CustomFileTemplate("foo", "txt"); + template.setText("Put caret here: #[[$END$]]# end of template"); + template.setHasEmbeddedLiveTemplate(true); + myFixture.testAction(new TestAction(template)); + VirtualFile[] files = FileEditorManager.getInstance(getProject()).getSelectedFiles(); + myFixture.openFileInEditor(files[0]); + myFixture.checkResult("Put caret here: end of template"); + } + + private static class TestAction extends CreateFromTemplateActionBase { + + private final FileTemplate myTemplate; + + public TestAction(FileTemplate template) { + super("", "", null); + myTemplate = template; + } + + @Override + protected FileTemplate getTemplate(Project project, PsiDirectory dir) { + return myTemplate; + } + } +} 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 95c53d95c5e5..17cf0febeee6 100644 --- a/platform/lang-impl/src/com/intellij/ide/fileTemplates/FileTemplate.java +++ b/platform/lang-impl/src/com/intellij/ide/fileTemplates/FileTemplate.java @@ -81,6 +81,10 @@ public interface FileTemplate extends Cloneable { void setReformatCode(boolean reformat); + boolean isHasEmbeddedLiveTemplate(); + + void setHasEmbeddedLiveTemplate(boolean hasEmbeddedLiveTemplate); + FileTemplate clone(); @NotNull String[] getUnsetAttributes(@NotNull Properties properties, Project project) throws ParseException; diff --git a/platform/lang-impl/src/com/intellij/ide/fileTemplates/actions/CreateFromTemplateAction.java b/platform/lang-impl/src/com/intellij/ide/fileTemplates/actions/CreateFromTemplateAction.java index f30d2a971b16..21696aa98e16 100644 --- a/platform/lang-impl/src/com/intellij/ide/fileTemplates/actions/CreateFromTemplateAction.java +++ b/platform/lang-impl/src/com/intellij/ide/fileTemplates/actions/CreateFromTemplateAction.java @@ -18,12 +18,10 @@ package com.intellij.ide.fileTemplates.actions; import com.intellij.ide.fileTemplates.FileTemplate; import com.intellij.ide.fileTemplates.FileTemplateUtil; -import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.Presentation; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiDirectory; -import org.jetbrains.annotations.Nullable; public class CreateFromTemplateAction extends CreateFromTemplateActionBase { @@ -34,12 +32,6 @@ public class CreateFromTemplateAction extends CreateFromTemplateActionBase { myTemplate = template; } - @Override - @Nullable - protected AnAction getReplacedAction(final FileTemplate template) { - return null; - } - @Override protected FileTemplate getTemplate(final Project project, final PsiDirectory dir) { return myTemplate; diff --git a/platform/lang-impl/src/com/intellij/ide/fileTemplates/actions/CreateFromTemplateActionBase.java b/platform/lang-impl/src/com/intellij/ide/fileTemplates/actions/CreateFromTemplateActionBase.java index 64f3751a5f22..1a24357a5834 100644 --- a/platform/lang-impl/src/com/intellij/ide/fileTemplates/actions/CreateFromTemplateActionBase.java +++ b/platform/lang-impl/src/com/intellij/ide/fileTemplates/actions/CreateFromTemplateActionBase.java @@ -16,15 +16,24 @@ package com.intellij.ide.fileTemplates.actions; +import com.intellij.codeInsight.template.TemplateManager; +import com.intellij.codeInsight.template.impl.TemplateImpl; import com.intellij.ide.IdeView; import com.intellij.ide.fileTemplates.FileTemplate; import com.intellij.ide.fileTemplates.FileTemplateManager; import com.intellij.ide.fileTemplates.ui.CreateFromTemplateDialog; import com.intellij.ide.util.DirectoryChooserUtil; -import com.intellij.openapi.actionSystem.*; +import com.intellij.ide.util.EditorHelper; +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.actionSystem.LangDataKeys; +import com.intellij.openapi.command.WriteCommandAction; +import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiDirectory; import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; import org.jetbrains.annotations.Nullable; import javax.swing.*; @@ -48,7 +57,7 @@ public abstract class CreateFromTemplateActionBase extends AnAction { Project project = dir.getProject(); FileTemplate selectedTemplate = getTemplate(project, dir); - if(selectedTemplate != null){ + if (selectedTemplate != null){ AnAction action = getReplacedAction(selectedTemplate); if (action != null) { action.actionPerformed(e); @@ -62,18 +71,39 @@ public abstract class CreateFromTemplateActionBase extends AnAction { if (createdElement != null) { elementCreated(dialog, createdElement); view.selectElement(createdElement); + if (selectedTemplate.isHasEmbeddedLiveTemplate() && createdElement instanceof PsiFile) { + startLiveTemplate((PsiFile)createdElement); + } } } } } + private static void startLiveTemplate(PsiFile file) { + Project project = file.getProject(); + final Editor editor = EditorHelper.openInEditor(file); + if (editor == null) return; + + final TemplateImpl template = new TemplateImpl("", file.getText(), ""); + template.setInline(true); + WriteCommandAction.runWriteCommandAction(project, new Runnable() { + @Override + public void run() { + editor.getDocument().setText(template.getTemplateText()); + } + }); + TemplateManager.getInstance(project).startTemplate(editor, template); + } + @Nullable protected PsiDirectory getTargetDirectory(DataContext dataContext, IdeView view) { return DirectoryChooserUtil.getOrChooseDirectory(view); } @Nullable - protected abstract AnAction getReplacedAction(final FileTemplate selectedTemplate); + protected AnAction getReplacedAction(final FileTemplate selectedTemplate) { + return null; + } protected abstract FileTemplate getTemplate(final Project project, final PsiDirectory dir); 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 6662bd0a4d65..ed0254f83bd2 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 @@ -39,6 +39,7 @@ public abstract class FileTemplateBase implements FileTemplate { @Nullable private String myText; private boolean myShouldReformatCode = DEFAULT_REFORMAT_CODE_VALUE; + private boolean myHasEmbeddedLiveTemplate; @Override public final boolean isReformatCode() { @@ -113,4 +114,14 @@ public abstract class FileTemplateBase implements FileTemplate { public boolean isTemplateOfType(@NotNull final FileType fType) { return fType.equals(FileTypeManagerEx.getInstanceEx().getFileTypeByExtension(getExtension())); } + + @Override + public boolean isHasEmbeddedLiveTemplate() { + return myHasEmbeddedLiveTemplate; + } + + @Override + public void setHasEmbeddedLiveTemplate(boolean hasEmbeddedLiveTemplate) { + myHasEmbeddedLiveTemplate = hasEmbeddedLiveTemplate; + } } 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 8eec7b714cec..d932bffe37e8 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 @@ -29,6 +29,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.Computable; +import com.intellij.openapi.util.Disposer; import com.intellij.openapi.wm.ex.IdeFocusTraversalPolicy; import com.intellij.psi.PsiDirectory; import com.intellij.psi.PsiElement; @@ -90,6 +91,11 @@ public class CreateFromTemplateDialog extends DialogWrapper { } public PsiElement create(){ + if (ApplicationManager.getApplication().isUnitTestMode()) { + doCreate(myTemplate.getName() + "." + myTemplate.getExtension()); + Disposer.dispose(getDisposable()); + return myCreatedElement; + } if (myAttrPanel != null) { if (myAttrPanel.hasSomethingToAsk()) { show(); diff --git a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java index 6c2f074c322f..aa11d47f4b06 100644 --- a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java +++ b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java @@ -1610,7 +1610,6 @@ public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsig Editor editor = instance.openTextEditor(new OpenFileDescriptor(project, file), false); if (editor != null) { - editor.getCaretModel().moveToOffset(0); DaemonCodeAnalyzer.getInstance(getProject()).restart(); } return editor;