diff --git a/platform/lang-impl/src/com/intellij/lang/LanguagePerFileMappings.java b/platform/lang-impl/src/com/intellij/lang/LanguagePerFileMappings.java index dfad1a0e4611..7c0d999d6e97 100644 --- a/platform/lang-impl/src/com/intellij/lang/LanguagePerFileMappings.java +++ b/platform/lang-impl/src/com/intellij/lang/LanguagePerFileMappings.java @@ -145,7 +145,8 @@ public abstract class LanguagePerFileMappings implements PersistentStateCompo } protected abstract List getAvailableValues(); - + + @Nullable protected abstract String serialize(T t); public Element getState() { @@ -161,10 +162,13 @@ public abstract class LanguagePerFileMappings implements PersistentStateCompo }); for (VirtualFile file : files) { final T dialect = myMappings.get(file); - final Element child = new Element("file"); - element.addContent(child); - child.setAttribute("url", file == null ? "PROJECT" : file.getUrl()); - child.setAttribute(getValueAttribute(), serialize(dialect)); + String value = serialize(dialect); + if (value != null) { + final Element child = new Element("file"); + element.addContent(child); + child.setAttribute("url", file == null ? "PROJECT" : file.getUrl()); + child.setAttribute(getValueAttribute(), value); + } } return element; } @@ -184,7 +188,10 @@ public abstract class LanguagePerFileMappings implements PersistentStateCompo synchronized (myMappings) { final THashMap dialectMap = new THashMap(); for (T dialect : getAvailableValues()) { - dialectMap.put(serialize(dialect), dialect); + String key = serialize(dialect); + if (key != null) { + dialectMap.put(key, dialect); + } } final List files = state.getChildren("file"); for (Element fileElement : files) { diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/TextChangesStorage.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/TextChangesStorage.java index 9fb79784d6a9..d2dd97bbdecd 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/TextChangesStorage.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/TextChangesStorage.java @@ -162,7 +162,10 @@ public class TextChangesStorage { int newChangeStart = change.getStart(); int newChangeEnd = change.getEnd(); int storedChangeStart = getChangeIndex(change.getStart()); - int clientShift = 0; + int clientShift = 0; // 'Client text' shift before the given change to store. I.e. this value can be subtracted from the + // given change's start/end offsets in order to get original document range affected by the given change. + int changeDiff = change.getText().length() - (change.getEnd() - change.getStart()); + boolean updateClientOffsetOnly = false; if (storedChangeStart < 0) { storedChangeStart = -storedChangeStart - 1; @@ -171,9 +174,6 @@ public class TextChangesStorage { ChangeEntry changeEntry = myChanges.get(storedChangeStart - 1); clientShift = changeEntry.clientStartOffset - changeEntry.change.getStart() + changeEntry.change.getDiff(); } - } - - if (storedChangeStart >= myChanges.size()) { myChanges.add(new ChangeEntry( new TextChangeImpl(change.getText(), change.getStart() - clientShift, change.getEnd() - clientShift), change.getStart() @@ -192,6 +192,21 @@ public class TextChangesStorage { CharSequence storedText = changeEntry.change.getText(); int storedClientEnd = storedClientStart + storedText.length(); + // Stored change lays after the new one. + if (!updateClientOffsetOnly && storedClientStart > newChangeEnd) { + if (changeDiff != 0) { + updateClientOffsetOnly = true; + } + else { + break; + } + } + + if (updateClientOffsetOnly) { + changeEntry.clientStartOffset += changeDiff; + continue; + } + // Stored change lays before the new one. if (storedClientEnd <= newChangeStart) { clientShift += changeEntry.change.getDiff(); @@ -199,9 +214,7 @@ public class TextChangesStorage { continue; } - // We know that given change and stored change have intersections if control flow reaches this place. - - // Check if given change target sub-range of the stored one + // Check if given change targets sub-range of the stored one. if (storedClientStart <= newChangeStart && storedClientEnd >= newChangeEnd) { StringBuilder adjustedText = new StringBuilder(); if (storedClientStart < newChangeStart) { @@ -215,13 +228,15 @@ public class TextChangesStorage { if (adjustedText.length() == 0 && changeEntry.change.getStart() == changeEntry.change.getEnd()) { myChanges.remove(i); insertionIndex = -1; - break; + updateClientOffsetOnly = true; + continue; } TextChangeImpl adjusted = new TextChangeImpl(adjustedText, changeEntry.change.getStart(), changeEntry.change.getEnd()); myChanges.set(i, new ChangeEntry(adjusted, adjusted.getStart())); insertionIndex = -1; - break; + updateClientOffsetOnly = true; + continue; } // Check if given change completely contains stored change range. @@ -234,7 +249,7 @@ public class TextChangesStorage { } // Check if given change intersects stored change range from the left. - if (newChangeStart <= storedClientStart && newChangeEnd < storedClientEnd) { + if (newChangeStart <= storedClientStart && newChangeEnd > storedClientStart) { int numberOfStoredChangeSymbolsToRemove = newChangeEnd - storedClientStart; CharSequence adjustedText = storedText.subSequence(numberOfStoredChangeSymbolsToRemove, storedText.length()); changeEntry.change = new TextChangeImpl(adjustedText, changeEntry.change.getStart(), changeEntry.change.getEnd()); @@ -244,7 +259,7 @@ public class TextChangesStorage { } // Check if given change intersects stored change range from the right. - if (newChangeStart < storedClientEnd && newChangeEnd > storedClientEnd) { + if (newChangeStart < storedClientEnd && newChangeEnd >= storedClientEnd) { CharSequence adjustedText = storedText.subSequence(0, newChangeStart - storedClientStart); TextChangeImpl adjusted = new TextChangeImpl(adjustedText, changeEntry.change.getStart(), changeEntry.change.getEnd()); myChanges.set(i, new ChangeEntry(adjusted, adjusted.getStart())); diff --git a/platform/platform-impl/testSrc/com/intellij/openapi/editor/impl/TextChangesStorageTest.java b/platform/platform-impl/testSrc/com/intellij/openapi/editor/impl/TextChangesStorageTest.java index ecf250f536da..fb4b164b0e4f 100644 --- a/platform/platform-impl/testSrc/com/intellij/openapi/editor/impl/TextChangesStorageTest.java +++ b/platform/platform-impl/testSrc/com/intellij/openapi/editor/impl/TextChangesStorageTest.java @@ -64,6 +64,13 @@ public class TextChangesStorageTest { checkChanges(c("abc", 2), c("def", 3), c("ghi", 5)); } + @Test + public void disconnectedInsertsFromTailToStart() { + insert("abc", 10); + insert("def", 1); + checkChanges(c("def", 1), c("abc", 10)); + } + @Test public void adjacentInserts() { insert("abc", 2); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/config/AbstractConfigUtils.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/config/AbstractConfigUtils.java index e4255329a795..a09ee1fd5b20 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/config/AbstractConfigUtils.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/config/AbstractConfigUtils.java @@ -23,7 +23,6 @@ import com.intellij.openapi.roots.libraries.LibraryTable; import com.intellij.openapi.util.Condition; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.ArrayUtil; -import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -83,8 +82,22 @@ public abstract class AbstractConfigUtils { */ @Nullable public static String getSDKJarVersion(String jarPath, final String jarRegex, String manifestPath) { + return getSDKJarVersion(jarPath, Pattern.compile(jarRegex), manifestPath); + } + + /** + * Return value of Implementation-Version attribute in jar manifest + *

+ * + * @param jarPath directory containing jar file + * @param jarPattern filename pattern for jar file + * @param manifestPath path to manifest file in jar file + * @return value of Implementation-Version attribute, null if not found + */ + @Nullable + public static String getSDKJarVersion(String jarPath, final Pattern jarPattern, String manifestPath) { try { - File[] jars = GroovyUtils.getFilesInDirectoryByPattern(jarPath, jarRegex); + File[] jars = GroovyUtils.getFilesInDirectoryByPattern(jarPath, jarPattern); if (jars.length != 1) { return null; } @@ -107,7 +120,7 @@ public abstract class AbstractConfigUtils { return version; } - final Matcher matcher = Pattern.compile(jarRegex).matcher(jars[0].getName()); + final Matcher matcher = jarPattern.matcher(jars[0].getName()); if (matcher.matches() && matcher.groupCount() == 1) { return matcher.group(1); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/debugger/GroovyHotSwapper.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/debugger/GroovyHotSwapper.java index d8085109a7bd..45223d715e30 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/debugger/GroovyHotSwapper.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/debugger/GroovyHotSwapper.java @@ -42,7 +42,7 @@ public class GroovyHotSwapper extends JavaProgramPatcher { return true; } } - return true; + return false; } private static boolean containsGroovyClasses(Project project) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/runner/GroovyRunConfigurationEditor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/runner/GroovyRunConfigurationEditor.java index f0178dea99f1..2467ed7b511b 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/runner/GroovyRunConfigurationEditor.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/runner/GroovyRunConfigurationEditor.java @@ -23,7 +23,9 @@ import com.intellij.openapi.fileChooser.FileChooserDescriptor; import com.intellij.openapi.module.Module; import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.options.SettingsEditor; +import com.intellij.openapi.roots.ui.configuration.ModulesAlphaComparator; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.ui.ComboboxSpeedSearch; import com.intellij.ui.FieldPanel; import com.intellij.ui.RawCommandLineEditor; import org.jetbrains.annotations.NotNull; @@ -31,6 +33,8 @@ import org.jetbrains.plugins.groovy.GroovyFileType; import javax.swing.*; import java.awt.*; +import java.util.*; +import java.util.List; public class GroovyRunConfigurationEditor extends SettingsEditor { private DefaultComboBoxModel myModulesModel; @@ -84,7 +88,9 @@ public class GroovyRunConfigurationEditor extends SettingsEditor modules = new ArrayList(configuration.getValidModules()); + Collections.sort(modules, ModulesAlphaComparator.INSTANCE); + for (Module module : modules) { myModulesModel.addElement(module); } myModulesModel.setSelectedItem(configuration.getModule()); @@ -118,6 +124,12 @@ public class GroovyRunConfigurationEditor extends SettingsEditor(tag, new XmlEnclosingTagUnwrapper())); } tag = PsiTreeUtil.getParentOfType(tag, XmlTag.class);