diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/template/LiveTemplateTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/template/LiveTemplateTest.groovy index 6abd2e809cdd..5b2ff9d54ff0 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/template/LiveTemplateTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/template/LiveTemplateTest.groovy @@ -67,9 +67,9 @@ public class LiveTemplateTest extends LightCodeInsightFixtureTestCase { } private void doTestTemplateWithArg(@NotNull String templateName, - @NotNull String templateText, - @NotNull String fileText, - @NotNull String expected) throws IOException { + @NotNull String templateText, + @NotNull String fileText, + @NotNull String expected) throws IOException { configureFromFileText("dummy.java", fileText); final TemplateManager manager = TemplateManager.getInstance(getProject()); String group = "user"; @@ -83,11 +83,11 @@ public class LiveTemplateTest extends LightCodeInsightFixtureTestCase { UIUtil.dispatchAllInvocationEvents() checkResultByText(expected); } - + public void testTemplateWithSegmentsAtTheSamePosition_1() { doTestTemplateWithThreeVariables("", "", "", "class A { void test() { for(TestValue1TestValue2TestValue3) {} } }") } - + public void testTemplateWithSegmentsAtTheSamePosition_2() { doTestTemplateWithThreeVariables("Def1", "Def2", "DefaultValue", "class A { void test() { for(Def1Def2DefaultValue) {} } }") } @@ -142,7 +142,6 @@ public class LiveTemplateTest extends LightCodeInsightFixtureTestCase { startTemplate(template); checkResultByText(""); - } public void testTemplateWithEnd() throws Exception { @@ -276,6 +275,11 @@ class Foo { state.gotoEnd(); checkResult(); } + + def startTemplate(String name, char expandKey) { + myFixture.type(name) + myFixture.type(expandKey) + } def startTemplate(String name, String group) { startTemplate(TemplateSettings.getInstance().getTemplate(name, group)); @@ -448,10 +452,14 @@ class Foo { public void testOtherContext() throws IOException { configureFromFileText("a.java", "class Foo { xxx }"); - assertInstanceOf(assertOneElement(TemplateManagerImpl.getApplicableContextTypes(myFixture.getFile(), getEditor().getCaretModel().getOffset())), JavaCodeContextType.Declaration.class); + assertInstanceOf( + assertOneElement(TemplateManagerImpl.getApplicableContextTypes(myFixture.getFile(), getEditor().getCaretModel().getOffset())), + JavaCodeContextType.Declaration.class); configureFromFileText("a.txt", "class Foo { xxx }"); - assertInstanceOf(assertOneElement(TemplateManagerImpl.getApplicableContextTypes(myFixture.getFile(), getEditor().getCaretModel().getOffset())), EverywhereContextType.class); + assertInstanceOf( + assertOneElement(TemplateManagerImpl.getApplicableContextTypes(myFixture.getFile(), getEditor().getCaretModel().getOffset())), + EverywhereContextType.class); } private boolean isApplicable(String text, TemplateImpl inst) throws IOException { @@ -461,7 +469,7 @@ class Foo { @Override protected void invokeTestRunnable(@NotNull final Runnable runnable) throws Exception { - if (name in ["testNavigationActionsDontTerminateTemplate", "testTemplateWithEnd", "testDisappearingVar", + if (name in ["testNavigationActionsDontTerminateTemplate", "testTemplateWithEnd", "testDisappearingVar", "test escape string characters in soutv", "test do not replace macro value with empty result"]) { runnable.run(); return; @@ -661,12 +669,12 @@ class Foo { } } ''' - + final TemplateManager manager = TemplateManager.getInstance(getProject()); final Template template = manager.createTemplate("result", "user", '$T$ result;'); template.addVariable('T', new MacroCallNode(new MethodReturnTypeMacro()), new EmptyNode(), false) template.toReformat = true - + startTemplate(template); assert myFixture.editor.document.text.contains('List> result;') } @@ -708,11 +716,11 @@ class Foo { public void "test stop at SELECTION when invoked surround template by tab"() { myFixture.configureByText "a.txt", "" - + final TemplateManager manager = TemplateManager.getInstance(getProject()); final Template template = manager.createTemplate("xxx", "user", 'foo $ARG$ bar $END$ goo $SELECTION$ after'); template.addVariable("ARG", "", "", true); - + startTemplate(template); myFixture.type('arg') state.nextTab() @@ -749,7 +757,6 @@ class Foo { } } """ - } public void "test snakeCase should convert hyphens to underscores"() { @@ -838,7 +845,7 @@ class Foo { template.addVariable("VAR2", new MacroCallNode(new FileNameMacro()), new ConstantNode("default"), true) ((TemplateImpl)template).templateContext.setEnabled(contextType(JavaCodeContextType.class), true) addTemplate(template, testRootDisposable) - + startTemplate(template); myFixture.checkResult """\ class Foo { @@ -848,7 +855,7 @@ class Foo { } """ myFixture.type 'test' - + myFixture.checkResult """\ class Foo { { @@ -857,4 +864,97 @@ class Foo { } """ } + + public void "test multicaret expanding with space"() { + myFixture.configureByText "a.java", """\ +class Foo { + { + + + + } +} +""" + def defaultShortcutChar = TemplateSettings.instance.defaultShortcutChar + try { + TemplateSettings.instance.defaultShortcutChar = TemplateSettings.SPACE_CHAR + startTemplate("sout", TemplateSettings.SPACE_CHAR) + } + finally { + TemplateSettings.instance.defaultShortcutChar = defaultShortcutChar + } + myFixture.checkResult("""\ +class Foo { + { + System.out.println(); + sout + System.out.println(); + } +} +""") + + } + + public void "test multicaret expanding with enter"() { + myFixture.configureByText "a.java", """\ +class Foo { + { + + + + } +} +""" + def defaultShortcutChar = TemplateSettings.instance.defaultShortcutChar + try { + TemplateSettings.instance.defaultShortcutChar = TemplateSettings.ENTER_CHAR + startTemplate("sout", TemplateSettings.ENTER_CHAR) + } + finally { + TemplateSettings.instance.defaultShortcutChar = defaultShortcutChar + } + myFixture.checkResult("""\ +class Foo { + { + System.out.println(); + sout + + System.out.println(); + } +} +""") + + } + + public void "test multicaret expanding with tab"() { + myFixture.configureByText "a.java", """\ +class Foo { + { + + + + } +} +""" + def defaultShortcutChar = TemplateSettings.instance.defaultShortcutChar + try { + TemplateSettings.instance.defaultShortcutChar = TemplateSettings.TAB_CHAR + startTemplate("sout", TemplateSettings.TAB_CHAR) + } + finally { + TemplateSettings.instance.defaultShortcutChar = defaultShortcutChar + } + + myFixture.checkResult("""\ +class Foo { + { + System.out.println(); + sout + System.out.println(); + } +} +""") + } + + } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateManagerImpl.java b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateManagerImpl.java index e0b89d73fae0..68e6ad3b808c 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateManagerImpl.java @@ -270,13 +270,14 @@ public class TemplateManagerImpl extends TemplateManager implements Disposable { continue; } if (isApplicable(customLiveTemplate, editor, file)) { - PsiDocumentManager.getInstance(myProject).commitAllDocuments(); + final Document document = editor.getDocument(); + PsiDocumentManager.getInstance(myProject).commitDocument(document); final CustomTemplateCallback callback = new CustomTemplateCallback(editor, file); final String key = customLiveTemplate.computeTemplateKey(callback); if (key != null) { int caretOffset = editor.getCaretModel().getOffset(); int offsetBeforeKey = caretOffset - key.length(); - CharSequence text = editor.getDocument().getCharsSequence(); + CharSequence text = document.getImmutableCharSequence(); if (template2argument == null || !containsTemplateStartingBefore(template2argument, offsetBeforeKey, caretOffset, text)) { return new Runnable() { @Override diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/editorActions/EnterHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/editorActions/EnterHandler.java index de503d125f30..93afd86cc825 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/editorActions/EnterHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/editorActions/EnterHandler.java @@ -17,15 +17,12 @@ package com.intellij.codeInsight.template.impl.editorActions; import com.intellij.codeInsight.editorActions.BaseEnterHandler; import com.intellij.codeInsight.template.TemplateManager; -import com.intellij.codeInsight.template.impl.TemplateManagerImpl; import com.intellij.codeInsight.template.impl.TemplateSettings; -import com.intellij.openapi.actionSystem.CommonDataKeys; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.editor.Caret; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.actionSystem.EditorActionHandler; import com.intellij.openapi.project.Project; -import com.intellij.psi.PsiDocumentManager; import org.jetbrains.annotations.NotNull; public class EnterHandler extends BaseEnterHandler { @@ -43,15 +40,13 @@ public class EnterHandler extends BaseEnterHandler { @Override public void executeWriteAction(Editor editor, Caret caret, DataContext dataContext) { - Project project = CommonDataKeys.PROJECT.getData(dataContext); - if (project != null) { - PsiDocumentManager.getInstance(project).commitDocument(editor.getDocument()); - TemplateManagerImpl templateManager = (TemplateManagerImpl)TemplateManager.getInstance(project); - if (templateManager != null && templateManager.startTemplate(editor, TemplateSettings.ENTER_CHAR)) { - return; - } + final Project project = editor.getProject(); + if (project != null && TemplateManager.getInstance(project).startTemplate(editor, TemplateSettings.ENTER_CHAR)) { + return; } - myOriginalHandler.execute(editor, caret, dataContext); + if (myOriginalHandler != null) { + myOriginalHandler.execute(editor, caret, dataContext); + } } } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/editorActions/ExpandLiveTemplateCustomAction.java b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/editorActions/ExpandLiveTemplateCustomAction.java index 745d267225b5..44f138f2229a 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/editorActions/ExpandLiveTemplateCustomAction.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/editorActions/ExpandLiveTemplateCustomAction.java @@ -24,7 +24,6 @@ import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.actionSystem.EditorAction; import com.intellij.openapi.editor.actionSystem.EditorWriteActionHandler; import com.intellij.openapi.project.Project; -import com.intellij.psi.PsiDocumentManager; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -43,7 +42,6 @@ public class ExpandLiveTemplateCustomAction extends EditorAction { public void executeWriteAction(Editor editor, @Nullable Caret caret, DataContext dataContext) { Project project = editor.getProject(); assert project != null; - PsiDocumentManager.getInstance(project).commitDocument(editor.getDocument()); TemplateManager.getInstance(project).startTemplate(editor, shortcutChar); } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/editorActions/SpaceHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/editorActions/SpaceHandler.java index 0cb84d5fb8f8..4b10297ef6e9 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/editorActions/SpaceHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/editorActions/SpaceHandler.java @@ -15,37 +15,21 @@ */ package com.intellij.codeInsight.template.impl.editorActions; +import com.intellij.codeInsight.editorActions.TypedHandlerDelegate; import com.intellij.codeInsight.template.TemplateManager; -import com.intellij.codeInsight.template.impl.TemplateManagerImpl; import com.intellij.codeInsight.template.impl.TemplateSettings; -import com.intellij.openapi.actionSystem.CommonDataKeys; -import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.editor.actionSystem.TypedActionHandler; +import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.project.Project; -import com.intellij.psi.PsiDocumentManager; -import org.jetbrains.annotations.NotNull; - -public class SpaceHandler extends TypedActionHandlerBase { - public SpaceHandler(TypedActionHandler originalHandler) { - super(originalHandler); - } +import com.intellij.psi.PsiFile; +public class SpaceHandler extends TypedHandlerDelegate { @Override - public void execute(@NotNull Editor editor, char charTyped, @NotNull DataContext dataContext) { - if (charTyped == ' ') { - Project project = CommonDataKeys.PROJECT.getData(dataContext); - if (project != null) { - PsiDocumentManager.getInstance(project).commitDocument(editor.getDocument()); - TemplateManagerImpl templateManager = (TemplateManagerImpl)TemplateManager.getInstance(project); - if (templateManager != null && templateManager.startTemplate(editor, TemplateSettings.SPACE_CHAR)) { - return; - } - } + public Result beforeCharTyped(char charTyped, Project project, Editor editor, PsiFile file, FileType fileType) { + if (charTyped == TemplateSettings.SPACE_CHAR && TemplateManager.getInstance(project).startTemplate(editor, TemplateSettings.SPACE_CHAR)) { + return Result.STOP; } - if (myOriginalHandler != null) { - myOriginalHandler.execute(editor, charTyped, dataContext); - } + return super.beforeCharTyped(charTyped, project, editor, file, fileType); } } diff --git a/platform/platform-resources/src/META-INF/LangExtensions.xml b/platform/platform-resources/src/META-INF/LangExtensions.xml index 9e029e12a6e7..8d6b02fb86d8 100644 --- a/platform/platform-resources/src/META-INF/LangExtensions.xml +++ b/platform/platform-resources/src/META-INF/LangExtensions.xml @@ -659,7 +659,7 @@ - +