IDEA-89020 Disappears value of the variables standing next in Live templates

IDEA-121634 Live Template: template is broken with 3+ variables and leading space
This commit is contained in:
Alexander Zolotov
2014-03-06 21:06:28 +04:00
parent 31dbd88513
commit c738a20ef9
3 changed files with 73 additions and 20 deletions
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2013 JetBrains s.r.o.
* Copyright 2000-2014 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.
@@ -29,6 +29,7 @@ import com.intellij.openapi.command.WriteCommandAction
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.editor.impl.DocumentImpl
import com.intellij.openapi.util.Disposer
import com.intellij.openapi.util.text.StringUtil
import com.intellij.psi.PsiDocumentManager
import com.intellij.psi.codeStyle.CodeStyleSettingsManager
import com.intellij.psi.codeStyle.CommonCodeStyleSettings
@@ -74,15 +75,50 @@ public class LiveTemplateTest extends LightCodeInsightFixtureTestCase {
String group = "user";
final Template template = manager.createTemplate(templateName, group, templateText);
template.addVariable("ARG", "", "", false);
final TemplateContextType contextType =
ContainerUtil.findInstance(TemplateContextType.EP_NAME.getExtensions(), JavaCodeContextType.class);
TemplateContextType contextType = contextType(JavaCodeContextType.class);
((TemplateImpl)template).getTemplateContext().setEnabled(contextType, true);
addTemplate(template, testRootDisposable)
final Editor editor = getEditor();
manager.startTemplate(editor, (char)'\t');
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) {} } }")
}
public void testTemplateWithSegmentsAtTheSamePosition_3() {
doTestTemplateWithThreeVariables("", "DefaultValue", "", "class A { void test() { for(TestValue1DefaultValueTestValue3) {} } }")
}
private void doTestTemplateWithThreeVariables(String firstDefaultValue, String secondDefaultValue, String thirdDefaultValue,
String expectedText) {
configureFromFileText("dummy.java", "class A { void test() { <caret> } }")
TemplateManager manager = TemplateManager.getInstance(getProject())
def templateName = "tst_template"
def templateGroup = "user"
final Template template = manager.createTemplate(templateName, templateGroup, 'for($TEST1$$TEST2$$TEST3$) {}')
template.addVariable("TEST1", "", StringUtil.wrapWithDoubleQuote(firstDefaultValue), true)
template.addVariable("TEST2", "", StringUtil.wrapWithDoubleQuote(secondDefaultValue), true)
template.addVariable("TEST3", "", StringUtil.wrapWithDoubleQuote(thirdDefaultValue), true)
((TemplateImpl)template).templateContext.setEnabled(contextType(JavaCodeContextType.class), true)
addTemplate(template, testRootDisposable)
startTemplate(templateName, templateGroup)
if (firstDefaultValue.empty) myFixture.type("TestValue1")
myFixture.type("\t")
if (secondDefaultValue.empty) myFixture.type("TestValue2")
myFixture.type("\t")
if (thirdDefaultValue.empty) myFixture.type("TestValue3")
myFixture.type("\t")
assert state == null
checkResultByText(expectedText);
}
public void testTemplateWithArg1() throws IOException {
doTestTemplateWithArg("tst", 'wrap($ARG$)', "tst arg<caret>", "wrap(arg)");
@@ -245,6 +281,10 @@ class Foo {
TemplateManager.getInstance(getProject()).startTemplate(getEditor(), TemplateSettings.getInstance().getTemplate(name, group));
}
private static <T extends TemplateContextType> T contextType(Class<T> clazz) {
ContainerUtil.findInstance(TemplateContextType.EP_NAME.getExtensions(), clazz)
}
private void configure() {
myFixture.configureByFile(getTestName(false) + ".java");
}
@@ -549,8 +589,7 @@ class Foo {
public void testTemplateExpandingWithSelection() {
final TemplateManager manager = TemplateManager.getInstance(getProject());
final Template template = manager.createTemplate("tpl", "user", 'expanded');
final JavaStringContextType contextType =
ContainerUtil.findInstance(TemplateContextType.EP_NAME.getExtensions(), JavaStringContextType.class);
final JavaStringContextType contextType = contextType(JavaStringContextType.class);
((TemplateImpl)template).getTemplateContext().setEnabled(contextType, true);
myFixture.configureByText("a.java", "class A { void f() { Stri<selection>ng s = \"tpl</selection><caret>\"; } }")
@@ -750,4 +789,4 @@ class Foo {
}
"""
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2014 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.
@@ -73,12 +73,19 @@ public class TemplateSegments {
}
public void replaceSegmentAt(int index, int start, int end) {
replaceSegmentAt(index, start, end, false);
}
public void replaceSegmentAt(int index, int start, int end, boolean preserveGreediness) {
RangeMarker rangeMarker = mySegments.get(index);
boolean greedyToLeft = rangeMarker.isGreedyToLeft();
boolean greedyToRight = rangeMarker.isGreedyToRight();
rangeMarker.dispose();
Document doc = myEditor.getDocument();
rangeMarker = doc.createRangeMarker(start, end);
rangeMarker.setGreedyToLeft(true);
rangeMarker.setGreedyToRight(true);
rangeMarker.setGreedyToLeft(greedyToLeft || !preserveGreediness);
rangeMarker.setGreedyToRight(greedyToRight || !preserveGreediness);
mySegments.set(index, rangeMarker);
}
@@ -631,6 +631,8 @@ public class TemplateState implements Disposable {
}
}
fixOverlappedSegments(myCurrentSegmentNumber);
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
@@ -682,6 +684,19 @@ public class TemplateState implements Disposable {
});
}
private void fixOverlappedSegments(int currentSegment) {
if (currentSegment >= 0) {
int currentSegmentStart = mySegments.getSegmentStart(currentSegment);
int currentSegmentEnd = mySegments.getSegmentEnd(currentSegment);
for (int i = currentSegment + 1; i < mySegments.getSegmentsCount(); i++) {
final int startOffset = mySegments.getSegmentStart(i);
if (currentSegmentStart <= startOffset && startOffset < currentSegmentEnd) {
mySegments.replaceSegmentAt(i, currentSegmentEnd, Math.max(mySegments.getSegmentEnd(i), currentSegmentEnd), true);
}
}
}
}
@NotNull
private String getVariableValueText(String variableName) {
TextResult value = getVariableValue(variableName);
@@ -726,18 +741,13 @@ public class TemplateState implements Disposable {
String oldText = myDocument.getCharsSequence().subSequence(start, end).toString();
if (!oldText.equals(newValue)) {
int segmentNumberWithTheSameStart = mySegments.getSegmentWithTheSameStart(segmentNumber, start);
mySegments.setNeighboursGreedy(segmentNumber, false);
myDocument.replaceString(start, end, newValue);
int newEnd = start + newValue.length();
mySegments.replaceSegmentAt(segmentNumber, start, newEnd);
mySegments.setNeighboursGreedy(segmentNumber, true);
if (segmentNumberWithTheSameStart != -1) {
mySegments.replaceSegmentAt(segmentNumberWithTheSameStart, newEnd,
newEnd + mySegments.getSegmentEnd(segmentNumberWithTheSameStart) -
mySegments.getSegmentStart(segmentNumberWithTheSameStart));
}
fixOverlappedSegments(segmentNumber);
}
}
@@ -998,10 +1008,7 @@ public class TemplateState implements Disposable {
if (e instanceof MacroCallNode) {
marker = ((MacroCallNode)e).getMacro().getDefaultValue();
}
int start = mySegments.getSegmentStart(i);
int end = start + marker.length();
myDocument.insertString(start, marker);
mySegments.replaceSegmentAt(i, start, end);
replaceString(marker, mySegments.getSegmentStart(i), mySegments.getSegmentEnd(i), i);
indices.add(i);
break;
}