Merge remote-tracking branch 'origin/master'

This commit is contained in:
Ilya.Kazakevich
2014-05-06 16:34:07 +04:00
91 changed files with 1969 additions and 905 deletions
@@ -53,6 +53,8 @@ import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.packaging.artifacts.Artifact;
import com.intellij.packaging.impl.artifacts.ArtifactBySourceFileFinder;
import com.intellij.util.ArrayUtil;
import com.intellij.util.messages.MessageBusConnection;
import org.apache.oro.text.regex.*;
@@ -978,7 +980,15 @@ public class CompilerConfigurationImpl extends CompilerConfiguration implements
}
return extensionsString.toString();
}
public boolean isCompilableResourceFile(final Project project, final VirtualFile file) {
if (!isResourceFile(file)) {
return false;
}
final Collection<? extends Artifact> artifacts = ArtifactBySourceFileFinder.getInstance(project).findArtifacts(file);
return artifacts.isEmpty();
}
private static class CompiledPattern {
@NotNull final Pattern fileName;
@Nullable final Pattern dir;
@@ -26,14 +26,11 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ProjectFileIndex;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.packaging.artifacts.Artifact;
import com.intellij.packaging.impl.artifacts.ArtifactBySourceFileFinder;
import com.intellij.psi.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public class CompileAction extends CompileActionBase {
@@ -108,7 +105,8 @@ public class CompileAction extends CompileActionBase {
else if (files.length == 1) {
final VirtualFile file = files[0];
FileType fileType = file.getFileType();
if (CompilerManager.getInstance(project).isCompilableFileType(fileType) || isCompilableResourceFile(project, compilerConfiguration, file)) {
if (CompilerManager.getInstance(project).isCompilableFileType(fileType) || compilerConfiguration
.isCompilableResourceFile(project, file)) {
elementDescription = "'" + file.getName() + "'";
}
else {
@@ -135,7 +133,7 @@ public class CompileAction extends CompileActionBase {
}
private static String createPresentationText(String elementDescription) {
StringBuffer buffer = new StringBuffer(40);
StringBuilder buffer = new StringBuilder(40);
buffer.append(ActionsBundle.actionText(IdeActions.ACTION_COMPILE)).append(" ");
int length = elementDescription.length();
if (length > 23) {
@@ -175,20 +173,12 @@ public class CompileAction extends CompileActionBase {
}
else {
FileType fileType = file.getFileType();
if (!(compilerManager.isCompilableFileType(fileType) || isCompilableResourceFile(project, compilerConfiguration, file))) {
if (!(compilerManager.isCompilableFileType(fileType) || compilerConfiguration.isCompilableResourceFile(project, file))) {
continue;
}
}
filesToCompile.add(file);
}
return VfsUtil.toVirtualFileArray(filesToCompile);
}
private static boolean isCompilableResourceFile(final Project project, final CompilerConfiguration compilerConfiguration, final VirtualFile file) {
if (!compilerConfiguration.isResourceFile(file)) {
return false;
}
final Collection<? extends Artifact> artifacts = ArtifactBySourceFileFinder.getInstance(project).findArtifacts(file);
return artifacts.isEmpty();
return VfsUtilCore.toVirtualFileArray(filesToCompile);
}
}
@@ -198,14 +198,15 @@ public class CompilerTask extends Task.Backgroundable {
ApplicationManager.getApplication().invokeLater(new Runnable() {
public void run() {
if (myProject.isDisposed()) {
final Project project = myProject;
if (project == null || project.isDisposed()) {
return;
}
synchronized (myMessageViewLock) {
// clear messages from the previous compilation
if (myErrorTreeView == null) {
// if message view != null, the contents has already been cleared
removeAllContents(myProject, null);
removeAllContents(project, null);
}
}
}
@@ -454,7 +455,12 @@ public class CompilerTask extends Task.Backgroundable {
if (content == notRemove) {
continue;
}
if (CONTENT_ID_KEY.get(content) == myContentId || SESSION_ID_KEY.get(content) != mySessionId) { // the content was added by previous compilation
boolean toRemove = CONTENT_ID_KEY.get(content) == myContentId;
if (!toRemove) {
final Object contentSessionId = SESSION_ID_KEY.get(content);
toRemove = contentSessionId != null && contentSessionId != mySessionId; // the content was added by previous compilation
}
if (toRemove) {
messageView.getContentManager().removeContent(content, true);
}
}
@@ -54,6 +54,8 @@ public abstract class CompilerConfiguration {
public abstract boolean isResourceFile(String path);
public abstract boolean isCompilableResourceFile(Project project, VirtualFile file);
public abstract void addResourceFilePattern(String namePattern) throws MalformedPatternException;
public abstract boolean isAddNotNullAssertions();
@@ -124,19 +124,7 @@ public abstract class OrderEntryFix implements IntentionAction, LocalQuickFix {
final VirtualFile location = PsiUtilCore.getVirtualFile(reference != null ? reference.getElement() : null);
boolean inTests = location != null && ModuleRootManager.getInstance(currentModule).getFileIndex().isInTestSourceContent(location);
try {
final String[] junit4Paths = {JavaSdkUtil.getJunit4JarPath(),
PathUtil.getJarPathForClass(Class.forName("org.hamcrest.Matcher")),
PathUtil.getJarPathForClass(Class.forName("org.hamcrest.Matchers"))};
ModuleRootModificationUtil.addModuleLibrary(currentModule,
"JUnit4",
ContainerUtil.map(junit4Paths,
new Function<String, String>() {
@Override
public String fun(String libPath) {
return convertToLibraryRoot(libPath).getUrl();
}
}),
Collections.<String>emptyList(), inTests ? DependencyScope.TEST : DependencyScope.COMPILE);
addJUnit4Library(inTests, currentModule);
final GlobalSearchScope scope = GlobalSearchScope.moduleWithLibrariesScope(currentModule);
final PsiClass aClass = JavaPsiFacade.getInstance(project).findClass(className, scope);
if (aClass != null && editor != null && reference != null) {
@@ -276,6 +264,22 @@ public abstract class OrderEntryFix implements IntentionAction, LocalQuickFix {
return result;
}
public static void addJUnit4Library(boolean inTests, Module currentModule) throws ClassNotFoundException {
final String[] junit4Paths = {JavaSdkUtil.getJunit4JarPath(),
PathUtil.getJarPathForClass(Class.forName("org.hamcrest.Matcher")),
PathUtil.getJarPathForClass(Class.forName("org.hamcrest.Matchers"))};
ModuleRootModificationUtil.addModuleLibrary(currentModule,
"JUnit4",
ContainerUtil.map(junit4Paths,
new Function<String, String>() {
@Override
public String fun(String libPath) {
return convertToLibraryRoot(libPath).getUrl();
}
}),
Collections.<String>emptyList(), inTests ? DependencyScope.TEST : DependencyScope.COMPILE);
}
private static List<PsiClass> filterAllowedDependencies(PsiElement element, PsiClass[] classes) {
DependencyValidationManager dependencyValidationManager = DependencyValidationManager.getInstance(element.getProject());
PsiFile fromFile = element.getContainingFile();
@@ -15,6 +15,7 @@
*/
package com.intellij.testIntegration;
import com.intellij.codeInsight.daemon.impl.quickfix.OrderEntryFix;
import com.intellij.ide.fileTemplates.FileTemplate;
import com.intellij.ide.fileTemplates.FileTemplateDescriptor;
import com.intellij.ide.fileTemplates.FileTemplateManager;
@@ -119,4 +120,8 @@ public abstract class JavaTestFramework implements TestFramework {
public FileTemplateDescriptor getTestClassFileTemplateDescriptor() {
return null;
}
public void setupLibrary(Module module) {
OrderEntryFix.addJarToRoots(getLibraryPath(), module, null);
}
}
@@ -126,10 +126,7 @@ public class CreateTestDialog extends DialogWrapper {
for (final TestFramework descriptor : Extensions.getExtensions(TestFramework.EXTENSION_NAME)) {
final JRadioButton b = new JRadioButton(descriptor.getName());
if (descriptor instanceof JavaTestFramework) {
final char mnemonic = ((JavaTestFramework)descriptor).getMnemonic();
if (mnemonic > -1) {
b.setMnemonic(mnemonic);
}
b.setMnemonic(((JavaTestFramework)descriptor).getMnemonic());
}
myLibraryButtons.add(b);
group.add(b);
@@ -173,7 +170,11 @@ public class CreateTestDialog extends DialogWrapper {
public void actionPerformed(ActionEvent e) {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
public void run() {
OrderEntryFix.addJarToRoots(mySelectedFramework.getLibraryPath(), myTargetModule, null);
if (mySelectedFramework instanceof JavaTestFramework) {
((JavaTestFramework)mySelectedFramework).setupLibrary(myTargetModule);
} else {
OrderEntryFix.addJarToRoots(mySelectedFramework.getLibraryPath(), myTargetModule, null);
}
}
});
myFixLibraryPanel.setVisible(false);
@@ -97,8 +97,8 @@ public abstract class AbstractLayoutCodeProcessorTest extends PsiTestCase {
@Override
public void tearDown() throws Exception {
super.tearDown();
delete(myWorkingDirectory.getVirtualFile());
super.tearDown();
}
@NotNull
@@ -277,45 +277,6 @@ public abstract class AbstractLayoutCodeProcessorTest extends PsiTestCase {
PsiTestUtil.addSourceRoot(module, src.getVirtualFile());
return module;
}
class TestFileStructure {
private int myLevel;
@NotNull private PsiDirectory myRoot;
@NotNull private PsiDirectory myCurrentLevelDirectory;
private List<List<PsiFile>> myFilesForLevel = new ArrayList<List<PsiFile>>();
TestFileStructure(@NotNull PsiDirectory root) {
myRoot = root;
myCurrentLevelDirectory = root;
myFilesForLevel.add(new ArrayList<PsiFile>());
myLevel = 0;
}
TestFileStructure addTestFilesToCurrentDirectory(String[] names) throws IOException {
getFilesAtLevel(myLevel).addAll(createTestFiles(myCurrentLevelDirectory, names));
return this;
}
TestFileStructure createDirectoryAndMakeItCurrent(String name) {
myLevel++;
myFilesForLevel.add(new ArrayList<PsiFile>());
myCurrentLevelDirectory = createDirectory(myCurrentLevelDirectory.getVirtualFile(), name);
return this;
}
List<PsiFile> getFilesAtLevel(int level) {
assert (myLevel >= level);
return myFilesForLevel.get(level);
}
List<PsiFile> getAllFiles() {
List<PsiFile> all = new ArrayList<PsiFile>();
for (List<PsiFile> files: myFilesForLevel) {
all.addAll(files);
}
return all;
}
}
}
@@ -32,14 +32,6 @@ public class ReformatCodeActionTest extends AbstractLayoutCodeProcessorTest {
private static String[] classNames = {"Vasya", "Main", "Oiie", "Ololo"};
private TestFileStructure getThreeLevelDirectoryStructure() throws IOException {
TestFileStructure fileStructure = new TestFileStructure(getTempRootDirectory());
fileStructure.createDirectoryAndMakeItCurrent("dir").addTestFilesToCurrentDirectory(classNames)
.createDirectoryAndMakeItCurrent("innerDir").addTestFilesToCurrentDirectory(classNames)
.createDirectoryAndMakeItCurrent("innerInnerDir").addTestFilesToCurrentDirectory(classNames);
return fileStructure;
}
public void testReformatAndOptimizeMultipleFiles() throws IOException {
List<PsiFile> files = createTestFiles(getTempRootDirectory(), classNames);
injectMockDialogFlags(new MockReformatFileSettings().setOptimizeImports(true));
@@ -118,4 +110,25 @@ public class ReformatCodeActionTest extends AbstractLayoutCodeProcessorTest {
checkFormationAndImportsOptimizationFor(files);
}
private TestFileStructure getThreeLevelDirectoryStructure() throws IOException {
TestFileStructure fileStructure = new TestFileStructure(getModule(), getTempRootDirectory());
fileStructure.createDirectoryAndMakeItCurrent("dir");
addFilesToCurrentDirectory(fileStructure);
fileStructure.createDirectoryAndMakeItCurrent("innerDir");
addFilesToCurrentDirectory(fileStructure);
fileStructure.createDirectoryAndMakeItCurrent("innerInnerDir");
addFilesToCurrentDirectory(fileStructure);
return fileStructure;
}
private void addFilesToCurrentDirectory(TestFileStructure fileStructure) throws IOException {
for (int i = 0; i < 5; i++) {
String className = "Test" + i;
fileStructure.addTestFile("Test" + i + ".java", getUntouchedJavaSourceForTotalProcessing(className));
}
}
}
@@ -49,7 +49,7 @@ public class DeprecationInspectionTest extends InspectionTestCase {
doTest();
}
public void testDeprecatedDefaultConstructorFromTypeParameter() throws Exception {
public void testDeprecatedDefaultConstructorTypeParameter() throws Exception {
doTest();
}
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
@@ -16,13 +16,12 @@
package com.intellij.psi.impl.source;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.CommonClassNames;
import com.intellij.util.CharTable;
import com.intellij.util.containers.OpenTHashSet;
import com.intellij.util.text.CharArrayUtil;
import com.intellij.util.text.CharSequenceHashingStrategy;
import com.intellij.util.text.CharSequenceSubSequence;
import com.intellij.util.text.StringFactory;
import gnu.trove.TIntObjectHashMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -34,55 +33,62 @@ import java.lang.reflect.Modifier;
*/
public class CharTableImpl implements CharTable {
private static final int INTERN_THRESHOLD = 40; // 40 or more characters long tokens won't be interned.
private static final CharSequenceHashingStrategy HASHER = CharSequenceHashingStrategy.CASE_SENSITIVE;
private static final OpenTHashSet<CharSequence> STATIC_ENTRIES = newStaticSet();
private final OpenTHashSet<CharSequence> entries = new OpenTHashSet<CharSequence>(10, 0.9f, HASHER);
private static final StringHashToCharSequencesMap STATIC_ENTRIES = newStaticSet();
private final StringHashToCharSequencesMap entries = new StringHashToCharSequencesMap(10, 0.9f);
@NotNull
@Override
public CharSequence intern(@NotNull final CharSequence text) {
if (text.length() > INTERN_THRESHOLD) return createSequence(text);
CharSequence result;
if (text.length() > INTERN_THRESHOLD) result = createSequence(text);
else result = doIntern(text);
return doIntern(text);
return result;
}
@NotNull
public CharSequence doIntern(@NotNull CharSequence text) {
CharSequence interned = getStaticInterned(text);
private CharSequence doIntern(@NotNull CharSequence text, int startOffset, int endOffset) {
int hashCode = subSequenceHashCode(text, startOffset, endOffset);
CharSequence interned = STATIC_ENTRIES.getSubSequenceWithHashCode(hashCode, text, startOffset, endOffset);
if (interned != null) {
return interned;
}
synchronized(entries) {
interned = entries.get(text);
if (interned != null) {
return interned;
}
// We need to create separate string just to prevent referencing all character data when original is string or char sequence over string
final CharSequence entry = createSequence(text);
boolean added = entries.add(entry);
assert added;
return entry;
return entries.getOrAddSubSequenceWithHashCode(hashCode, text, startOffset, endOffset);
}
}
@NotNull
public CharSequence doIntern(@NotNull CharSequence text) {
return doIntern(text, 0, text.length());
}
@NotNull
@Override
public CharSequence intern(@NotNull final CharSequence baseText, final int startOffset, final int endOffset) {
if (endOffset - startOffset == baseText.length()) return intern(baseText);
return intern(new CharSequenceSubSequence(baseText, startOffset, endOffset));
CharSequence result;
if (endOffset - startOffset == baseText.length()) result = intern(baseText);
else if (endOffset - startOffset > INTERN_THRESHOLD) result = createSequence(baseText, startOffset, endOffset);
else result = doIntern(baseText, startOffset, endOffset);
return result;
}
@NotNull
private static String createSequence(@NotNull CharSequence text) {
return createSequence(text, 0, text.length());
}
@NotNull
private static String createSequence(@NotNull CharSequence text, int startOffset, int endOffset) {
if (text instanceof String) {
return (String)text;
return ((String)text).substring(startOffset, endOffset);
}
char[] buf = new char[text.length()];
CharArrayUtil.getChars(text, buf, 0);
char[] buf = new char[endOffset - startOffset];
CharArrayUtil.getChars(text, buf, startOffset, 0, buf.length);
return StringFactory.createShared(buf); // this way the .toString() doesn't create another instance (as opposed to new CharArrayCharSequence())
}
@@ -96,9 +102,9 @@ public class CharTableImpl implements CharTable {
STATIC_ENTRIES.add(text);
}
}
private static OpenTHashSet<CharSequence> newStaticSet() {
final OpenTHashSet<CharSequence> r = new OpenTHashSet<CharSequence>(10, 0.9f, HASHER);
private static StringHashToCharSequencesMap newStaticSet() {
final StringHashToCharSequencesMap r = new StringHashToCharSequencesMap(10, 0.9f);
r.add("==" );
r.add("!=" );
r.add("||" );
@@ -214,4 +220,95 @@ public class CharTableImpl implements CharTable {
staticIntern(typeName);
}
}
private static class StringHashToCharSequencesMap extends TIntObjectHashMap<Object> {
StringHashToCharSequencesMap(int capacity, float loadFactor) {
super(capacity, loadFactor);
}
CharSequence get(CharSequence sequence, int startOffset, int endOffset) {
return getSubSequenceWithHashCode(subSequenceHashCode(sequence, startOffset, endOffset), sequence, startOffset, endOffset);
}
CharSequence getSubSequenceWithHashCode(int hashCode, CharSequence sequence, int startOffset, int endOffset) {
Object o = get(hashCode);
if (o == null) return null;
if (o instanceof CharSequence) {
if (charSequenceSubSequenceEquals((CharSequence)o, sequence, startOffset, endOffset)) {
return (CharSequence)o;
}
return null;
} else if (o instanceof CharSequence[]) {
for(CharSequence cs:(CharSequence[])o) {
if (charSequenceSubSequenceEquals(cs, sequence, startOffset, endOffset)) {
return cs;
}
}
} else {
assert false:o.getClass();
}
return null;
}
private static boolean charSequenceSubSequenceEquals(CharSequence cs, CharSequence baseSequence, int startOffset, int endOffset) {
if (cs.length() != endOffset - startOffset) return false;
if (cs == baseSequence && startOffset == 0) return true;
for(int i = 0, len = cs.length(); i < len; ++i) {
if (cs.charAt(i) != baseSequence.charAt(startOffset + i)) return false;
}
return true;
}
CharSequence get(CharSequence sequence) {
return get(sequence, 0, sequence.length());
}
CharSequence add(CharSequence sequence) {
return add(sequence, 0, sequence.length());
}
CharSequence add(CharSequence sequence, int startOffset, int endOffset) {
int hashCode = subSequenceHashCode(sequence, startOffset, endOffset);
return getOrAddSubSequenceWithHashCode(hashCode, sequence, startOffset, endOffset);
}
private CharSequence getOrAddSubSequenceWithHashCode(int hashCode, CharSequence sequence, int startOffset, int endOffset) {
int index = index(hashCode);
String addedSequence = null;
if (index < 0) {
put(hashCode, addedSequence = createSequence(sequence, startOffset, endOffset));
} else {
Object value = _values[index];
if (value instanceof CharSequence) {
CharSequence existingSequence = (CharSequence)value;
if (charSequenceSubSequenceEquals(existingSequence, sequence, startOffset, endOffset)) {
return existingSequence;
}
put(hashCode, new CharSequence[] {existingSequence, addedSequence = createSequence(sequence, startOffset, endOffset)});
} else if (value instanceof CharSequence[]) {
CharSequence[] existingSequenceArray = (CharSequence[])value;
for(CharSequence cs:existingSequenceArray) {
if (charSequenceSubSequenceEquals(cs, sequence, startOffset, endOffset)) {
return cs;
}
}
CharSequence[] newSequenceArray = new CharSequence[existingSequenceArray.length + 1];
System.arraycopy(existingSequenceArray, 0, newSequenceArray, 0, existingSequenceArray.length);
newSequenceArray[existingSequenceArray.length] = addedSequence = createSequence(sequence, startOffset, endOffset);
put(hashCode, newSequenceArray);
} else {
assert false:value.getClass();
}
}
return addedSequence;
}
}
private static int subSequenceHashCode(CharSequence sequence, int startOffset, int endOffset) {
if (startOffset == 0 && endOffset == sequence.length()) {
return StringUtil.stringHashCode(sequence);
}
return StringUtil.stringHashCode(sequence, startOffset, endOffset);
}
}
@@ -25,7 +25,6 @@ import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
@@ -34,18 +33,23 @@ import com.intellij.openapi.project.IndexNotReadyException;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectCoreUtil;
import com.intellij.openapi.roots.GeneratedSourcesFilter;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.ui.ex.MessagesEx;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.PsiBundle;
import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiFile;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.SequentialModalProgressTask;
import com.intellij.util.SequentialTask;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
@@ -205,7 +209,14 @@ public abstract class AbstractLayoutCodeProcessor {
return;
}
FileTreeIterator iterator = buildFileTreeIterator();
FileTreeIterator iterator;
if (myFiles != null) {
iterator = new FileTreeIterator(myFiles);
}
else {
iterator = myProcessChangedTextOnly ? buildChangedFilesIterator()
: buildFileTreeIterator();
}
runProcessFiles(iterator);
}
@@ -226,6 +237,35 @@ public abstract class AbstractLayoutCodeProcessor {
return new FileTreeIterator(Collections.<PsiFile>emptyList());
}
@NotNull
private FileTreeIterator buildChangedFilesIterator() {
List<PsiFile> files = getChangedFilesFromContext();
return new FileTreeIterator(files);
}
@NotNull
private List<PsiFile> getChangedFilesFromContext() {
List<PsiDirectory> dirs = getAllSearchableDirsFromContext();
return FormatChangedTextUtil.getChangedFilesFromDirs(myProject, dirs);
}
private List<PsiDirectory> getAllSearchableDirsFromContext() {
List<PsiDirectory> dirs = ContainerUtil.newArrayList();
if (myDirectory != null) {
dirs.add(myDirectory);
}
else if (myModule != null) {
List<PsiDirectory> allModuleDirs = FileTreeIterator.collectModuleDirectories(myModule);
dirs.addAll(allModuleDirs);
}
else if (myProject != null) {
List<PsiDirectory> allProjectDirs = FileTreeIterator.collectProjectDirectories(myProject);
dirs.addAll(allProjectDirs);
}
return dirs;
}
private void runProcessFile(@NotNull final PsiFile file) {
Document document = PsiDocumentManager.getInstance(myProject).getDocument(file);
@@ -493,72 +533,4 @@ public abstract class AbstractLayoutCodeProcessor {
myCompositeTask = compositeTask;
}
}
private static class FileTreeIterator {
private Queue<PsiFile> myCurrentFiles = new LinkedList<PsiFile>();
private Queue<PsiDirectory> myCurrentDirectories = new LinkedList<PsiDirectory>();
public FileTreeIterator(@NotNull List<PsiFile> files) {
myCurrentFiles.addAll(files);
}
public FileTreeIterator(@NotNull Module module) {
addDirectoriesFrom(module);
expandDirectoriesUntilFilesNotEmpty();
}
public FileTreeIterator(@NotNull Project project) {
Module[] modules = ModuleManager.getInstance(project).getModules();
for (Module module : modules) {
addDirectoriesFrom(module);
}
expandDirectoriesUntilFilesNotEmpty();
}
public FileTreeIterator(@NotNull PsiDirectory directory) {
myCurrentDirectories.add(directory);
expandDirectoriesUntilFilesNotEmpty();
}
public FileTreeIterator(@NotNull FileTreeIterator fileTreeIterator) {
myCurrentFiles = new LinkedList<PsiFile>(fileTreeIterator.myCurrentFiles);
myCurrentDirectories = new LinkedList<PsiDirectory>(fileTreeIterator.myCurrentDirectories);
}
@NotNull
public PsiFile next() {
if (myCurrentFiles.isEmpty()) {
throw new NoSuchElementException();
}
PsiFile current = myCurrentFiles.poll();
expandDirectoriesUntilFilesNotEmpty();
return current;
}
public boolean hasNext() {
return !myCurrentFiles.isEmpty();
}
private void expandDirectoriesUntilFilesNotEmpty() {
while (myCurrentFiles.isEmpty() && !myCurrentDirectories.isEmpty()) {
PsiDirectory dir = myCurrentDirectories.poll();
expandDirectory(dir);
}
}
private void expandDirectory(@NotNull PsiDirectory dir) {
Collections.addAll(myCurrentFiles, dir.getFiles());
Collections.addAll(myCurrentDirectories, dir.getSubdirectories());
}
private void addDirectoriesFrom(Module module) {
VirtualFile[] contentRoots = ModuleRootManager.getInstance(module).getContentRoots();
for (VirtualFile root : contentRoots) {
PsiDirectory dir = PsiManager.getInstance(module.getProject()).findDirectory(root);
if (dir != null) {
myCurrentDirectories.add(dir);
}
}
}
}
}
@@ -0,0 +1,111 @@
/*
* 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.
* 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.codeInsight.actions;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import java.util.*;
public class FileTreeIterator {
private Queue<PsiFile> myCurrentFiles = new LinkedList<PsiFile>();
private Queue<PsiDirectory> myCurrentDirectories = new LinkedList<PsiDirectory>();
public FileTreeIterator(@NotNull List<PsiFile> files) {
myCurrentFiles.addAll(files);
}
public FileTreeIterator(@NotNull Module module) {
myCurrentDirectories.addAll(collectModuleDirectories(module));
expandDirectoriesUntilFilesNotEmpty();
}
public FileTreeIterator(@NotNull Project project) {
myCurrentDirectories.addAll(collectProjectDirectories(project));
expandDirectoriesUntilFilesNotEmpty();
}
@NotNull
public static List<PsiDirectory> collectProjectDirectories(@NotNull Project project) {
List<PsiDirectory> directories = ContainerUtil.newArrayList();
Module[] modules = ModuleManager.getInstance(project).getModules();
for (Module module : modules) {
directories.addAll(collectModuleDirectories(module));
}
return directories;
}
public FileTreeIterator(@NotNull PsiDirectory directory) {
myCurrentDirectories.add(directory);
expandDirectoriesUntilFilesNotEmpty();
}
public FileTreeIterator(@NotNull FileTreeIterator fileTreeIterator) {
myCurrentFiles = new LinkedList<PsiFile>(fileTreeIterator.myCurrentFiles);
myCurrentDirectories = new LinkedList<PsiDirectory>(fileTreeIterator.myCurrentDirectories);
}
@NotNull
public PsiFile next() {
if (myCurrentFiles.isEmpty()) {
throw new NoSuchElementException();
}
PsiFile current = myCurrentFiles.poll();
expandDirectoriesUntilFilesNotEmpty();
return current;
}
public boolean hasNext() {
return !myCurrentFiles.isEmpty();
}
private void expandDirectoriesUntilFilesNotEmpty() {
while (myCurrentFiles.isEmpty() && !myCurrentDirectories.isEmpty()) {
PsiDirectory dir = myCurrentDirectories.poll();
expandDirectory(dir);
}
}
private void expandDirectory(@NotNull PsiDirectory dir) {
Collections.addAll(myCurrentFiles, dir.getFiles());
Collections.addAll(myCurrentDirectories, dir.getSubdirectories());
}
@NotNull
public static List<PsiDirectory> collectModuleDirectories(Module module) {
List<PsiDirectory> dirs = ContainerUtil.newArrayList();
VirtualFile[] contentRoots = ModuleRootManager.getInstance(module).getContentRoots();
for (VirtualFile root : contentRoots) {
PsiDirectory dir = PsiManager.getInstance(module.getProject()).findDirectory(root);
if (dir != null) {
dirs.add(dir);
}
}
return dirs;
}
}
@@ -17,7 +17,9 @@ package com.intellij.codeInsight.actions;
import com.intellij.openapi.application.ReadAction;
import com.intellij.openapi.application.Result;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.EditorFactory;
import com.intellij.openapi.editor.markup.RangeHighlighter;
import com.intellij.openapi.module.ModifiableModuleModel;
import com.intellij.openapi.module.Module;
@@ -25,27 +27,30 @@ import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vcs.changes.Change;
import com.intellij.openapi.vcs.changes.ChangeListManager;
import com.intellij.openapi.vcs.changes.ContentRevision;
import com.intellij.openapi.vcs.ex.LineStatusTracker;
import com.intellij.openapi.vcs.ex.Range;
import com.intellij.openapi.vcs.ex.RangesBuilder;
import com.intellij.openapi.vcs.impl.LineStatusTrackerManager;
import com.intellij.openapi.vcs.impl.LineStatusTrackerManagerI;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.ContainerUtilRt;
import com.intellij.util.diff.FilesTooBigForDiffException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
/**
* Contains utility methods for 'format only changed text' (in terms of VCS changes).
*
* @author Denis Zhdanov
* @since 12/19/11 10:55 AM
*/
public class FormatChangedTextUtil {
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.actions.FormatChangedTextUtil");
private FormatChangedTextUtil() {
}
@@ -120,6 +125,14 @@ public class FormatChangedTextUtil {
return false;
}
public static boolean hasChanges(@NotNull VirtualFile[] files, @NotNull Project project) {
for (VirtualFile file : files) {
if (hasChanges(file, project))
return true;
}
return false;
}
/**
* Allows to answer if any file that belongs to the given module has changes in comparison with VCS.
*
@@ -209,4 +222,96 @@ public class FormatChangedTextUtil {
}
return result;
}
@NotNull
public static List<PsiFile> getChangedFilesFromDirs(@NotNull Project project, @NotNull List<PsiDirectory> dirs) {
ChangeListManager changeListManager = ChangeListManager.getInstance(project);
Collection<Change> changes = ContainerUtil.newArrayList();
for (PsiDirectory dir : dirs) {
changes.addAll(changeListManager.getChangesIn(dir.getVirtualFile()));
}
return getChangedFiles(project, changes);
}
@NotNull
public static List<PsiFile> getChangedFiles(@NotNull Project project, @NotNull Collection<Change> changes) {
List<PsiFile> files = ContainerUtil.newArrayList();
for (Change change : changes) {
VirtualFile vFile = change.getVirtualFile();
if (vFile != null) {
PsiFile file = PsiManager.getInstance(project).findFile(vFile);
if (file != null) files.add(file);
}
}
return files;
}
@NotNull
public static List<TextRange> getChangedTextRanges(@NotNull Project project, @NotNull PsiFile file) {
Change change = ChangeListManager.getInstance(project).getChange(file.getVirtualFile());
if (change == null) {
return ContainerUtilRt.emptyList();
}
if (change.getType() == Change.Type.NEW) {
return ContainerUtil.newArrayList(file.getTextRange());
}
String contentFromVcs = getRevisionedContentFrom(change);
return contentFromVcs != null ? calculateChangedTextRanges(project, file, contentFromVcs)
: ContainerUtil.<TextRange>emptyList();
}
@Nullable
private static String getRevisionedContentFrom(@NotNull Change change) {
ContentRevision revision = change.getBeforeRevision();
if (revision == null) {
return null;
}
try {
return revision.getContent();
}
catch (VcsException e) {
LOG.error("Can't get content for: " + change.getVirtualFile(), e);
return null;
}
}
@NotNull
private static List<TextRange> calculateChangedTextRanges(@NotNull Project project, @NotNull PsiFile file, @NotNull String contentFromVcs) {
Document documentFromVcs = EditorFactory.getInstance().createDocument(contentFromVcs);
Document document = PsiDocumentManager.getInstance(project).getDocument(file);
if (document == null) {
return ContainerUtil.emptyList();
}
try {
List<Range> changedRanges = new RangesBuilder(document, documentFromVcs).getRanges();
return getChangedTextRanges(document, changedRanges);
}
catch (FilesTooBigForDiffException e) {
LOG.error("Error while calculating changed ranges for: " + file.getVirtualFile(), e);
return ContainerUtil.emptyList();
}
}
@NotNull
private static List<TextRange> getChangedTextRanges(@NotNull Document document, @NotNull List<Range> changedRanges) {
List<TextRange> ranges = ContainerUtil.newArrayList();
for (Range range : changedRanges) {
if (range.getType() != Range.DELETED) {
int changeStartLine = range.getOffset1();
int changeEndLine = range.getOffset2();
int lineStartOffset = document.getLineStartOffset(changeStartLine);
int lineEndOffset = document.getLineEndOffset(changeEndLine - 1);
ranges.add(new TextRange(lineStartOffset, lineEndOffset));
}
}
return ranges;
}
}
@@ -187,8 +187,7 @@ public class LayoutCodeDialog extends DialogWrapper implements LayoutCodeOptions
myCbArrangeEntries.setEnabled(true);
myCbArrangeEntries.setSelected(myRearrangeEntriesSelected);
//TODO enable it when getting changed ranges will be fixed
myCbOnlyVcsChangedRegions.setEnabled(false);
myCbOnlyVcsChangedRegions.setEnabled(myDirectory != null && FormatChangedTextUtil.hasChanges(myDirectory));
myCbOnlyVcsChangedRegions.setSelected(false);
myDoNotAskMeCheckBox.setEnabled(false);
@@ -34,11 +34,13 @@ public class LayoutProjectCodeDialog extends DialogWrapper implements ReformatFi
private static @NonNls final String HELP_ID = "editing.codeReformatting";
private final String myText;
private final boolean myEnableOnlyVCSChangedTextCb;
private final boolean mySuggestOptimizeImports;
private final Project myProject;
private JCheckBox myCbOptimizeImports;
private JCheckBox myCbOnlyVcsChangedRegions;
private JCheckBox myCbRearrangeEntries;
public LayoutProjectCodeDialog(@NotNull Project project,
@@ -51,6 +53,7 @@ public class LayoutProjectCodeDialog extends DialogWrapper implements ReformatFi
myText = text;
mySuggestOptimizeImports = suggestOptimizeImports;
myProject = project;
myEnableOnlyVCSChangedTextCb = enableOnlyVCSChangedTextCb;
setOKButtonText(CodeInsightBundle.message("reformat.code.accept.button.text"));
setTitle(title);
@@ -63,16 +66,22 @@ public class LayoutProjectCodeDialog extends DialogWrapper implements ReformatFi
return new JLabel(myText);
}
JPanel panel = new JPanel(new GridLayout(3, 1));
JPanel panel = new JPanel(new GridLayout(4, 1));
myCbOptimizeImports = new JCheckBox(CodeInsightBundle.message("reformat.option.optimize.imports"));
myCbRearrangeEntries = new JCheckBox(CodeInsightBundle.message("reformat.option.rearrange.entries"));
myCbOnlyVcsChangedRegions = new JCheckBox(CodeInsightBundle.message("reformat.option.vcs.changed.region"));
panel.add(new JLabel(myText));
panel.add(myCbOptimizeImports);
panel.add(myCbRearrangeEntries);
panel.add(myCbOnlyVcsChangedRegions);
myCbOptimizeImports.setSelected(PropertiesComponent.getInstance().getBoolean(LayoutCodeConstants.OPTIMIZE_IMPORTS_KEY, false));
myCbRearrangeEntries.setSelected(LayoutCodeSettingsStorage.getLastSavedRearrangeEntriesCbStateFor(myProject));
myCbOnlyVcsChangedRegions.setEnabled(myEnableOnlyVCSChangedTextCb);
myCbOnlyVcsChangedRegions.setSelected(
myEnableOnlyVCSChangedTextCb && PropertiesComponent.getInstance().getBoolean(LayoutCodeConstants.PROCESS_CHANGED_TEXT_KEY, false)
);
return panel;
}
@@ -99,6 +108,9 @@ public class LayoutProjectCodeDialog extends DialogWrapper implements ReformatFi
if (mySuggestOptimizeImports) {
PropertiesComponent.getInstance().setValue(LayoutCodeConstants.OPTIMIZE_IMPORTS_KEY, Boolean.toString(isOptimizeImports()));
LayoutCodeSettingsStorage.saveRearrangeEntriesOptionFor(myProject, isRearrangeEntries());
if (myEnableOnlyVCSChangedTextCb) {
PropertiesComponent.getInstance().setValue(LayoutCodeConstants.PROCESS_CHANGED_TEXT_KEY, Boolean.toString(myCbOnlyVcsChangedRegions.isSelected()));
}
}
}
@@ -107,7 +119,7 @@ public class LayoutProjectCodeDialog extends DialogWrapper implements ReformatFi
}
public boolean isProcessOnlyChangedText() {
return false;
return myCbOnlyVcsChangedRegions.isEnabled() && myCbOnlyVcsChangedRegions.isSelected();
}
}
@@ -26,6 +26,7 @@ import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiFile;
import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -62,14 +63,14 @@ public class ReformatCodeProcessor extends AbstractLayoutCodeProcessor {
}
}
public ReformatCodeProcessor(Project project, PsiFile[] files, Runnable postRunnable, boolean processChangedTextOnly) {
public ReformatCodeProcessor(Project project, PsiFile[] files, @Nullable Runnable postRunnable, boolean processChangedTextOnly) {
this(project, files, COMMAND_NAME, postRunnable, processChangedTextOnly);
}
public ReformatCodeProcessor(Project project,
PsiFile[] files,
String commandName,
Runnable postRunnable,
@Nullable Runnable postRunnable,
boolean processChangedTextOnly)
{
super(project, files, PROGRESS_TEXT, commandName, postRunnable, processChangedTextOnly);
@@ -85,13 +86,8 @@ public class ReformatCodeProcessor extends AbstractLayoutCodeProcessor {
public Boolean call() throws Exception {
FormattingProgressTask.FORMATTING_CANCELLED_FLAG.set(false);
try {
if (myRanges.isEmpty() && processChangedTextOnly) {
myRanges.addAll(FormatChangedTextUtil.getChanges(file));
}
if (myRanges.isEmpty()) {
myRanges.add(file.getTextRange());
}
CodeStyleManager.getInstance(myProject).reformatText(file, myRanges);
Collection<TextRange> ranges = getRangesToFormat(processChangedTextOnly, file);
CodeStyleManager.getInstance(myProject).reformatText(file, ranges);
return !FormattingProgressTask.FORMATTING_CANCELLED_FLAG.get();
}
catch (IncorrectOperationException e) {
@@ -104,4 +100,13 @@ public class ReformatCodeProcessor extends AbstractLayoutCodeProcessor {
}
});
}
}
@NotNull
private Collection<TextRange> getRangesToFormat(boolean processChangedTextOnly, PsiFile file) {
if (processChangedTextOnly) {
return FormatChangedTextUtil.getChangedTextRanges(myProject, file);
}
return !myRanges.isEmpty() ? myRanges : ContainerUtil.newArrayList(file.getTextRange());
}
}
@@ -3,12 +3,12 @@
<grid id="59847" binding="myPanel" layout-manager="GridLayoutManager" row-count="1" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="4" bottom="0" right="0"/>
<constraints>
<xy x="30" y="17" width="244" height="113"/>
<xy x="30" y="17" width="244" height="149"/>
</constraints>
<properties/>
<border type="none"/>
<children>
<grid id="e83d0" layout-manager="GridLayoutManager" row-count="4" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<grid id="e83d0" layout-manager="GridLayoutManager" row-count="5" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
@@ -32,9 +32,17 @@
<text resource-bundle="messages/CodeInsightBundle" key="dialog.reformat.files.optimize.imports.checkbox"/>
</properties>
</component>
<component id="a0a79" class="javax.swing.JCheckBox" binding="myOnlyChangedText">
<constraints>
<grid row="3" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text resource-bundle="messages/CodeInsightBundle" key="reformat.option.vcs.changed.region"/>
</properties>
</component>
<vspacer id="8d758">
<constraints>
<grid row="3" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
<grid row="4" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
</constraints>
</vspacer>
<component id="cf942" class="javax.swing.JCheckBox" binding="myRearrangeEntriesCb">
@@ -29,6 +29,7 @@ public class ReformatFilesDialog extends DialogWrapper implements ReformatFilesO
@NotNull private Project myProject;
private JPanel myPanel;
private JCheckBox myOptimizeImports;
private JCheckBox myOnlyChangedText;
private JCheckBox myRearrangeEntriesCb;
public ReformatFilesDialog(@NotNull Project project, @NotNull VirtualFile[] files) {
@@ -36,6 +37,11 @@ public class ReformatFilesDialog extends DialogWrapper implements ReformatFilesO
myProject = project;
setTitle(CodeInsightBundle.message("dialog.reformat.files.title"));
myOptimizeImports.setSelected(isOptmizeImportsOptionOn());
boolean canTargetVcsChanges = FormatChangedTextUtil.hasChanges(files, project);
myOnlyChangedText.setEnabled(canTargetVcsChanges);
myOnlyChangedText.setSelected(
canTargetVcsChanges && PropertiesComponent.getInstance().getBoolean(LayoutCodeConstants.PROCESS_CHANGED_TEXT_KEY, false)
);
myOptimizeImports.setSelected(isOptmizeImportsOptionOn());
myRearrangeEntriesCb.setSelected(LayoutCodeSettingsStorage.getLastSavedRearrangeEntriesCbStateFor(myProject));
init();
@@ -53,7 +59,7 @@ public class ReformatFilesDialog extends DialogWrapper implements ReformatFilesO
@Override
public boolean isProcessOnlyChangedText() {
return false;
return myOnlyChangedText.isEnabled() && myOnlyChangedText.isSelected();
}
@Override
@@ -65,6 +71,7 @@ public class ReformatFilesDialog extends DialogWrapper implements ReformatFilesO
protected void doOKAction() {
super.doOKAction();
PropertiesComponent.getInstance().setValue(LayoutCodeConstants.OPTIMIZE_IMPORTS_KEY, Boolean.toString(myOptimizeImports.isSelected()));
PropertiesComponent.getInstance().setValue(LayoutCodeConstants.PROCESS_CHANGED_TEXT_KEY, Boolean.toString(myOnlyChangedText.isSelected()));
LayoutCodeSettingsStorage.saveRearrangeEntriesOptionFor(myProject, isRearrangeEntries());
}
@@ -33,9 +33,11 @@ import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.fileEditor.TextEditor;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.impl.BackgroundableProcessIndicator;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.popup.JBPopup;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.ui.popup.LightweightWindowEvent;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.vfs.VirtualFile;
@@ -285,10 +287,21 @@ public class ShowImplementationsAction extends AnAction implements PopupAction {
@Override
public boolean process(JBPopup popup) {
usageView.set(component.showInUsageView());
myTaskRef = new WeakReference<BackgroundUpdaterTask>(null);
popup.cancel();
return false;
}
})
.setCancelCallback(new Computable<Boolean>() {
@Override
public Boolean compute() {
final BackgroundUpdaterTask task = myTaskRef.get();
if (task != null) {
task.setCanceled();
}
return Boolean.TRUE;
}
})
.createPopup();
updateInBackground(editor, element, component, title, (AbstractPopup)popup, usageView);
@@ -315,7 +328,12 @@ public class ShowImplementationsAction extends AnAction implements PopupAction {
task.init(popup, component, usageView);
myTaskRef = new WeakReference<BackgroundUpdaterTask>(task);
ProgressManager.getInstance().run(task);
ProgressManager.getInstance().runProcessWithProgressAsynchronously(task, new BackgroundableProcessIndicator(task) {
@Override
public boolean isCanceled() {
return super.isCanceled() || task.isCanceled();
}
});
}
protected boolean isIncludeAlwaysSelf() {
@@ -73,12 +73,6 @@ public abstract class BackgroundUpdaterTask<T> extends Task.Backgroundable {
myComponent = component;
myUsageView = usageView;
myPopup.addPopupListener(new JBPopupAdapter() {
@Override
public void onClosed(LightweightWindowEvent event) {
setCanceled();
}
});
}
public abstract String getCaption(int size);
@@ -91,6 +85,10 @@ public abstract class BackgroundUpdaterTask<T> extends Task.Backgroundable {
return canceled;
}
public boolean isCanceled() {
return myCanceled;
}
public boolean updateComponent(final PsiElement element, @Nullable final Comparator comparator) {
final UsageView view = myUsageView.get();
if (view != null && !((UsageViewImpl)view).isDisposed()) {
@@ -152,10 +152,8 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA
private Component myContextComponent;
private CalcThread myCalcThread;
private static AtomicBoolean ourShiftIsPressed = new AtomicBoolean(false);
private static AtomicBoolean shift1Pressed = new AtomicBoolean(false);
private static AtomicBoolean shift1Released = new AtomicBoolean(false);
private static AtomicBoolean shift2Pressed = new AtomicBoolean(false);
private static AtomicBoolean shift2Released = new AtomicBoolean(false);
private final static Couple<AtomicBoolean> ourPressed = Couple.newOne(new AtomicBoolean(false), new AtomicBoolean(false));
private final static Couple<AtomicBoolean> ourReleased = Couple.newOne(new AtomicBoolean(false), new AtomicBoolean(false));
private static AtomicBoolean ourOtherKeyWasPressed = new AtomicBoolean(false);
private static AtomicLong ourLastTimePressed = new AtomicLong(0);
private static AtomicBoolean showAll = new AtomicBoolean(false);
@@ -185,7 +183,7 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA
return false;
}
ourOtherKeyWasPressed.set(false);
if (shift1Pressed.get() && System.currentTimeMillis() - ourLastTimePressed.get() > 500) {
if (ourPressed.first.get() && System.currentTimeMillis() - ourLastTimePressed.get() > 500) {
resetState();
}
handleShift((KeyEvent)event);
@@ -203,37 +201,37 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA
}
private void resetState() {
shift1Pressed.set(false);
shift1Released.set(false);
shift2Pressed.set(false);
shift2Released.set(false);
ourPressed.first.set(false);
ourPressed.second.set(false);
ourReleased.first.set(false);
ourReleased.second.set(false);
}
private void handleShift(KeyEvent event) {
if (shift1Pressed.get() && System.currentTimeMillis() - ourLastTimePressed.get() > 300) {
if (ourPressed.first.get() && System.currentTimeMillis() - ourLastTimePressed.get() > 300) {
resetState();
return;
}
if (event.getID() == KeyEvent.KEY_PRESSED) {
if (!shift1Pressed.get()) {
if (!ourPressed.first.get()) {
resetState();
shift1Pressed.set(true);
ourPressed.first.set(true);
ourLastTimePressed.set(System.currentTimeMillis());
return;
} else {
if (shift1Pressed.get() && shift1Released.get()) {
shift2Pressed.set(true);
if (ourPressed.first.get() && ourReleased.first.get()) {
ourPressed.second.set(true);
ourLastTimePressed.set(System.currentTimeMillis());
return;
}
}
} else if (event.getID() == KeyEvent.KEY_RELEASED) {
if (shift1Pressed.get() && !shift1Released.get()) {
shift1Released.set(true);
if (ourPressed.first.get() && !ourReleased.first.get()) {
ourReleased.first.set(true);
ourLastTimePressed.set(System.currentTimeMillis());
return;
} else if (shift1Pressed.get() && shift1Released.get() && shift2Pressed.get()) {
} else if (ourPressed.first.get() && ourReleased.first.get() && ourPressed.second.get()) {
resetState();
run(event);
return;
@@ -426,16 +424,9 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA
@Override
protected void textChanged(DocumentEvent e) {
final String pattern = editor.getText();
final int len = pattern.trim().length();
myAlarm.cancelAllRequests();
myAlarm.addRequest(new Runnable() {
@Override
public void run() {
if (editor.hasFocus()) {
rebuildList(pattern);
}
}
}, len == 1 ? 400 : len == 2 ? 300 : len == 3 ? 250 : 30);
if (editor.hasFocus()) {
rebuildList(pattern);
}
}
});
editor.addFocusListener(new FocusAdapter() {
@@ -1021,7 +1012,7 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA
final int width = myMainPanel.getPreferredSize().width;
if (width > myPopupActualWidth) {
myPopupActualWidth = width;
schedulePopupUpdate();
//schedulePopupUpdate();
}
return myMainPanel;
}
@@ -45,6 +45,15 @@ public class LazyRangeMarkerFactory {
EditorFactory.getInstance().getEventMulticaster().addDocumentListener(new DocumentAdapter() {
@Override
public void beforeDocumentChange(DocumentEvent e) {
transformRangeMarkers(e);
}
@Override
public void documentChanged(DocumentEvent e) {
transformRangeMarkers(e);
}
private void transformRangeMarkers(DocumentEvent e) {
VirtualFile file = fileDocumentManager.getFile(e.getDocument());
if (file == null) {
return;
@@ -58,8 +67,7 @@ public class LazyRangeMarkerFactory {
List<LazyMarker> markers = lazyMarkers.toStrongList();
List<LazyMarker> markersToRemove = null;
for (LazyMarker marker : markers) {
if (file.equals(marker.getFile())) {
marker.getOrCreateDelegate();
if (file.equals(marker.getFile()) && marker.documentChanged(e.getDocument()) != null) {
if (markersToRemove == null) {
markersToRemove = new SmartList<LazyMarker>();
}
@@ -143,13 +151,26 @@ public class LazyRangeMarkerFactory {
return myDelegate;
}
@NotNull
@Nullable
protected final RangeMarker documentChanged(@NotNull Document document) {
if (myDelegate == null) {
myDelegate = createDelegate(myFile, document);
}
return myDelegate;
}
@Nullable
protected abstract RangeMarker createDelegate(@NotNull VirtualFile file, @NotNull Document document);
@Override
@NotNull
public Document getDocument() {
return getOrCreateDelegate().getDocument();
RangeMarker delegate = getOrCreateDelegate();
if (delegate == null) {
//noinspection ConstantConditions
return FileDocumentManager.getInstance().getDocument(myFile);
}
return delegate.getDocument();
}
@Override
@@ -222,10 +243,13 @@ public class LazyRangeMarkerFactory {
}
@Override
@NotNull
public RangeMarker createDelegate(@NotNull VirtualFile file, @NotNull final Document document) {
int offset = calculateOffset(myProject, file, document, myLine, myColumn);
@Nullable
public RangeMarker createDelegate(@NotNull VirtualFile file, @NotNull Document document) {
if (document.getTextLength() == 0 && !(myLine == 0 && myColumn == 0)) {
return null;
}
int offset = calculateOffset(myProject, file, document, myLine, myColumn);
return document.createRangeMarker(offset, offset);
}
@@ -69,6 +69,7 @@ import javax.xml.parsers.SAXParserFactory;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URL;
import java.util.*;
@@ -329,6 +330,9 @@ public abstract class PluginManagerMain implements Disposable {
}
catch (ProcessCanceledException ignore) {
}
catch (FileNotFoundException e) {
LOG.info(e);
}
catch (Exception e) {
LOG.info(e);
errorMessages.add(e.getMessage());
@@ -1,45 +0,0 @@
/*
* 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.
* 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.startupWizardV2;
import com.intellij.CommonBundle;
import org.jetbrains.annotations.NotNull;
public class FeaturedPluginsPage extends AbstractWizardPage{
@NotNull
@Override
String getID() {
return "Featured plugins";
}
@NotNull
@Override
String getTitle() {
return "Download featured plugins";
}
@NotNull
@Override
String getHeader() {
return "We have a few plugins in our web repository that most users like to download. Perhaps, you need them too?";
}
@NotNull
@Override
String getFooter() {
return "New plugins can be also downloaded in " + CommonBundle.settingsTitle() +" | Plugins";
}
}
@@ -1,115 +0,0 @@
/*
* 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.
* 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.startupWizardV2;
import com.intellij.CommonBundle;
import com.intellij.ide.ui.laf.IntelliJLookAndFeelInfo;
import com.intellij.ide.ui.laf.darcula.DarculaLookAndFeelInfo;
import com.intellij.openapi.util.IconLoader;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.util.IconUtil;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import java.awt.*;
import java.util.LinkedHashMap;
import java.util.Map;
public class LafPage extends AbstractWizardPage {
private static final String AQUA = "Default";
private static final String DARCULA = "Darcula";
private static final String ALLOY = "Alloy. IDEA Theme";
private static final String INTELLIJ = "IntelliJ";
private static final String GTK = "GTK+";
private Map<UIManager.LookAndFeelInfo, Icon> myLafs = new LinkedHashMap<UIManager.LookAndFeelInfo, Icon>();
private final JLabel myPreviewLabel = new JLabel();
private final boolean myVertical;
public LafPage() {
boolean isAlloyAvailable = false;
boolean isGTKAvailable = false;
for (UIManager.LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
if (ALLOY.equals(info.getName())) {
isAlloyAvailable = true;
}
if (GTK.equals(info.getName())) {
isGTKAvailable = true;
}
}
final String osPrefix = SystemInfo.isMac ? "OSX" : SystemInfo.isWindows ? "Windows" : "Linux";
if (SystemInfo.isMac) {
myLafs.put(new UIManager.LookAndFeelInfo(AQUA, "com.apple.laf.AquaLookAndFeel"), IconLoader.getIcon("/lafs/OSXAqua.png"));
}
else {
if (isAlloyAvailable) {
myLafs.put(new UIManager.LookAndFeelInfo(ALLOY, "com.incors.plaf.alloy.AlloyIdea"),
IconLoader.getIcon("/lafs/" + osPrefix + "Alloy.png"));
}
else {
myLafs.put(new IntelliJLookAndFeelInfo(), IconLoader.getIcon("/lafs/" + osPrefix + "IntelliJ.png"));
}
}
myLafs.put(new DarculaLookAndFeelInfo(), IconLoader.getIcon("/lafs/" + osPrefix + "Darcula.png"));
if (SystemInfo.isLinux && isGTKAvailable) {
myLafs.put(new UIManager.LookAndFeelInfo(GTK, "com.sun.java.swing.plaf.gtk.GTKLookAndFeel"),
IconLoader.getIcon("/lafs/" + osPrefix + "GTK.png"));
}
myVertical = myLafs.size() > 2;
JPanel buttonPanel = new JPanel(myVertical ? new GridLayout(myLafs.size(), 1, 5, 5) : new GridLayout(1, myLafs.size(), 5, 5));
ButtonGroup group = new ButtonGroup();
boolean isFirst = true;
for (Map.Entry<UIManager.LookAndFeelInfo, Icon> entry : myLafs.entrySet()) {
JPanel p = new JPanel(new BorderLayout());
JRadioButton radioButton = new JRadioButton(entry.getKey().getName(), isFirst);
isFirst = false;
group.add(radioButton);
p.add(radioButton, BorderLayout.NORTH);
Icon icon = entry.getValue();
buttonPanel.add(new JLabel(myVertical ?
new ImageIcon(IconUtil.toImage(icon)
.getScaledInstance(icon.getIconWidth() / 3, icon.getIconHeight() / 3, Image.SCALE_AREA_AVERAGING))
: icon));
}
setLayout(new BorderLayout());
add(buttonPanel, BorderLayout.CENTER);
if (myVertical) {
add(myPreviewLabel, BorderLayout.EAST);
}
}
@NotNull
@Override
String getTitle() {
return "Set UI Theme";
}
@NotNull
@Override
String getID() {
return "UI Themes";
}
@NotNull
@Override
String getFooter() {
return "UI theme can be changed later in " + CommonBundle.settingsTitle() + " | Appearance.";
}
}
@@ -1,39 +0,0 @@
/*
* 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.
* 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.startupWizardV2;
import com.intellij.openapi.application.ApplicationNamesInfo;
import org.jetbrains.annotations.NotNull;
public class PluginsPage extends AbstractWizardPage {
@NotNull
@Override
String getID() {
return "Default plugins";
}
@NotNull
@Override
String getTitle() {
return "Tune " + ApplicationNamesInfo.getInstance().getProductName() + " to your tasks";
}
@NotNull
@Override
String getHeader() {
return ApplicationNamesInfo.getInstance().getProductName() + " has a lot of tools enabled by default. You can set only the ones you need or leave them all.";
}
}
@@ -1,153 +0,0 @@
/*
* 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.
* 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.startupWizardV2;
import com.intellij.openapi.application.ApplicationNamesInfo;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.VerticalFlowLayout;
import com.intellij.openapi.util.IconLoader;
import com.intellij.ui.JBCardLayout;
import com.intellij.ui.components.JBScrollPane;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Arrays;
import java.util.List;
public class StartupWizard2 extends DialogWrapper implements ActionListener {
private final JLabel myNavLabel = new JLabel();
private final JLabel myHeaderLabel = new JLabel();
private final JLabel myFooterLabel = new JLabel();
private final JBCardLayout myCardLayout = new JBCardLayout();
private final JPanel myContentPanel = new JPanel(myCardLayout);
private final JButton mySkipButton = new JButton();
private final JButton myBackwardButton = new JButton();
private final JButton myForwardButton = new JButton();
private List<AbstractWizardPage> myPages = Arrays.asList(new LafPage(), new KeymapPage(), new PluginsPage(), new FeaturedPluginsPage());
private int myIndex = -1;
public StartupWizard2() {
super(null, true, true);
IconLoader.activate();
getPeer().setAppIcons();
setResizable(false);
setTitle("Customize" + ApplicationNamesInfo.getInstance().getProductName());
init();
showPage(0);
}
@Override
protected void dispose() {
super.dispose();
IconLoader.deactivate();
}
@Override
public Dimension getPreferredSize() {
return new Dimension(700, 700);
}
@Override
public void actionPerformed(ActionEvent event) {
if (event.getSource() == mySkipButton) {
doOKAction();
}
if (event.getSource() == myBackwardButton) {
showPage(myIndex - 1);
}
if (event.getSource() == myForwardButton) {
if (myIndex == myPages.size() - 1) {
doOKAction();
}
else {
showPage(myIndex + 1);
}
}
}
private void showPage(int index) {
myIndex = index;
AbstractWizardPage page = myPages.get(index);
myCardLayout.swipe(myContentPanel, page.getID(), JBCardLayout.SwipeDirection.AUTO);
updateNavLabel();
myHeaderLabel.setText("<html><body><h2>" + page.getTitle() + "</h2>" + page.getHeader() + "</body></html>");
myFooterLabel.setText("<html><body>" + page.getFooter() + "</body></html>");
mySkipButton.setText(myIndex>0?"Skip All and Set Defaults" : "Skip Remaining and Set Defaults");
myBackwardButton.setVisible(myIndex>0);
if (myIndex > 0) {
myBackwardButton.setText("Back to " + myPages.get(myIndex-1).getID());
}
myForwardButton.setText(myIndex < myPages.size() - 1 ? "Next: " + myPages.get(myIndex+1).getID() : "Start using " + ApplicationNamesInfo
.getInstance().getFullProductName());
}
private void updateNavLabel() {
StringBuilder sb = new StringBuilder("<html><body>");
for (int i = 0; i < myPages.size(); i++) {
AbstractWizardPage wizardPage = myPages.get(i);
if (i > 0 && i < myPages.size() - 1) sb.append(" &#8594; ");
if (i == myIndex) sb.append("<b>");
sb.append(wizardPage.getID());
if (i == myIndex) sb.append("</b>");
}
sb.append("</body></html>");
myNavLabel.setText(sb.toString());
}
@Nullable
@Override
protected JComponent createCenterPanel() {
for (AbstractWizardPage page : myPages) {
myContentPanel.add(page, page.getID());
}
JPanel mainPanel = new JPanel(new VerticalFlowLayout());
mainPanel.add(myNavLabel);
mainPanel.add(myHeaderLabel);
mainPanel.add(
new JBScrollPane(myContentPanel, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER));
mainPanel.add(myFooterLabel);
return mainPanel;
}
@Nullable
@Override
protected JComponent createSouthPanel() {
JPanel result = new JPanel(new GridBagLayout());
result.setBorder(new EmptyBorder(5, 5, 5, 5));
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridy = 0;
result.add(mySkipButton, gbc);
result.add(myBackwardButton, gbc);
gbc.weightx = 1;
result.add(Box.createHorizontalGlue(), gbc);
gbc.weightx = 0;
result.add(myForwardButton, gbc);
mySkipButton.addActionListener(this);
myBackwardButton.addActionListener(this);
myForwardButton.addActionListener(this);
return result;
}
}
@@ -18,7 +18,6 @@ package com.intellij.openapi.vfs.impl.jar;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.components.ApplicationComponent;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.io.FileAttributes;
import com.intellij.openapi.util.io.FileUtil;
@@ -44,7 +43,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
public class JarFileSystemImpl extends JarFileSystem implements ApplicationComponent {
public class JarFileSystemImpl extends JarFileSystem {
private static final class JarFileSystemImplLock { }
private static final JarFileSystemImplLock LOCK = new JarFileSystemImplLock();
@@ -125,18 +124,6 @@ public class JarFileSystemImpl extends JarFileSystem implements ApplicationCompo
return null;
}
@Override
@NotNull
public String getComponentName() {
return "JarFileSystem";
}
@Override
public void initComponent() { }
@Override
public void disposeComponent() { }
@Override
public void setNoCopyJarForPath(String pathInJar) {
if (myNoCopyJarPaths == null || pathInJar == null) return;
@@ -3,11 +3,16 @@ package com.intellij.util.io.socketConnection;
import org.jetbrains.annotations.NotNull;
public enum ConnectionStatus {
NOT_CONNECTED("Not connected"), WAITING_FOR_CONNECTION("Waiting for connection"), CONNECTED("Connected"), DISCONNECTED("Disconnected"),
CONNECTION_FAILED("Connection failed");
NOT_CONNECTED("Not connected"),
WAITING_FOR_CONNECTION("Waiting for connection"),
CONNECTED("Connected"),
DISCONNECTED("Disconnected"),
CONNECTION_FAILED("Connection failed"),
DETACHED("Detached");
private final String myStatusText;
ConnectionStatus(String statusText) {
ConnectionStatus(@NotNull String statusText) {
myStatusText = statusText;
}
@@ -16,7 +16,7 @@ home.directory.not.specified.for.jdk.error.message=Home directory is not specifi
run.configuration.pause.output.action.name=Pause Output
main.class.is.not.specified.error.message=Main class is not specified
close.tab.action.name=Close
run.configuration.show.command.line.action.name=Show command line
run.configuration.show.command.line.action.name=Show Python Prompt
#---
create.run.configuration.action.name=Create Run Configuration
@@ -13,27 +13,29 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.ide.startupWizardV2;
package com.intellij.codeInsight.actions;
import com.intellij.CommonBundle;
import org.jetbrains.annotations.NotNull;
public class ChangedLines {
public final int from;
public final int to;
public class KeymapPage extends AbstractWizardPage {
@NotNull
@Override
String getID() {
return "Keymaps";
ChangedLines(int from, int to) {
this.from = from;
this.to = to;
}
@NotNull
@Override
String getTitle() {
return "Select keymap scheme";
public String toString() {
return "(" + from + ", " + to + ")";
}
@NotNull
@Override
String getFooter() {
return "Keymap scheme can be later changed in " + CommonBundle.settingsTitle() + " | Keymap";
public boolean equals(Object obj) {
if (obj instanceof ChangedLines) {
ChangedLines line = (ChangedLines)obj;
return from == line.from && to == line.to;
}
return false;
}
}
@@ -0,0 +1,172 @@
/*
* 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.
* 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.codeInsight.actions;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.psi.codeStyle.Indent;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.ThrowableRunnable;
import com.intellij.util.containers.HashMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.Map;
public class MockCodeStyleManager extends CodeStyleManager {
private Map<PsiFile, ChangedLines[]> myFormattedLinesForFile = new HashMap<PsiFile, ChangedLines[]>();
@NotNull
public ChangedLines[] getFormattedLinesFor(@NotNull PsiFile file) {
ChangedLines[] changedLines = myFormattedLinesForFile.get(file);
return changedLines != null ? changedLines : new ChangedLines[0];
}
@Override
public void reformatText(@NotNull PsiFile file, @NotNull Collection<TextRange> ranges) throws IncorrectOperationException {
Document document = PsiDocumentManager.getInstance(file.getProject()).getDocument(file);
assert(document != null);
ChangedLines[] formattedLines = new ChangedLines[ranges.size()];
int i = 0;
for (TextRange range : ranges) {
int lineStart = document.getLineNumber(range.getStartOffset());
int lineEnd = document.getLineNumber(range.getEndOffset());
formattedLines[i++] = new ChangedLines(lineStart, lineEnd);
}
myFormattedLinesForFile.put(file, formattedLines);
}
@NotNull
@Override
public Project getProject() {
throw new UnsupportedOperationException("com.intellij.codeInsight.actions.MockCodeStyleManager.getProject(...)");
}
@NotNull
@Override
public PsiElement reformat(@NotNull PsiElement element) throws IncorrectOperationException {
throw new UnsupportedOperationException("com.intellij.codeInsight.actions.MockCodeStyleManager.reformat(...)");
}
@NotNull
@Override
public PsiElement reformat(@NotNull PsiElement element, boolean canChangeWhiteSpacesOnly) throws IncorrectOperationException {
throw new UnsupportedOperationException("com.intellij.codeInsight.actions.MockCodeStyleManager.reformat(...)");
}
@Override
public PsiElement reformatRange(@NotNull PsiElement element, int startOffset, int endOffset) throws IncorrectOperationException {
throw new UnsupportedOperationException("com.intellij.codeInsight.actions.MockCodeStyleManager.reformatRange(...)");
}
@Override
public PsiElement reformatRange(@NotNull PsiElement element, int startOffset, int endOffset, boolean canChangeWhiteSpacesOnly)
throws IncorrectOperationException {
throw new UnsupportedOperationException("com.intellij.codeInsight.actions.MockCodeStyleManager.reformatRange(...)");
}
@Override
public void reformatText(@NotNull PsiFile file, int startOffset, int endOffset) throws IncorrectOperationException {
throw new UnsupportedOperationException("com.intellij.codeInsight.actions.MockCodeStyleManager.reformatText(...)");
}
@Override
public void adjustLineIndent(@NotNull PsiFile file, TextRange rangeToAdjust) throws IncorrectOperationException {
throw new UnsupportedOperationException("com.intellij.codeInsight.actions.MockCodeStyleManager.adjustLineIndent(...)");
}
@Override
public int adjustLineIndent(@NotNull PsiFile file, int offset) throws IncorrectOperationException {
throw new UnsupportedOperationException("com.intellij.codeInsight.actions.MockCodeStyleManager.adjustLineIndent(...)");
}
@Override
public int adjustLineIndent(@NotNull Document document, int offset) {
throw new UnsupportedOperationException("com.intellij.codeInsight.actions.MockCodeStyleManager.adjustLineIndent(...)");
}
@Override
public boolean isLineToBeIndented(@NotNull PsiFile file, int offset) {
throw new UnsupportedOperationException("com.intellij.codeInsight.actions.MockCodeStyleManager.isLineToBeIndented(...)");
}
@Nullable
@Override
public String getLineIndent(@NotNull PsiFile file, int offset) {
throw new UnsupportedOperationException("com.intellij.codeInsight.actions.MockCodeStyleManager.getLineIndent(...)");
}
@Nullable
@Override
public String getLineIndent(@NotNull Document document, int offset) {
throw new UnsupportedOperationException("com.intellij.codeInsight.actions.MockCodeStyleManager.getLineIndent(...)");
}
@Override
public Indent getIndent(String text, FileType fileType) {
throw new UnsupportedOperationException("com.intellij.codeInsight.actions.MockCodeStyleManager.getIndent(...)");
}
@Override
public String fillIndent(Indent indent, FileType fileType) {
throw new UnsupportedOperationException("com.intellij.codeInsight.actions.MockCodeStyleManager.fillIndent(...)");
}
@Override
public Indent zeroIndent() {
throw new UnsupportedOperationException("com.intellij.codeInsight.actions.MockCodeStyleManager.zeroIndent(...)");
}
@Override
public void reformatNewlyAddedElement(@NotNull ASTNode block, @NotNull ASTNode addedElement)
throws IncorrectOperationException {
throw new UnsupportedOperationException("com.intellij.codeInsight.actions.MockCodeStyleManager.reformatNewlyAddedElement(...)");
}
@Override
public boolean isSequentialProcessingAllowed() {
throw new UnsupportedOperationException("com.intellij.codeInsight.actions.MockCodeStyleManager.isSequentialProcessingAllowed(...)");
}
@Override
public void performActionWithFormatterDisabled(Runnable r) {
throw new UnsupportedOperationException(
"com.intellij.codeInsight.actions.MockCodeStyleManager.performActionWithFormatterDisabled(...)");
}
@Override
public <T extends Throwable> void performActionWithFormatterDisabled(ThrowableRunnable<T> r) throws T {
throw new UnsupportedOperationException(
"com.intellij.codeInsight.actions.MockCodeStyleManager.performActionWithFormatterDisabled(...)");
}
@Override
public <T> T performActionWithFormatterDisabled(Computable<T> r) {
throw new UnsupportedOperationException(
"com.intellij.codeInsight.actions.MockCodeStyleManager.performActionWithFormatterDisabled(...)");
}
}
@@ -0,0 +1,46 @@
/*
* 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.
* 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.codeInsight.actions;
import com.intellij.formatting.CustomFormattingModelBuilder;
import com.intellij.formatting.FormattingModel;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class MockPlainTextFormattingModelBuilder implements CustomFormattingModelBuilder {
@Override
public boolean isEngagedToFormat(PsiElement context) {
return true;
}
@NotNull
@Override
public FormattingModel createModel(PsiElement element, CodeStyleSettings settings) {
throw new UnsupportedOperationException("com.intellij.codeInsight.actions.MockPlainTextFormattingModelBuilder.createModel(...)");
}
@Nullable
@Override
public TextRange getRangeAffectingIndent(PsiFile file, int offset, ASTNode elementAtOffset) {
throw new UnsupportedOperationException("com.intellij.codeInsight.actions.MockPlainTextFormattingModelBuilder.getRangeAffectingIndent(...)");
}
}
@@ -0,0 +1,339 @@
/*
* 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.
* 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.codeInsight.actions;
import com.intellij.lang.LanguageFormatting;
import com.intellij.openapi.components.impl.ComponentManagerImpl;
import com.intellij.openapi.fileTypes.PlainTextLanguage;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vcs.FilePathImpl;
import com.intellij.openapi.vcs.changes.Change;
import com.intellij.openapi.vcs.changes.ChangeListManager;
import com.intellij.openapi.vcs.changes.ContentRevision;
import com.intellij.openapi.vcs.changes.SimpleContentRevision;
import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiFile;
import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.testFramework.LightPlatformTestCase;
import com.intellij.testFramework.PlatformTestCase;
import com.intellij.testFramework.vcs.MockChangeListManager;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.picocontainer.MutablePicoContainer;
import java.io.IOException;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
public class ReformatOnlyVcsChangedTextTest extends LightPlatformTestCase {
private static final String TEMP_DIR_NAME = "dir";
private PsiDirectory myWorkingDirectory;
private MockChangeListManager myMockChangeListManager;
private MockCodeStyleManager myMockCodeStyleManager;
private MockPlainTextFormattingModelBuilder myMockPlainTextFormattingModelBuilder;
private ChangeListManager myRealChangeListManager;
private CodeStyleManager myRealCodeStyleManger;
private final static String COMMITTED =
"class Test {\n" +
" int a = 22;\n" +
" public String getName() { return \"Test\"; }\n" +
"}";
private final static String MODIFIED =
"class Test {\n" +
" int a = 22;\n" +
" long l;\n" +
" double d;\n" +
" int i;\n" +
" public String getName() { return \"Test\"; }\n" +
" String test1;\n" +
" String test2;\n" +
"}";
private final static ChangedLines[] CHANGED_LINES = new ChangedLines[] { line(2, 4), line(6, 7) };
private final static ChangedLines[] NO_CHANGED_LINES = new ChangedLines[0];
@Override
public void setUp() throws Exception {
PlatformTestCase.initPlatformLangPrefix();
super.setUp();
myWorkingDirectory = TestFileStructure.createDirectory(getProject(), getSourceRoot(), TEMP_DIR_NAME);
myRealChangeListManager = ChangeListManager.getInstance(getProject());
myMockChangeListManager = new MockChangeListManager();
registerChangeListManager(myMockChangeListManager);
myRealCodeStyleManger = CodeStyleManager.getInstance(getProject());
myMockCodeStyleManager = new MockCodeStyleManager();
registerCodeStyleManager(myMockCodeStyleManager);
myMockPlainTextFormattingModelBuilder = new MockPlainTextFormattingModelBuilder();
LanguageFormatting.INSTANCE.addExplicitExtension(PlainTextLanguage.INSTANCE, myMockPlainTextFormattingModelBuilder);
}
@Override
public void tearDown() throws Exception {
registerChangeListManager(myRealChangeListManager);
registerCodeStyleManager(myRealCodeStyleManger);
LanguageFormatting.INSTANCE.removeExplicitExtension(PlainTextLanguage.INSTANCE, myMockPlainTextFormattingModelBuilder);
TestFileStructure.delete(myWorkingDirectory.getVirtualFile());
super.tearDown();
}
public void testInsertion() throws IOException {
doTest(
"public class B {\n" +
" int a = 3;\n" +
" String text;\n" +
" Object last = null;\n" +
"}",
"public class B {\n" +
" int a = 3;\n" +
" int toIndent1 = 1;\n" +
" String text;\n" +
" int toIndent2\n" +
" Object last = null;\n" +
"}",
line(2, 2), line(4, 4)
);
}
private static ChangedLines line(int from, int to) {
return new ChangedLines(from, to);
}
public void testDeletion() throws IOException {
doTest(
"public class B {\n" +
" int a = 3;\n" +
" String text;\n" +
" Object last = null;\n" +
" Object first = null;\n" +
" Object second = null;\n" +
"}",
"public class B {\n" +
" int newInt = 1;\n" +
" Object last = null;\n" +
"}",
line(1, 1)
);
}
public void testModification() throws IOException {
doTest(
"public class B {\n" +
" int a = 3;\n" +
" String text;\n" +
" Object last = null;\n" +
" Object first = null;\n" +
" Object second = null;\n" +
"}",
"public class B {\n" +
" int a = 33;\n" +
" String text;\n" +
" Object last = new Object();\n" +
" Object first = null;\n" +
" Object second = new Object();\n" +
"}",
line(1, 1), line(3,3), line(5,5)
);
}
public void testReformatFiles() throws IOException {
ChangedFilesStructure fs = new ChangedFilesStructure(myWorkingDirectory);
PsiFile m1 = fs.createFile("Test1.java", COMMITTED, MODIFIED);
PsiFile u1 = fs.createFile("Test2.java", COMMITTED, COMMITTED);
fs.createDirectoryAndMakeItCurrent();
PsiFile m2 = fs.createFile("Test3.java", COMMITTED, MODIFIED);
PsiFile u2 = fs.createFile("Test4.java", COMMITTED, COMMITTED);
new ReformatCodeProcessor(getProject(), new PsiFile[] {m1, m2, u1, u2}, null, true).run();
assertFormattedLines(CHANGED_LINES, m1, m2);
assertFormattedLines(NO_CHANGED_LINES, u1, u2);
}
public void testNoChangesNoFormatting() throws IOException {
ChangedFilesStructure fs = new ChangedFilesStructure(myWorkingDirectory);
PsiFile u1 = fs.createFile("Test1.java", COMMITTED, COMMITTED);
PsiFile u2 = fs.createFile("Test2.java", COMMITTED, COMMITTED);
reformatDirectory(fs.getCurrentDirectory());
assertFormattedLines(NO_CHANGED_LINES, u1, u2);
}
public void testReformatOnlyChanged() throws IOException {
ChangedFilesStructure fs = new ChangedFilesStructure(myWorkingDirectory);
PsiFile untouched1 = fs.createFile("Test1.java", COMMITTED, COMMITTED);
PsiFile untouched2 = fs.createFile("Test2.java", COMMITTED, COMMITTED);
PsiFile modified1 = fs.createFile("Test4.java", COMMITTED, MODIFIED);
PsiFile modified2 = fs.createFile("Test5.java", COMMITTED, MODIFIED);
PsiFile modified3 = fs.createFile("Test6.java", COMMITTED, MODIFIED);
reformatDirectory(fs.getCurrentDirectory());
assertFormattedLines(CHANGED_LINES, modified1, modified2, modified3);
assertFormattedLines(NO_CHANGED_LINES, untouched1, untouched2);
}
public void testReformatInAllSubtree() throws IOException {
ChangedFilesStructure fs = new ChangedFilesStructure(myWorkingDirectory);
PsiFile modified11 = fs.createFile("Test4.java", COMMITTED, MODIFIED);
PsiFile modified12 = fs.createFile("Test5.java", COMMITTED, MODIFIED);
fs.createDirectoryAndMakeItCurrent();
PsiDirectory dirToReformat = fs.getCurrentDirectory();
PsiFile modified21 = fs.createFile("Test6.java", COMMITTED, MODIFIED);
PsiFile modified22 = fs.createFile("Test7.java", COMMITTED, MODIFIED);
fs.createDirectoryAndMakeItCurrent();
PsiFile modified31 = fs.createFile("Test8.java", COMMITTED, MODIFIED);
PsiFile modified32 = fs.createFile("Test9.java", COMMITTED, MODIFIED);
reformatDirectory(dirToReformat);
assertFormattedLines(CHANGED_LINES, modified21, modified22, modified31, modified32);
assertFormattedLines(NO_CHANGED_LINES, modified11, modified12);
}
private static void registerChangeListManager(@NotNull ChangeListManager manager) {
Project project = getProject();
assert (project instanceof ComponentManagerImpl);
ComponentManagerImpl projectComponentManager = (ComponentManagerImpl)project;
projectComponentManager.registerComponentInstance(ChangeListManager.class, manager);
}
private static void registerCodeStyleManager(@NotNull CodeStyleManager manager) {
String componentKey = CodeStyleManager.class.getName();
MutablePicoContainer container = (MutablePicoContainer)getProject().getPicoContainer();
container.unregisterComponent(componentKey);
container.registerComponentInstance(componentKey, manager);
}
private void doTest(@NotNull String committed, @NotNull String modified, @NotNull ChangedLines... lines) throws IOException {
ChangedFilesStructure fs = new ChangedFilesStructure(myWorkingDirectory);
PsiFile file = fs.createFile("Test.java", committed, modified);
reformatDirectory(myWorkingDirectory);
assertFormattedRangesEqualsTo(file, lines);
}
private void assertFormattedLines(@NotNull ChangedLines[] expectedLines, @NotNull PsiFile... files) {
for (PsiFile file : files)
assertFormattedRangesEqualsTo(file, expectedLines);
}
private void assertFormattedRangesEqualsTo(@NotNull PsiFile file, ChangedLines... expected) {
ChangedLines[] formatted = myMockCodeStyleManager.getFormattedLinesFor(file);
Comparator<ChangedLines> cmp = new Comparator<ChangedLines>() {
@Override
public int compare(ChangedLines o1, ChangedLines o2) {
return o1.from < o2.from ? -1 : 1;
}
};
Arrays.sort(expected, cmp);
Arrays.sort(formatted, cmp);
assertTrue(getErrorMessage(expected, formatted), Arrays.equals(expected, formatted));
}
@NotNull
private static String getErrorMessage(ChangedLines[] expected, ChangedLines[] actual) {
return "Expected: " + Arrays.toString(expected) + " Actual: " + Arrays.toString(actual);
}
private static void reformatDirectory(@NotNull PsiDirectory dir) {
ReformatCodeProcessor processor = new ReformatCodeProcessor(getProject(), dir, true, true);
processor.run();
}
class ChangedFilesStructure {
private TestFileStructure myFileStructure;
public ChangedFilesStructure(@NotNull PsiDirectory directory) {
myFileStructure = new TestFileStructure(getModule(), directory);
}
public void createDirectoryAndMakeItCurrent() throws IOException {
myFileStructure.createDirectoryAndMakeItCurrent("inner");
}
@NotNull
public PsiFile createFile(@NotNull String fileName,
@NotNull String committedContent,
@NotNull String actualContent) throws IOException
{
PsiFile file = myFileStructure.addTestFile(fileName, actualContent);
if (committedContent != actualContent) {
registerCommittedRevision(committedContent, file);
}
return file;
}
private void registerCommittedRevision(@NotNull String committedContent, @NotNull PsiFile... files) {
List<Change> changes = createChanges(committedContent, files);
injectChanges(changes);
}
@NotNull
private List<Change> createChanges(@NotNull String committed, @NotNull PsiFile... files) {
List<Change> changes = ContainerUtil.newArrayList();
for (PsiFile file : files) {
changes.add(createChange(committed, file));
}
return changes;
}
private void injectChanges(@NotNull List<Change> changes) {
Change[] arr = new Change[changes.size()];
ContainerUtil.toArray(changes, arr);
myMockChangeListManager.addChanges(arr);
}
@NotNull
private Change createChange(@NotNull String committed, @NotNull PsiFile file) {
FilePathImpl filePath = new FilePathImpl(file.getVirtualFile());
ContentRevision before = new SimpleContentRevision(committed, filePath, "");
ContentRevision after = new SimpleContentRevision("", filePath, "");
return new Change(before, after);
}
@NotNull
public PsiDirectory getCurrentDirectory() {
return myFileStructure.getCurrentDirectory();
}
}
}
@@ -0,0 +1,128 @@
/*
* 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.
* 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.codeInsight.actions;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.Result;
import com.intellij.openapi.application.WriteAction;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import com.intellij.psi.impl.file.PsiDirectoryFactory;
import com.intellij.testFramework.PsiTestUtil;
import org.jetbrains.annotations.NotNull;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class TestFileStructure {
private int myLevel;
@NotNull private Project myProject;
@NotNull private Module myModule;
@NotNull private PsiDirectory myCurrentLevelDirectory;
private List<List<PsiFile>> myFilesForLevel = new ArrayList<List<PsiFile>>();
public TestFileStructure(@NotNull Module module, @NotNull PsiDirectory root) {
myProject = module.getProject();
myModule = module;
myCurrentLevelDirectory = root;
myFilesForLevel.add(new ArrayList<PsiFile>());
myLevel = 0;
}
@NotNull
public PsiFile addTestFile(@NotNull String name, @NotNull String content) throws IOException {
PsiFile createdFile = createFile(myModule, myCurrentLevelDirectory.getVirtualFile(), name, content);
getCurrentDirectoryFiles().add(createdFile);
return createdFile;
}
@NotNull
public List<PsiFile> getCurrentDirectoryFiles() {
return myFilesForLevel.get(myLevel);
}
@NotNull
public PsiDirectory getCurrentDirectory() {
return myCurrentLevelDirectory;
}
@NotNull
public TestFileStructure createDirectoryAndMakeItCurrent(String name) throws IOException {
myLevel++;
myFilesForLevel.add(new ArrayList<PsiFile>());
myCurrentLevelDirectory = createDirectory(myProject, myCurrentLevelDirectory.getVirtualFile(), name);
return this;
}
public List<PsiFile> getFilesAtLevel(int level) {
assert (myLevel >= level);
return myFilesForLevel.get(level);
}
private PsiFile createFile(final Module module, final VirtualFile vDir, final String fileName, final String text) {
return new WriteAction<PsiFile>() {
@Override
protected void run(@NotNull Result<PsiFile> result) throws Throwable {
if (!ModuleRootManager.getInstance(module).getFileIndex().isInSourceContent(vDir)) {
PsiTestUtil.addSourceContentToRoots(module, vDir);
}
final VirtualFile vFile = vDir.createChildData(vDir, fileName);
VfsUtil.saveText(vFile, text);
final PsiFile file = PsiManager.getInstance(myProject).findFile(vFile);
assert (file != null);
result.setResult(file);
}
}.execute().getResultObject();
}
public static PsiDirectory createDirectory(@NotNull Project project, @NotNull final VirtualFile parent, @NotNull final String name) throws IOException {
final VirtualFile[] dir = new VirtualFile[1];
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
try {
dir[0] = parent.createChildDirectory(null, name);
}
catch (IOException e) {
e.printStackTrace();
}
}
});
return PsiDirectoryFactory.getInstance(project).createDirectory(dir[0]);
}
public static void delete(@NotNull final VirtualFile file) {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
try {
file.delete(null);
}
catch (IOException e) {
e.printStackTrace();
}
}
});
}
}
@@ -78,7 +78,7 @@ public abstract class BreakpointBase<L> extends Breakpoint {
return this;
}
enabled = value;
dirty = true;
dirty = true;
return this;
}
@@ -1,11 +1,7 @@
package org.jetbrains.debugger;
import com.intellij.openapi.util.AsyncResult;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.debugger.values.FunctionValue;
import org.jetbrains.debugger.values.ObjectValue;
import org.jetbrains.debugger.values.Value;
/**
* Exposes additional data if variable is a property of object and its property descriptor
@@ -38,10 +34,4 @@ public interface ObjectProperty extends Variable {
* @return whether property described as 'enumerable'
*/
boolean isEnumerable();
/**
* Asynchronously evaluates property getter and returns property value
*/
@NotNull
AsyncResult<Value> evaluateGet(@NotNull ObjectValue host, @NotNull EvaluateContext evaluateContext);
}
@@ -16,7 +16,7 @@ public final class StandaloneVmHelper extends MessageWriter {
private final VmEx vm;
public StandaloneVmHelper(VmEx vm) {
public StandaloneVmHelper(@NotNull VmEx vm) {
this.vm = vm;
}
@@ -1,6 +1,7 @@
package org.jetbrains.debugger;
import com.intellij.openapi.util.ActionCallback;
import com.intellij.openapi.util.AsyncResult;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.debugger.values.Value;
@@ -13,4 +14,7 @@ public interface ValueModifier {
ActionCallback setValue(@NotNull Variable variable, String newValue, @NotNull EvaluateContext evaluateContext);
ActionCallback setValue(@NotNull Variable variable, Value newValue, @NotNull EvaluateContext evaluateContext);
@NotNull
AsyncResult<Value> evaluateGet(@NotNull ObjectProperty property, @NotNull EvaluateContext evaluateContext);
}
@@ -153,9 +153,9 @@ public final class VariableView extends XNamedValue implements VariableContext {
node.setFullValueEvaluator(new XFullValueEvaluator(" (invoke getter)") {
@Override
public void startEvaluation(@NotNull final XFullValueEvaluationCallback callback) {
ObjectValue host = (ObjectValue)((VariableView)context).getValue();
assert host != null;
ObsolescentAsyncResults.consume(((ObjectProperty)variable).evaluateGet(host, getEvaluateContext()), node, new PairConsumer<Value, XValueNode>() {
ValueModifier valueModifier = variable.getValueModifier();
assert valueModifier != null;
ObsolescentAsyncResults.consume(valueModifier.evaluateGet((ObjectProperty)variable, getEvaluateContext()), node, new PairConsumer<Value, XValueNode>() {
@Override
public void consume(Value value, XValueNode node) {
callback.evaluated("");
@@ -70,7 +70,7 @@ public abstract class VmConnection<T extends Vm> implements Disposable, BrowserC
started.setDone();
}
public final void close(@Nullable String message) {
public final void close(@Nullable String message, @NotNull ConnectionStatus status) {
if (!closed.compareAndSet(false, true)) {
return;
}
@@ -79,7 +79,7 @@ public abstract class VmConnection<T extends Vm> implements Disposable, BrowserC
if (!started.isProcessed()) {
started.setRejected();
}
setState(ConnectionStatus.DISCONNECTED, message);
setState(status, message);
Disposer.dispose(this, false);
}
@@ -101,7 +101,7 @@ public abstract class VmConnection<T extends Vm> implements Disposable, BrowserC
vm = null;
callback = currentVm.detach();
}
close(null);
close(null, ConnectionStatus.DISCONNECTED);
return callback;
}
}
@@ -70,7 +70,7 @@ class Generator {
}
private static boolean isDomainSkipped(Domain domain) {
if (domain.domain().equals("CSS")) {
if (domain.domain().equals("CSS") || domain.domain().equals("Inspector")) {
return false;
}
@@ -13,29 +13,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.ide.startupWizardV2;
package com.intellij.openapi.util;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
public abstract class AbstractWizardPage extends JPanel {
public AbstractWizardPage() {
/**
* @author Konstantin Bulenkov
*/
public class Couple<T> extends Pair<T, T> {
public Couple(T first, T second) {
super(first, second);
}
@NotNull
abstract String getID();
@NotNull
abstract String getTitle();
@NotNull
String getHeader() {
return "&nbsp;";
}
@NotNull
String getFooter() {
return "&nbsp;";
public static <T> Couple<T> newOne(T first, T second) {
return new Couple<T>(first, second);
}
}
@@ -188,18 +188,7 @@ public class PersistentHashMap<Key, Value> extends PersistentEnumeratorDelegate<
}
private SLRUCache<Key, BufferExposingByteArrayOutputStream> createAppendCache(final KeyDescriptor<Key> keyDescriptor) {
final EqualityPolicy<Key> hashingStrategy = new EqualityPolicy<Key>() {
@Override
public int getHashCode(Key object) {
return keyDescriptor.getHashCode(object);
}
@Override
public boolean isEqual(Key val1, Key val2) {
return keyDescriptor.isEqual(val1, val2);
}
};
return new SLRUCache<Key, BufferExposingByteArrayOutputStream>(16 * 1024, 4 * 1024, hashingStrategy) {
return new SLRUCache<Key, BufferExposingByteArrayOutputStream>(16 * 1024, 4 * 1024, keyDescriptor) {
@Override
@NotNull
public BufferExposingByteArrayOutputStream createValue(final Key key) {
@@ -20,6 +20,7 @@ import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.JBColor;
import com.intellij.util.NotNullFunction;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.hash.LinkedHashMap;
import com.intellij.vcs.log.Hash;
import com.intellij.vcs.log.VcsLogRefManager;
import com.intellij.vcs.log.VcsRef;
@@ -39,6 +40,14 @@ public class GraphColorManagerImpl implements GraphColorManager {
@NotNull private final NotNullFunction<Integer, Hash> myHashGetter;
@NotNull private final Map<VirtualFile, VcsLogRefManager> myRefManagers;
@NotNull private final LinkedHashMap<Integer, Integer> myErrorWasReported = new LinkedHashMap<Integer, Integer>(10) {
@Override
protected boolean removeEldestEntry(Map.Entry<Integer, Integer> eldest) {
return size() > 100;
}
};
public GraphColorManagerImpl(@NotNull RefsModel refsModel, @NotNull NotNullFunction<Integer, Hash> hashGetter,
@NotNull Map<VirtualFile, VcsLogRefManager> refManagers) {
myRefsModel = refsModel;
@@ -61,7 +70,10 @@ public class GraphColorManagerImpl implements GraphColorManager {
private boolean checkEmptiness(@NotNull Collection<VcsRef> refs, int head) {
if (refs.isEmpty()) {
LOG.error("No references found at head " + head + " which corresponds to hash " + myHashGetter.fun(head));
if (!myErrorWasReported.containsKey(head)) {
myErrorWasReported.put(head, head);
LOG.error("No references found at head " + head + " which corresponds to hash " + myHashGetter.fun(head));
}
return false;
}
return true;
@@ -5,7 +5,6 @@ import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.JBColor;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.ui.UIUtil;
import com.intellij.vcs.log.ui.tables.AbstractVcsLogTableModel;
import org.jetbrains.annotations.NotNull;
import java.awt.*;
@@ -60,9 +59,6 @@ public class VcsLogColorManagerImpl implements VcsLogColorManager {
@NotNull
@Override
public Color getRootColor(@NotNull VirtualFile root) {
if (root == AbstractVcsLogTableModel.FAKE_ROOT) {
return getDefaultRootColor();
}
Color color = myRoots2Colors.get(root);
if (color == null) {
LOG.error("No color record for root " + root + ". All roots: " + myRoots2Colors);
@@ -23,8 +23,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
public abstract class AbstractVcsLogTableModel<CommitColumnClass> extends AbstractTableModel {
public static final VirtualFile FAKE_ROOT = NullVirtualFile.INSTANCE;
public static final int ROOT_COLUMN = 0;
public static final int COMMIT_COLUMN = 1;
public static final int AUTHOR_COLUMN = 2;
@@ -22,8 +22,8 @@ import com.intellij.vcs.log.VcsShortCommitDetails;
import com.intellij.vcs.log.data.DataPack;
import com.intellij.vcs.log.data.LoadMoreStage;
import com.intellij.vcs.log.data.VcsLogDataHolder;
import com.intellij.vcs.log.ui.render.GraphCommitCell;
import com.intellij.vcs.log.ui.VcsLogUiImpl;
import com.intellij.vcs.log.ui.render.GraphCommitCell;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -44,7 +44,7 @@ public class EmptyTableModel extends AbstractVcsLogTableModel<GraphCommitCell> {
@NotNull
@Override
public VirtualFile getRoot(int rowIndex) {
return FAKE_ROOT;
throw new AssertionError("Root shouldn't be requested for empty table model. row: " + rowIndex);
}
@NotNull
@@ -61,7 +61,8 @@ public class GraphTableModel extends AbstractVcsLogTableModel<GraphCommitCell> {
Collection<VcsRef> refs = myDataPack.getRefsModel().refsToCommit(head);
if (refs.isEmpty()) {
LOG.error("No references pointing to head " + head + " identified for commit at row " + rowIndex);
return FAKE_ROOT;
// take the first root: it is the right choice in one-repo case, though it will likely fail in multi-repo case
return myDataPack.getLogProviders().keySet().iterator().next();
}
return refs.iterator().next().getRoot();
}
@@ -94,7 +94,7 @@ public class UnnecessarilyQualifiedStaticallyImportedElementInspection extends B
if (!(qualifier instanceof PsiJavaCodeReferenceElement)) {
return;
}
if (PsiTreeUtil.getParentOfType(reference, PsiReferenceExpression.class, PsiImportStatementBase.class) != null) {
if (PsiTreeUtil.getParentOfType(reference, PsiImportStatementBase.class) != null) {
return;
}
if (UnnecessarilyQualifiedStaticUsageInspection.isGenericReference(reference, (PsiJavaCodeReferenceElement)qualifier)) return;
@@ -0,0 +1,8 @@
<problems>
<problem>
<file>Test.java</file>
<line>7</line>
<problem_class severity="WARNING" attribute_key="NOT_USED_ELEMENT_ATTRIBUTES">Unnecessarily qualified statically imported element</problem_class>
<description>Statically imported element 'foo' is unnecessarily qualified with &lt;code&gt;A&lt;/code&gt; #loc</description>
</problem>
</problems>
@@ -0,0 +1,13 @@
package p;
import static p.A.foo;
class StaticImport {
void example() {
A.foo().toString();
}
}
class A {
static Object foo() {return null;}
}
@@ -21,7 +21,7 @@ public class UnnecessarilyQualifiedStaticallyImportedElementInspectionTest
extends IGInspectionTestCase {
public void test() throws Exception {
doTest("com/siyeh/igtest/style/unnecessarily_qualified_statically_imported_element",
doTest("com/siyeh/igtest/style/unnecessarily_qualified_statically_imported_element/simple",
new UnnecessarilyQualifiedStaticallyImportedElementInspection());
}
@@ -33,6 +33,10 @@ public class UnnecessarilyQualifiedStaticallyImportedElementInspectionTest
doTest(getTestName(true));
}
public void testChainedMethodCall() throws Exception {
doTest(getTestName(true));
}
private void doTest(String testName) throws Exception {
doTest("com/siyeh/igtest/style/unnecessarily_qualified_statically_imported_element/" + testName,
new UnnecessarilyQualifiedStaticallyImportedElementInspection());
@@ -90,8 +90,8 @@ public final class AntBuildMessageView extends JPanel implements DataProvider, O
private AntBuildFileBase myBuildFile;
private final String[] myTargets;
private int myPriorityThreshold = PRIORITY_BRIEF;
private int myErrorCount;
private int myWarningCount;
private volatile int myErrorCount;
private volatile int myWarningCount;
private volatile boolean myIsOutputPaused = false;
@NotNull
@@ -109,7 +109,7 @@ public final class AntBuildMessageView extends JPanel implements DataProvider, O
private final Runnable myFlushLogRunnable = new Runnable() {
@Override
public void run() {
if (myTreeView != null && myCommandsProcessedCount < myLog.size()) {
if (myCommandsProcessedCount < myLog.size()) {
if (!myIsOutputPaused) {
new OutputFlusher().doFlush();
myTreeView.scrollToLastMessage();
@@ -47,7 +47,7 @@ public class OutputParser{
private final WeakReference<ProgressIndicator> myProgress;
private final String myBuildName;
private final OSProcessHandler myProcessHandler;
private boolean isStopped;
private volatile boolean isStopped;
private List<String> myJavacMessages;
private boolean myFirstLineProcessed;
private boolean myStartedSuccessfully;
@@ -66,6 +66,13 @@
bundle="org.jetbrains.idea.devkit.DevKitBundle"
groupKey="inspections.group.name" enabledByDefault="true" level="WARNING"
implementationClass="org.jetbrains.idea.devkit.inspections.IntentionDescriptionNotFoundInspection"/>
<localInspection language="JAVA"
key="inspections.component.postfix.template.not.found.description.name"
bundle="org.jetbrains.idea.devkit.DevKitBundle"
groupKey="inspections.group.name"
enabledByDefault="true"
level="WARNING"
implementationClass="org.jetbrains.idea.devkit.inspections.PostfixTemplateDescriptionNotFoundInspection"/>
<localInspection shortName="ComponentRegistrationProblems"
bundle="org.jetbrains.idea.devkit.DevKitBundle" key="inspections.registration.problems.name"
groupKey="inspections.group.name"
@@ -0,0 +1,5 @@
<html>
<body>
Checks if postfix template (completion) has a description.
</body>
</html>
@@ -147,6 +147,9 @@ inspections.component.not.registered.option.ignore.non.public=Ignore non-public
inspections.component.not.registered.quickfix.family=Register Component
inspections.component.not.registered.quickfix.name=Register {0}
inspections.component.not.registered.quickfix.error=Cannot Register {0}
inspections.component.postfix.template.not.found.description.name=Postfix template Description Checker
InspectionUseGrayColor=Use Gray
ant.build.jar.comment=Build archive for plugin ''{0}''
ant.build.jar.description=Build plugin archive for module ''{0}''
@@ -0,0 +1,135 @@
/*
* 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.
* 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 org.jetbrains.idea.devkit.inspections;
import com.intellij.codeInspection.InspectionManager;
import com.intellij.codeInspection.LocalQuickFix;
import com.intellij.codeInspection.ProblemDescriptor;
import com.intellij.codeInspection.ProblemHighlightType;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleUtilCore;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.devkit.inspections.quickfix.CreateHtmlDescriptionFix;
import org.jetbrains.idea.devkit.util.PsiUtil;
abstract class DescriptionNotFoundInspectionBase extends DevKitInspectionBase {
@Override
public ProblemDescriptor[] checkClass(@NotNull PsiClass aClass, @NotNull InspectionManager manager, boolean isOnTheFly) {
final Project project = aClass.getProject();
final PsiIdentifier nameIdentifier = aClass.getNameIdentifier();
final Module module = ModuleUtilCore.findModuleForPsiElement(aClass);
if (nameIdentifier == null || module == null || !PsiUtil.isInstantiable(aClass)) return null;
final PsiClass base = JavaPsiFacade.getInstance(project).findClass(getClassName(), GlobalSearchScope.allScope(project));
if (base == null || !aClass.isInheritor(base, true)) return null;
String descriptionDir = getDescriptionDirName(aClass);
if (StringUtil.isEmptyOrSpaces(descriptionDir)) {
return null;
}
for (PsiDirectory description : getDescriptionsDirs(module)) {
PsiDirectory dir = description.findSubdirectory(descriptionDir);
if (dir == null) continue;
final PsiFile descr = dir.findFile("description.html");
if (descr != null) {
if (!hasBeforeAndAfterTemplate(dir.getVirtualFile())) {
PsiElement problem = aClass.getNameIdentifier();
ProblemDescriptor problemDescriptor = manager.createProblemDescriptor(problem == null ? nameIdentifier : problem,
getHasNotBeforeAfterError(),
isOnTheFly,
ProblemHighlightType.GENERIC_ERROR_OR_WARNING, false);
return new ProblemDescriptor[]{problemDescriptor};
}
return null;
}
}
final PsiElement problem = aClass.getNameIdentifier();
final ProblemDescriptor problemDescriptor = manager
.createProblemDescriptor(problem == null ? nameIdentifier : problem,
getHasNotDescriptionError(), isOnTheFly, new LocalQuickFix[]{getFix(module, descriptionDir)},
ProblemHighlightType.GENERIC_ERROR_OR_WARNING);
return new ProblemDescriptor[]{problemDescriptor};
}
protected CreateHtmlDescriptionFix getFix(Module module, String descriptionDir) {
return new CreateHtmlDescriptionFix(descriptionDir, module, true);
}
@Nullable
private static String getDescriptionDirName(PsiClass aClass) {
String descriptionDir = "";
PsiClass each = aClass;
while (each != null) {
String name = each.getName();
if (StringUtil.isEmptyOrSpaces(name)) {
return null;
}
descriptionDir = name + descriptionDir;
each = each.getContainingClass();
}
return descriptionDir;
}
private static boolean hasBeforeAndAfterTemplate(@NotNull VirtualFile dir) {
boolean hasBefore = false;
boolean hasAfter = false;
for (VirtualFile file : dir.getChildren()) {
String name = file.getName();
if (name.endsWith(".template")) {
if (name.startsWith("before.")) {
hasBefore = true;
}
else if (name.startsWith("after.")) {
hasAfter = true;
}
}
}
return hasBefore && hasAfter;
}
@Override
public boolean isEnabledByDefault() {
return true;
}
@NotNull
protected abstract String getClassName();
@NotNull
protected abstract String getHasNotDescriptionError();
@NotNull
protected abstract String getHasNotBeforeAfterError();
@NotNull
protected abstract PsiDirectory[] getDescriptionsDirs(@NotNull Module module);
}
@@ -15,118 +15,57 @@
*/
package org.jetbrains.idea.devkit.inspections;
import com.intellij.codeInspection.InspectionManager;
import com.intellij.codeInspection.LocalQuickFix;
import com.intellij.codeInspection.ProblemDescriptor;
import com.intellij.codeInspection.ProblemHighlightType;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleUtil;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.JavaPsiFacade;
import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiPackage;
import com.intellij.psi.search.GlobalSearchScope;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.devkit.inspections.quickfix.CreateHtmlDescriptionFix;
import org.jetbrains.idea.devkit.util.PsiUtil;
/**
* @author Konstantin Bulenkov
*/
public class IntentionDescriptionNotFoundInspection extends DevKitInspectionBase{
public class IntentionDescriptionNotFoundInspection extends DescriptionNotFoundInspectionBase {
@NonNls private static final String INTENTION = "com.intellij.codeInsight.intention.IntentionAction";
@NonNls private static final String INSPECTION_DESCRIPTIONS = "intentionDescriptions";
@Override
public ProblemDescriptor[] checkClass(@NotNull PsiClass aClass, @NotNull InspectionManager manager, boolean isOnTheFly) {
final Project project = aClass.getProject();
final PsiIdentifier nameIdentifier = aClass.getNameIdentifier();
final Module module = ModuleUtil.findModuleForPsiElement(aClass);
if (nameIdentifier == null || module == null || !PsiUtil.isInstantiable(aClass)) return null;
final PsiClass base = JavaPsiFacade.getInstance(project).findClass(INTENTION, GlobalSearchScope.allScope(project));
if (base == null || ! aClass.isInheritor(base, true)) return null;
String descriptionDir = getDescriptionDirName(aClass);
if (StringUtil.isEmptyOrSpaces(descriptionDir)) {
return null;
}
for (PsiDirectory description : getIntentionDescriptionsDirs(module)) {
PsiDirectory dir = description.findSubdirectory(descriptionDir);
if (dir == null) continue;
final PsiFile descr = dir.findFile("description.html");
if (descr != null) {
if (!hasBeforeAndAfterTemplate(dir.getVirtualFile())) {
PsiElement problem = aClass.getNameIdentifier();
ProblemDescriptor problemDescriptor = manager.createProblemDescriptor(problem == null ? nameIdentifier : problem,
"Intention must have 'before.*.template' and 'after.*.template' beside 'description.html'",
isOnTheFly,
ProblemHighlightType.GENERIC_ERROR_OR_WARNING, false);
return new ProblemDescriptor[]{problemDescriptor};
}
return null;
}
}
final PsiElement problem = aClass.getNameIdentifier();
final ProblemDescriptor problemDescriptor = manager
.createProblemDescriptor(problem == null ? nameIdentifier : problem,
"Intention does not have a description", isOnTheFly, new LocalQuickFix[]{new CreateHtmlDescriptionFix(descriptionDir, module, true)},
ProblemHighlightType.GENERIC_ERROR_OR_WARNING);
return new ProblemDescriptor[]{problemDescriptor};
protected CreateHtmlDescriptionFix getFix(Module module, String descriptionDir) {
return new CreateHtmlDescriptionFix(descriptionDir, module, true);
}
@Nullable
private static String getDescriptionDirName(PsiClass aClass) {
String descriptionDir = "";
PsiClass each = aClass;
while (each != null) {
String name = each.getName();
if (StringUtil.isEmptyOrSpaces(name)) {
return null;
}
descriptionDir = name + descriptionDir;
each = each.getContainingClass();
}
return descriptionDir;
@NotNull
protected String getClassName() {
return INTENTION;
}
private static boolean hasBeforeAndAfterTemplate(@NotNull VirtualFile dir) {
boolean hasBefore = false;
boolean hasAfter = false;
@NotNull
protected String getHasNotDescriptionError() {
return "Intention does not have a description";
}
for (VirtualFile file : dir.getChildren()) {
String name = file.getName();
if (name.endsWith(".template")) {
if (name.startsWith("before.")) {
hasBefore = true;
}
else if (name.startsWith("after.")) {
hasAfter = true;
}
}
}
return hasBefore && hasAfter;
@NotNull
protected String getHasNotBeforeAfterError() {
return "Intention must have 'before.*.template' and 'after.*.template' beside 'description.html'";
}
public static PsiDirectory[] getIntentionDescriptionsDirs(Module module) {
final PsiPackage aPackage = JavaPsiFacade.getInstance(module.getProject()).findPackage(INSPECTION_DESCRIPTIONS);
if (aPackage != null) {
return aPackage.getDirectories(GlobalSearchScope.moduleWithDependenciesScope(module));
} else {
}
else {
return PsiDirectory.EMPTY_ARRAY;
}
}
@NotNull
protected PsiDirectory[] getDescriptionsDirs(@NotNull Module module) {
return getIntentionDescriptionsDirs(module);
}
@Nls
@NotNull
public String getDisplayName() {
@@ -137,9 +76,4 @@ public class IntentionDescriptionNotFoundInspection extends DevKitInspectionBase
public String getShortName() {
return "IntentionDescriptionNotFoundInspection";
}
@Override
public boolean isEnabledByDefault() {
return true;
}
}
@@ -0,0 +1,86 @@
/*
* 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.
* 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 org.jetbrains.idea.devkit.inspections;
import com.intellij.openapi.module.Module;
import com.intellij.psi.JavaPsiFacade;
import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiPackage;
import com.intellij.psi.search.GlobalSearchScope;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.idea.devkit.DevKitBundle;
import org.jetbrains.idea.devkit.inspections.quickfix.CreateHtmlDescriptionFix;
import org.jetbrains.idea.devkit.inspections.quickfix.CreatePostfixTemplateHtmlDescriptionFix;
public class PostfixTemplateDescriptionNotFoundInspection extends DescriptionNotFoundInspectionBase {
private static final String POSTFIX_TEMPLATES = "postfixTemplates";
@NotNull
@Override
protected PsiDirectory[] getDescriptionsDirs(@NotNull Module module) {
return getPostfixTemplateDirectories(module);
}
@Override
protected CreateHtmlDescriptionFix getFix(Module module, String descriptionDir) {
return new CreatePostfixTemplateHtmlDescriptionFix(descriptionDir, module);
}
@NotNull
public static PsiDirectory[] getPostfixTemplateDirectories(Module module) {
final PsiPackage aPackage = JavaPsiFacade.getInstance(module.getProject()).findPackage(POSTFIX_TEMPLATES);
if (aPackage != null) {
return aPackage.getDirectories(GlobalSearchScope.moduleWithDependenciesScope(module));
}
else {
return PsiDirectory.EMPTY_ARRAY;
}
}
@NotNull
@Override
protected String getHasNotDescriptionError() {
return "Postfix template does not have a description";
}
@NotNull
@Override
protected String getHasNotBeforeAfterError() {
return "Postfix template must have 'before.*.template' and 'after.*.template' beside 'description.html'";
}
@NotNull
@Override
protected String getClassName() {
return "com.intellij.codeInsight.template.postfix.templates.PostfixTemplate";
}
@Nls
@NotNull
@Override
public String getDisplayName() {
return DevKitBundle.message("inspections.component.postfix.template.not.found.description.name");
}
@NotNull
@Override
public String getShortName() {
return "PostfixTemplateDescriptionNotFound";
}
}
@@ -57,75 +57,15 @@ import java.util.List;
* @author Konstantin Bulenkov
*/
public class CreateHtmlDescriptionFix implements LocalQuickFix, Iconable {
private final String myFilename;
private final Module myModule;
@NonNls private static final String TEMPLATE_NAME = "InspectionDescription.html";
private final String myFilename;
protected final Module myModule;
private final boolean isIntention;
public CreateHtmlDescriptionFix(String filename, Module module, boolean isIntention) {
myModule = module;
this.isIntention = isIntention;
myFilename = isIntention ? filename : filename + ".html";
}
@NotNull
public String getName() {
return DevKitBundle.message("create.description.file");
}
@NotNull
public String getFamilyName() {
return "DevKit";
}
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
final PsiDirectory[] dirs;
if (isIntention) {
dirs = IntentionDescriptionNotFoundInspection.getIntentionDescriptionsDirs(myModule);
}
else {
dirs = InspectionDescriptionNotFoundInspection.getInspectionDescriptionsDirs(myModule);
}
final List<VirtualFile> virtualFiles = getPotentialRoots(myModule, dirs);
final VirtualFile[] roots = prepare(VfsUtil.toVirtualFileArray(virtualFiles));
if (roots.length == 1) {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
public void run() {
createDescription(roots[0]);
}
});
}
else {
List<String> options = new ArrayList<String>();
for (VirtualFile file : roots) {
String path = file.getPresentableUrl() + File.separator + getDescriptionFolderName() + File.separator + myFilename;
if (isIntention) {
path += File.separator + "description.html";
}
options.add(path);
}
final JBList files = new JBList(ArrayUtil.toStringArray(options));
files.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
final JBPopup popup = JBPopupFactory.getInstance()
.createListPopupBuilder(files)
.setTitle(DevKitBundle.message("select.target.location.of.description", myFilename))
.setItemChoosenCallback(new Runnable() {
public void run() {
final int index = files.getSelectedIndex();
if (0 <= index && index < roots.length) {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
public void run() {
createDescription(roots[index]);
}
});
}
}
}).createPopup();
final Editor editor = FileEditorManager.getInstance(myModule.getProject()).getSelectedTextEditor();
if (editor == null) return;
popup.showInBestPositionFor(editor);
}
myFilename = getNormalizedFileName(filename);
}
private static List<VirtualFile> getPotentialRoots(Module module, PsiDirectory[] dirs) {
@@ -147,6 +87,80 @@ public class CreateHtmlDescriptionFix implements LocalQuickFix, Iconable {
}
}
private String getNormalizedFileName(String filename) {
return isIntention ? filename : filename + ".html";
}
@NotNull
public String getName() {
return DevKitBundle.message("create.description.file");
}
@NotNull
public String getFamilyName() {
return "DevKit";
}
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
final PsiDirectory[] dirs;
dirs = getDirectories();
final List<VirtualFile> virtualFiles = getPotentialRoots(myModule, dirs);
final VirtualFile[] roots = prepare(VfsUtil.toVirtualFileArray(virtualFiles));
if (roots.length == 1) {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
public void run() {
createDescription(roots[0]);
}
});
}
else {
List<String> options = new ArrayList<String>();
for (VirtualFile file : roots) {
String path = getPath(file);
options.add(path);
}
final JBList files = new JBList(ArrayUtil.toStringArray(options));
files.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
final JBPopup popup = JBPopupFactory.getInstance()
.createListPopupBuilder(files)
.setTitle(DevKitBundle.message("select.target.location.of.description", myFilename))
.setItemChoosenCallback(new Runnable() {
public void run() {
final int index = files.getSelectedIndex();
if (0 <= index && index < roots.length) {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
public void run() {
createDescription(roots[index]);
}
});
}
}
}).createPopup();
final Editor editor = FileEditorManager.getInstance(myModule.getProject()).getSelectedTextEditor();
if (editor == null) return;
popup.showInBestPositionFor(editor);
}
}
private String getPath(VirtualFile file) {
String path = file.getPresentableUrl() + File.separator + getDescriptionFolderName() + File.separator + myFilename;
if (isIntention) {
path += File.separator + "description.html";
}
return path;
}
protected PsiDirectory[] getDirectories() {
PsiDirectory[] dirs;
if (isIntention) {
dirs = IntentionDescriptionNotFoundInspection.getIntentionDescriptionsDirs(myModule);
}
else {
dirs = InspectionDescriptionNotFoundInspection.getInspectionDescriptionsDirs(myModule);
}
return dirs;
}
private void createDescription(VirtualFile root) {
if (!root.isDirectory()) return;
final PsiManager psiManager = PsiManager.getInstance(myModule.getProject());
@@ -169,7 +183,8 @@ public class CreateHtmlDescriptionFix implements LocalQuickFix, Iconable {
}
}
final FileTemplate descrTemplate = FileTemplateManager.getInstance().getJ2eeTemplate(TEMPLATE_NAME);
final PsiElement template = FileTemplateUtil.createFromTemplate(descrTemplate, isIntention? "description.html" : myFilename, null, descrRoot);
final PsiElement template =
FileTemplateUtil.createFromTemplate(descrTemplate, getNewFileName(), null, descrRoot);
if (template instanceof PsiFile) {
final VirtualFile file = ((PsiFile)template).getVirtualFile();
if (file != null) {
@@ -181,6 +196,10 @@ public class CreateHtmlDescriptionFix implements LocalQuickFix, Iconable {
}
}
private String getNewFileName() {
return isIntention ? "description.html" : myFilename;
}
public Icon getIcon(int flags) {
return new LayeredIcon(AllIcons.FileTypes.Html, AllIcons.Actions.New);
}
@@ -205,7 +224,7 @@ public class CreateHtmlDescriptionFix implements LocalQuickFix, Iconable {
return false;
}
private String getDescriptionFolderName() {
protected String getDescriptionFolderName() {
return isIntention ? "intentionDescriptions" : "inspectionDescriptions";
}
}
@@ -0,0 +1,39 @@
/*
* 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.
* 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 org.jetbrains.idea.devkit.inspections.quickfix;
import com.intellij.openapi.module.Module;
import com.intellij.psi.PsiDirectory;
import org.jetbrains.idea.devkit.inspections.PostfixTemplateDescriptionNotFoundInspection;
public class CreatePostfixTemplateHtmlDescriptionFix extends CreateHtmlDescriptionFix {
public CreatePostfixTemplateHtmlDescriptionFix(String filename, Module module) {
super(filename, module, true);
}
@Override
protected PsiDirectory[] getDirectories() {
return PostfixTemplateDescriptionNotFoundInspection.getPostfixTemplateDirectories(myModule);
}
@Override
protected String getDescriptionFolderName() {
return "postfixTemplates";
}
}
@@ -0,0 +1,6 @@
import com.intellij.codeInsight.template.postfix.templates.PostfixTemplate;
public class <caret>MyQuickFixTemplate extends PostfixTemplate {
}
@@ -0,0 +1,6 @@
import com.intellij.codeInsight.template.postfix.templates.PostfixTemplate;
public class <warning descr="Postfix template does not have a description">MyTemplate</warning> extends PostfixTemplate {
}
@@ -0,0 +1,6 @@
import com.intellij.codeInsight.template.postfix.templates.PostfixTemplate;
public class MyTemplateWithDescription extends PostfixTemplate {
}
@@ -0,0 +1,6 @@
import com.intellij.codeInsight.template.postfix.templates.PostfixTemplate;
public class <warning descr="Postfix template must have 'before.*.template' and 'after.*.template' beside 'description.html'">MyTemplateWithoutBeforeAfter</warning> extends PostfixTemplate{
}
@@ -0,0 +1,61 @@
/*
* 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.
* 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 org.jetbrains.idea.devkit.codeInsight;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.openapi.application.PluginPathManager;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.testFramework.fixtures.JavaCodeInsightFixtureTestCase;
import org.jetbrains.idea.devkit.inspections.PostfixTemplateDescriptionNotFoundInspection;
public class PostfixTemplateInspectionTest extends JavaCodeInsightFixtureTestCase {
@Override
protected String getBasePath() {
return PluginPathManager.getPluginHomePathRelative("devkit") + "/testData/codeInsight/postfixTemplates";
}
@Override
protected void setUp() throws Exception {
super.setUp();
myFixture.enableInspections(PostfixTemplateDescriptionNotFoundInspection.class);
myFixture.addClass("package com.intellij.codeInsight.template.postfix.templates; public class PostfixTemplate {}");
}
public void testHighlightingForDescription() {
myFixture.testHighlighting("MyTemplate.java");
}
public void testNoHighlighting() {
myFixture.copyDirectoryToProject("postfixTemplates", "postfixTemplates");
myFixture.testHighlighting("MyTemplateWithDescription.java");
}
public void testHighlightingForBeforeAfter() {
myFixture.copyDirectoryToProject("postfixTemplates", "postfixTemplates");
myFixture.testHighlighting("MyTemplateWithoutBeforeAfter.java");
}
public void testQuickFix() {
myFixture.configureByFiles("MyQuickFixTemplate.java");
IntentionAction item = myFixture.findSingleIntention("Create Description File");
myFixture.launchAction(item);
VirtualFile path = myFixture.findFileInTempDir("postfixTemplates/MyQuickFixTemplate/description.html");
assertNotNull(path);
assertTrue(path.exists());
}
}
@@ -228,7 +228,11 @@ public class GitBranchUtil {
String branchName = stdName.substring(slash + 1);
GitRemote remote = findRemoteByName(remoteName, remotes);
if (remote == null) {
return null;
// user may remove the remote section from .git/config, but leave remote refs untouched in .git/refs/remotes
LOG.info(String.format("No remote found with the name [%s]. All remotes: %s", remoteName, remotes));
GitRemote fakeRemote = new GitRemote(remoteName, ContainerUtil.<String>emptyList(), Collections.<String>emptyList(),
Collections.<String>emptyList(), Collections.<String>emptyList());
return new GitStandardRemoteBranch(fakeRemote, branchName, hash);
}
return new GitStandardRemoteBranch(remote, branchName, hash);
}
@@ -241,8 +245,6 @@ public class GitBranchUtil {
return remote;
}
}
// user may remove the remote section from .git/config, but leave remote refs untouched in .git/refs/remotes
LOG.info(String.format("No remote found with the name [%s]. All remotes: %s", remoteName, remotes));
return null;
}
@@ -135,6 +135,13 @@ public class GitConfig {
*/
@NotNull
static GitConfig read(@NotNull GitPlatformFacade platformFacade, @NotNull File configFile) {
GitConfig emptyConfig = new GitConfig(Collections.<Remote>emptyList(), Collections.<Url>emptyList(),
Collections.<BranchConfig>emptyList());
if (!configFile.exists()) {
LOG.info("No .git/config file at " + configFile.getPath());
return emptyConfig;
}
Ini ini = new Ini();
ini.getConfig().setMultiOption(true); // duplicate keys (e.g. url in [remote])
ini.getConfig().setTree(false); // don't need tree structure: it corrupts url in section name (e.g. [url "http://github.com/"]
@@ -143,7 +150,7 @@ public class GitConfig {
}
catch (IOException e) {
LOG.error(new RepoStateException("Couldn't load .git/config file at " + configFile.getPath(), e));
return new GitConfig(Collections.<Remote>emptyList(), Collections.<Url>emptyList(), Collections.<BranchConfig>emptyList());
return emptyConfig;
}
IdeaPluginDescriptor plugin = platformFacade.getPluginByClassName(GitConfig.class.getName());
@@ -39,7 +39,7 @@ import java.util.List;
* </p>
* <p>
* GitRemote instance constructed by {@link GitConfig#read(GitPlatformFacade, File)}} has all these rules applied.
* Thus, for example, if only one {@code url} and no {@code pushUrls} are defined for the remote,
* Thus, for example, if only one {@code url} and no {@code pushUrls} are defined for the remote,
* both {@link #getUrls()} and {@link #getPushUrls()} will return this url. <br/>
* This is made to avoid urls transformation logic from the code using GitRemote, leaving it all in GitConfig parsing.
* </p>
@@ -47,14 +47,14 @@ import java.util.List;
* Same applies to fetch and push specs: {@link #getPushRefSpecs()} returns the spec,
* even if there are no separate record in {@code .git/config}
* </p>
*
*
* <p>
* NB: Not all remote preferences (defined in {@code .git/config} are stored in the object.
* If some additional data is needed, add the field, getter, constructor parameter and populate it in {@link GitConfig}.
* </p>
*
*
* <p>Remotes are compared (via equals, hashcode and compareTo) only by names.</p>
*
*
* @author Kirill Likhodedov
*/
public final class GitRemote implements Comparable<GitRemote> {
@@ -80,8 +80,8 @@ public final class GitRemote implements Comparable<GitRemote> {
@NotNull final List<String> myFetchRefSpecs;
@NotNull private final List<String> myPushRefSpecs;
GitRemote(@NotNull String name, @NotNull List<String> urls, @NotNull Collection<String> pushUrls,
@NotNull List<String> fetchRefSpecs, @NotNull List<String> pushRefSpecs) {
public GitRemote(@NotNull String name, @NotNull List<String> urls, @NotNull Collection<String> pushUrls,
@NotNull List<String> fetchRefSpecs, @NotNull List<String> pushRefSpecs) {
myName = name;
myUrls = urls;
myPushUrls = pushUrls;
@@ -16,10 +16,14 @@
package git4idea.repo;
import com.intellij.dvcs.repo.Repository;
import com.intellij.openapi.util.Condition;
import com.intellij.util.containers.ContainerUtil;
import git4idea.GitLocalBranch;
import git4idea.GitRemoteBranch;
import git4idea.test.GitSingleRepoTest;
import java.io.File;
import java.util.Collection;
import static git4idea.test.GitExecutor.git;
import static git4idea.test.GitScenarios.commit;
@@ -46,4 +50,24 @@ public class GitRepositoryReaderNewTest extends GitSingleRepoTest {
assertEquals("State value is incorrect", Repository.State.REBASING, state);
}
// inspired by IDEA-124052
public void test_remote_reference_without_remote() {
final String INVALID_REMOTE = "invalid-remote";
final String INVALID_REMOTE_BRANCH = "master";
git("update-ref refs/remotes/" + INVALID_REMOTE + "/" + INVALID_REMOTE_BRANCH + " HEAD");
File gitDir = new File(myRepo.getRoot().getPath(), ".git");
GitRepositoryReader reader = new GitRepositoryReader(gitDir);
GitConfig config = GitConfig.read(myPlatformFacade, new File(gitDir, "config"));
Collection<GitRemote> remotes = config.parseRemotes();
Collection<GitRemoteBranch> remoteBranches = reader.readBranches(remotes).getRemoteBranches();
assertTrue("Remote branch not found", ContainerUtil.exists(remoteBranches, new Condition<GitRemoteBranch>() {
@Override
public boolean value(GitRemoteBranch branch) {
return branch.getNameForLocalOperations().equals(INVALID_REMOTE + "/" + INVALID_REMOTE_BRANCH);
}
}));
}
}
@@ -20,7 +20,6 @@ import com.intellij.ide.fileTemplates.FileTemplateDescriptor;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiMethod;
import com.intellij.util.PathUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.GroovyFileType;
@@ -16,10 +16,11 @@ import com.google.common.base.Objects;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vcs.FilePath;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.vcsUtil.VcsUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.zmlx.hg4idea.util.HgUtil;
import java.io.File;
@@ -53,10 +54,11 @@ public class HgFile {
return file;
}
@NotNull
@Nullable
public String getRelativePath() {
if (relativePath == null) {
relativePath = buildRelativePath(VfsUtil.virtualToIoFile(vcsRoot), file);
//For configuration like "d:/.hg" File.getParent method has minimal prefix length, so vcsRoot will be "d:", getParent will be "d:/".
relativePath = FileUtil.getRelativePath(VfsUtilCore.virtualToIoFile(vcsRoot), file);
}
return relativePath;
}
@@ -66,17 +68,6 @@ public class HgFile {
return VcsUtil.getFilePath(file);
}
private static String buildRelativePath(File anchestor, File descendant) {
if (anchestor.equals(descendant)) {
return ".";
}
if (anchestor.equals(descendant.getParentFile())) {
return descendant.getName();
}
return buildRelativePath(anchestor, descendant.getParentFile())
+ File.separator + descendant.getName();
}
@Override
public boolean equals(Object o) {
if (this == o) {
@@ -17,10 +17,13 @@ package com.intellij.execution.junit;
import com.intellij.CommonBundle;
import com.intellij.codeInsight.AnnotationUtil;
import com.intellij.codeInsight.daemon.impl.quickfix.OrderEntryFix;
import com.intellij.codeInsight.intention.AddAnnotationFix;
import com.intellij.icons.AllIcons;
import com.intellij.ide.fileTemplates.FileTemplateDescriptor;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.projectRoots.ex.JavaSdkUtil;
import com.intellij.openapi.ui.Messages;
import com.intellij.psi.*;
@@ -34,6 +37,8 @@ import org.jetbrains.annotations.Nullable;
import javax.swing.*;
public class JUnit4Framework extends JavaTestFramework {
private static final Logger LOG = Logger.getInstance("#" + JUnit4Framework.class.getName());
@NotNull
public String getName() {
return "JUnit4";
@@ -153,6 +158,16 @@ public class JUnit4Framework extends JavaTestFramework {
return new FileTemplateDescriptor("JUnit4 Test Class.java");
}
@Override
public void setupLibrary(Module module) {
try {
OrderEntryFix.addJUnit4Library(false, module);
}
catch (ClassNotFoundException e) {
LOG.info(e);
}
}
@Override
public boolean isParameterized(PsiClass clazz) {
final PsiAnnotation annotation = AnnotationUtil.findAnnotation(clazz, JUnitUtil.RUN_WITH);
@@ -23,6 +23,7 @@ import com.intellij.ide.util.ClassFilter;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiClass;
@@ -30,6 +31,7 @@ import com.intellij.psi.PsiManager;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.PsiUtilCore;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jps.model.java.JavaModuleSourceRootTypes;
import java.util.ArrayList;
import java.util.List;
@@ -59,7 +61,9 @@ public class TestClassFilter implements ClassFilter.ClassFilterWithScope {
(aClass.isInheritor(myBase, true) || JUnitUtil.isTestClass(aClass))) {
final CompilerConfiguration compilerConfiguration = CompilerConfiguration.getInstance(getProject());
final VirtualFile virtualFile = PsiUtilCore.getVirtualFile(aClass);
return !compilerConfiguration.isExcludedFromCompilation(virtualFile) && !compilerConfiguration.isResourceFile(virtualFile);
if (virtualFile == null) return false;
return !compilerConfiguration.isExcludedFromCompilation(virtualFile) &&
!ProjectRootManager.getInstance(myProject).getFileIndex().isUnderSourceRootOfType(virtualFile, JavaModuleSourceRootTypes.RESOURCES);
}
return false;
}
@@ -98,6 +98,11 @@ public class JUnitEntryPoint extends EntryPoint {
@Override
public String[] getIgnoreAnnotations() {
return new String[]{"org.junit.Rule", "org.mockito.Mock", "org.mockito.InjectMocks", "org.junit.ClassRule", "org.junit.experimental.theories.DataPoint"};
return new String[]{"org.junit.Rule",
"org.mockito.Mock",
"org.mockito.Spy",
"org.mockito.InjectMocks",
"org.junit.ClassRule",
"org.junit.experimental.theories.DataPoint"};
}
}
@@ -20,6 +20,9 @@ import com.intellij.openapi.fileTypes.FileTypeManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.module.ModuleUtil;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.project.DumbModeTask;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.roots.*;
@@ -156,27 +159,45 @@ public class PythonLanguageLevelPusher implements FilePropertyPusher<LanguageLev
}
}
public void afterRootsChanged(@NotNull Project project) {
Set<Sdk> updatedSdks = new HashSet<Sdk>();
final Module[] modules = ModuleManager.getInstance(project).getModules();
boolean needReparseOpenFiles = false;
for (Module module : modules) {
Sdk newSdk = PythonSdkType.findPythonSdk(module);
if (myModuleSdks.containsKey(module)) {
Sdk oldSdk = myModuleSdks.get(module);
if ((newSdk != null || oldSdk != null) && newSdk != oldSdk) {
needReparseOpenFiles = true;
public void afterRootsChanged(@NotNull final Project project) {
final Runnable updateLanguageLevel = new Runnable() {
@Override
public void run() {
final Set<Sdk> updatedSdks = new HashSet<Sdk>();
final Module[] modules = ModuleManager.getInstance(project).getModules();
boolean needReparseOpenFiles = false;
for (Module module : modules) {
Sdk newSdk = PythonSdkType.findPythonSdk(module);
if (myModuleSdks.containsKey(module)) {
Sdk oldSdk = myModuleSdks.get(module);
if ((newSdk != null || oldSdk != null) && newSdk != oldSdk) {
needReparseOpenFiles = true;
}
}
myModuleSdks.put(module, newSdk);
if (newSdk != null && !updatedSdks.contains(newSdk)) {
updatedSdks.add(newSdk);
updateSdkLanguageLevel(project, newSdk);
}
}
final boolean finalNeedReparseOpenFiles = needReparseOpenFiles;
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
if (finalNeedReparseOpenFiles) {
FileContentUtil.reparseFiles(project, Collections.<VirtualFile>emptyList(), true);
}
}
});
}
myModuleSdks.put(module, newSdk);
if (newSdk != null && !updatedSdks.contains(newSdk)) {
updatedSdks.add(newSdk);
updateSdkLanguageLevel(project, newSdk);
};
final DumbModeTask task = new DumbModeTask() {
@Override
public void performInDumbMode(@NotNull ProgressIndicator indicator) {
ApplicationManager.getApplication().runReadAction(updateLanguageLevel);
}
}
if (needReparseOpenFiles) {
FileContentUtil.reparseFiles(project, Collections.<VirtualFile>emptyList(), true);
}
};
DumbService.getInstance(project).queueTask(task);
}
private void updateSdkLanguageLevel(Project project, Sdk sdk) {
@@ -287,6 +287,7 @@ public class PythonSdkType extends SdkType {
public void consume(@Nullable Sdk sdk) {
if (sdk != null) {
sdk.putUserData(SDK_CREATOR_COMPONENT_KEY, new WeakReference<Component>(parentComponent));
sdkCreatedCallback.consume(sdk);
}
}
});
@@ -499,6 +500,11 @@ public class PythonSdkType extends SdkType {
setupSdkPaths(sdk, project, ownerComponent);
}
@Override
public boolean setupSdkPaths(Sdk sdk, SdkModel sdkModel) {
return true; // run setupSdkPaths only once (from PythonSdkDetailsStep). Skip this from showCustomCreateUI
}
public static void setupSdkPaths(Sdk sdk, @Nullable Project project, @Nullable Component ownerComponent) {
final SdkModificator sdkModificator = sdk.getSdkModificator();
final boolean success = setupSdkPaths(project, ownerComponent, sdk, sdkModificator);