Merge branch 'master' into upsource-master

Conflicts:
	plugins/gettext/src/com/jetbrains/gettext/highlighter/GetTextHighlighterData.java
This commit is contained in:
Evgeny Pasynkov
2012-07-11 16:28:46 +02:00
849 changed files with 8688 additions and 6539 deletions
@@ -121,6 +121,7 @@ public interface RegExpTT {
ESC_CTRL_CHARACTER,
ESC_CHARACTER,
CTRL_CHARACTER,
CTRL,
UNICODE_CHAR,
HEX_CHAR, BAD_HEX_VALUE,
OCT_CHAR, BAD_OCT_VALUE,
+4
View File
@@ -603,6 +603,10 @@
<pattern>\Q\j\E</pattern>
<expected>OK</expected>
</test>
<test>
<pattern>\c0</pattern>
<expected>OK</expected>
</test>
</escapes>
<anchors>
@@ -19,6 +19,7 @@ import com.intellij.openapi.fileEditor.impl.EditorFileSwapper;
import com.intellij.openapi.fileEditor.impl.EditorWithProviderComposite;
import com.intellij.openapi.fileEditor.impl.text.TextEditorImpl;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
@@ -66,7 +67,7 @@ public class JavaEditorFileSwapper extends EditorFileSwapper {
if (member != null) {
PsiElement navigationElement = member.getNavigationElement();
if (navigationElement.getContainingFile().getVirtualFile() == sourceFile) {
if (Comparing.equal(navigationElement.getContainingFile().getVirtualFile(), sourceFile)) {
position = navigationElement.getTextOffset();
}
}
@@ -143,7 +143,7 @@ public class PostHighlightingPass extends TextEditorHighlightingPass {
myInLibrary = fileIndex.isInLibraryClasses(virtualFile) || fileIndex.isInLibrarySource(virtualFile);
myRefCountHolder = RefCountHolder.endUsing(myFile);
if (myRefCountHolder == null || !myRefCountHolder.retrieveUnusedReferencesInfo(new Runnable() {
if (myRefCountHolder == null || !myRefCountHolder.retrieveUnusedReferencesInfo((DaemonProgressIndicator)progress, new Runnable() {
@Override
public void run() {
boolean errorFound = collectHighlights(elementSet, highlights, progress);
@@ -47,14 +47,9 @@ public class RefCountHolder {
private final Map<PsiNamedElement, Boolean> myDclsUsedMap = new ConcurrentHashMap<PsiNamedElement, Boolean>();
private final Map<PsiReference, PsiImportStatementBase> myImportStatements = new ConcurrentHashMap<PsiReference, PsiImportStatementBase>();
private final Map<PsiElement,Boolean> myPossiblyDuplicateElements = new ConcurrentHashMap<PsiElement, Boolean>();
private final AtomicReference<State> myState = new AtomicReference<State>(State.VIRGIN);
private enum State {
VIRGIN, // just created or cleared
BEING_WRITTEN_BY_GHP, // general highlighting pass is storing references during analysis
READY, // may be used for highlighting unused stuff
BEING_USED_BY_PHP, // post highlighting pass is retrieving info
}
private final AtomicReference<DaemonProgressIndicator> myState = new AtomicReference<DaemonProgressIndicator>(VIRGIN);
private static final DaemonProgressIndicator VIRGIN = new DaemonProgressIndicator(); // just created or cleared
private static final DaemonProgressIndicator READY = new DaemonProgressIndicator();
private static class HolderReference extends SoftReference<RefCountHolder> {
@SuppressWarnings("UnusedDeclaration")
@@ -122,20 +117,19 @@ public class RefCountHolder {
}
private void clear() {
assertIsAnalyzing();
myLocalRefsMap.clear();
synchronized (myLocalRefsMap) {
myLocalRefsMap.clear();
}
myImportStatements.clear();
myDclsUsedMap.clear();
myPossiblyDuplicateElements.clear();
}
public void registerLocallyReferenced(@NotNull PsiNamedElement result) {
assertIsAnalyzing();
myDclsUsedMap.put(result,Boolean.TRUE);
}
public void registerReference(@NotNull PsiJavaReference ref, @NotNull JavaResolveResult resolveResult) {
assertIsAnalyzing();
PsiElement refElement = resolveResult.getElement();
PsiFile psiFile = refElement == null ? null : refElement.getContainingFile();
if (psiFile != null) psiFile = (PsiFile)psiFile.getNavigationElement(); // look at navigation elements because all references resolve into Cls elements when highlighting library source
@@ -154,7 +148,6 @@ public class RefCountHolder {
}
public boolean isRedundant(@NotNull PsiImportStatementBase importStatement) {
assertIsRetrieving();
return !myImportStatements.containsValue(importStatement);
}
@@ -167,7 +160,6 @@ public class RefCountHolder {
}
private void removeInvalidRefs() {
assertIsAnalyzing();
synchronized (myLocalRefsMap) {
for(Iterator<PsiReference> iterator = myLocalRefsMap.keySet().iterator(); iterator.hasNext();){
PsiReference ref = iterator.next();
@@ -197,8 +189,10 @@ public class RefCountHolder {
}
public boolean isReferenced(PsiNamedElement element) {
assertIsRetrieving();
List<PsiReference> array = myLocalRefsMap.getKeysByValue(element);
List<PsiReference> array;
synchronized (myLocalRefsMap) {
array = myLocalRefsMap.getKeysByValue(element);
}
if (array != null && !array.isEmpty() && !isParameterUsedRecursively(element, array)) return true;
Boolean usedStatus = myDclsUsedMap.get(element);
@@ -235,9 +229,11 @@ public class RefCountHolder {
}
public boolean isReferencedForRead(@NotNull PsiElement element) {
assertIsRetrieving();
LOG.assertTrue(element instanceof PsiVariable);
List<PsiReference> array = myLocalRefsMap.getKeysByValue(element);
List<PsiReference> array;
synchronized (myLocalRefsMap) {
array = myLocalRefsMap.getKeysByValue(element);
}
if (array == null) return false;
for (PsiReference ref : array) {
PsiElement refElement = ref.getElement();
@@ -257,9 +253,11 @@ public class RefCountHolder {
}
public boolean isReferencedForWrite(@NotNull PsiElement element) {
assertIsRetrieving();
LOG.assertTrue(element instanceof PsiVariable);
List<PsiReference> array = myLocalRefsMap.getKeysByValue(element);
List<PsiReference> array;
synchronized (myLocalRefsMap) {
array = myLocalRefsMap.getKeysByValue(element);
}
if (array == null) return false;
for (PsiReference ref : array) {
final PsiElement refElement = ref.getElement();
@@ -273,14 +271,14 @@ public class RefCountHolder {
return false;
}
public boolean analyze(@NotNull PsiFile file, TextRange dirtyScope, @NotNull Runnable analyze) {
State old = myState.get();
myState.compareAndSet(State.READY, State.VIRGIN);
if (!myState.compareAndSet(State.VIRGIN, State.BEING_WRITTEN_BY_GHP)) {
log("a: failed to change " + old + "->" + State.BEING_WRITTEN_BY_GHP);
public boolean analyze(@NotNull PsiFile file, TextRange dirtyScope, @NotNull Runnable analyze, @NotNull DaemonProgressIndicator indicator) {
DaemonProgressIndicator old = myState.get();
if (old != VIRGIN && old != READY) return false;
if (!myState.compareAndSet(old, indicator)) {
log("a: failed to change " + old + "->" + indicator);
return false;
}
log("a: changed " + old + "->" + State.BEING_WRITTEN_BY_GHP);
log("a: changed " + old + "->" + indicator);
boolean finished = false;
try {
if (dirtyScope != null) {
@@ -296,9 +294,9 @@ public class RefCountHolder {
finished = true;
}
finally {
boolean set = myState.compareAndSet(State.BEING_WRITTEN_BY_GHP, finished ? State.READY : State.VIRGIN);
boolean set = myState.compareAndSet(indicator, finished ? READY : VIRGIN);
assert set : myState.get();
log("a: changed back " + State.BEING_WRITTEN_BY_GHP + "->" + (finished ? State.READY : State.VIRGIN));
log("a: changed back " + indicator + "->" + (finished ? READY : VIRGIN));
}
return true;
}
@@ -307,31 +305,21 @@ public class RefCountHolder {
//System.err.println("RFC: "+s);
}
public boolean retrieveUnusedReferencesInfo(@NotNull Runnable analyze) {
State old = myState.get();
if (!myState.compareAndSet(State.READY, State.BEING_USED_BY_PHP)) {
log("r: failed to change " + old + "->" + State.BEING_USED_BY_PHP);
public boolean retrieveUnusedReferencesInfo(@NotNull DaemonProgressIndicator indicator, @NotNull Runnable analyze) {
DaemonProgressIndicator old = myState.get();
if (!myState.compareAndSet(READY, indicator)) {
log("r: failed to change " + old + "->" + indicator);
return false;
}
log("r: changed " + old + "->" + State.BEING_USED_BY_PHP);
log("r: changed " + old + "->" + indicator);
try {
analyze.run();
}
finally {
boolean set = myState.compareAndSet(State.BEING_USED_BY_PHP, State.READY);
boolean set = myState.compareAndSet(indicator, READY);
assert set : myState.get();
log("r: changed back " + State.BEING_USED_BY_PHP + "->" + State.READY);
log("r: changed back " + indicator + "->" + READY);
}
return true;
}
private void assertIsAnalyzing() {
State state = myState.get();
assert state == State.BEING_WRITTEN_BY_GHP : state;
}
private void assertIsRetrieving() {
State state = myState.get();
assert state == State.BEING_USED_BY_PHP : state;
}
}
@@ -24,6 +24,7 @@ import com.intellij.codeInsight.daemon.impl.quickfix.SetupJDKFix;
import com.intellij.lang.injection.InjectedLanguageManager;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.colors.EditorColorsScheme;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.IndexNotReadyException;
@@ -131,7 +132,8 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
myRefCountHolder = refCountHolder;
Document document = PsiDocumentManager.getInstance(project).getDocument(file);
TextRange dirtyScope = document == null ? file.getTextRange() : fileStatusMap.getFileDirtyScope(document, Pass.UPDATE_ALL);
success = refCountHolder.analyze(file, dirtyScope, action);
ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator();
success = indicator instanceof DaemonProgressIndicator && refCountHolder.analyze(file, dirtyScope, action, (DaemonProgressIndicator)indicator);
}
else {
myRefCountHolder = null;
@@ -31,6 +31,7 @@ import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.module.ModuleUtil;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.JavaPsiFacade;
import com.intellij.psi.PsiClass;
@@ -77,7 +78,7 @@ public class PsiClassFavoriteNodeProvider extends FavoriteNodeProvider {
public boolean elementContainsFile(final Object element, final VirtualFile vFile) {
if (element instanceof PsiClass) {
final PsiFile file = ((PsiClass)element).getContainingFile();
if (file != null && file.getVirtualFile() == vFile) return true;
if (file != null && Comparing.equal(file.getVirtualFile(), vFile)) return true;
}
return false;
}
@@ -21,6 +21,7 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.CompilerModuleExtension;
import com.intellij.openapi.roots.CompilerProjectExtension;
import com.intellij.openapi.roots.ModuleRootModel;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.pointers.VirtualFilePointer;
import com.intellij.openapi.util.io.FileUtil;
@@ -53,7 +54,8 @@ public class ExcludeCompilerOutputPolicy implements DirectoryIndexExcludePolicy
@Override
public boolean isExcludeRootForModule(final Module module, final VirtualFile excludeRoot) {
final CompilerModuleExtension compilerModuleExtension = CompilerModuleExtension.getInstance(module);
return compilerModuleExtension.getCompilerOutputPath() == excludeRoot || compilerModuleExtension.getCompilerOutputPathForTests() == excludeRoot;
return Comparing.equal(compilerModuleExtension.getCompilerOutputPath(), excludeRoot) ||
Comparing.equal(compilerModuleExtension.getCompilerOutputPathForTests(), excludeRoot);
}
@Override
@@ -87,7 +89,7 @@ public class ExcludeCompilerOutputPolicy implements DirectoryIndexExcludePolicy
private static boolean isEqualWithFileOrUrl(VirtualFile f, VirtualFile fileToCompareWith, String url) {
if (fileToCompareWith != null) {
if (fileToCompareWith == f) return true;
if (Comparing.equal(fileToCompareWith, f)) return true;
}
else if (url != null) {
if (FileUtil.pathsEqual(url, f.getUrl())) return true;
@@ -26,6 +26,7 @@ import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.*;
import com.intellij.openapi.roots.libraries.LibraryUtil;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.text.StringUtil;
@@ -172,7 +173,7 @@ public class TreeModelBuilder {
VirtualFile dir = null;
public boolean processFile(VirtualFile fileOrDir) {
if (!fileOrDir.isDirectory()) {
if (lastParent != null && dir != fileOrDir.getParent()) {
if (lastParent != null && !Comparing.equal(dir, fileOrDir.getParent())) {
lastParent = null;
}
lastParent = buildFileNode(fileOrDir, lastParent);
@@ -20,6 +20,7 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ProjectFileIndex;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.ui.ComponentWithBrowseButton;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.Pass;
import com.intellij.openapi.vfs.VirtualFile;
@@ -111,7 +112,7 @@ public abstract class JavaExtractSuperBaseDialog extends ExtractSuperBaseDialog<
final VirtualFile sourceRoot = fileIndex.getSourceRootForFile(sourceFile);
if (sourceRoot != null) {
for (PsiDirectory dir : directories) {
if (fileIndex.getSourceRootForFile(dir.getVirtualFile()) == sourceRoot) {
if (Comparing.equal(fileIndex.getSourceRootForFile(dir.getVirtualFile()), sourceRoot)) {
return dir;
}
}
@@ -15,6 +15,8 @@
*/
package com.intellij.refactoring.move.moveClassesOrPackages;
import com.intellij.openapi.util.Comparing;
import com.intellij.ui.ListCellRendererWrapper;
import com.intellij.ide.util.DirectoryChooser;
import com.intellij.openapi.editor.event.DocumentAdapter;
import com.intellij.openapi.editor.event.DocumentEvent;
@@ -122,7 +124,7 @@ public abstract class DestinationFolderComboBox extends ComboboxWithBrowseButton
final ComboBoxModel model = getComboBox().getModel();
for (int i = 0; i < model.getSize(); i++) {
DirectoryChooser.ItemWrapper item = (DirectoryChooser.ItemWrapper)model.getElementAt(i);
if (item != NULL_WRAPPER && fileIndex.getSourceRootForFile(item.getDirectory().getVirtualFile()) == root) {
if (item != NULL_WRAPPER && Comparing.equal(fileIndex.getSourceRootForFile(item.getDirectory().getVirtualFile()), root)) {
getComboBox().setSelectedItem(item);
getComboBox().repaint();
return;
@@ -164,7 +166,9 @@ public abstract class DestinationFolderComboBox extends ComboboxWithBrowseButton
}
final PsiDirectory selectedPsiDirectory = selectedItem.getDirectory();
VirtualFile selectedDestination = selectedPsiDirectory.getVirtualFile();
if (showChooserWhenDefault && selectedDestination == myInitialTargetDirectory.getVirtualFile() && mySourceRoots.length > 1) {
if (showChooserWhenDefault &&
Comparing.equal(selectedDestination, myInitialTargetDirectory.getVirtualFile()) &&
mySourceRoots.length > 1) {
selectedDestination = MoveClassesOrPackagesUtil.chooseSourceRoot(targetPackage, mySourceRoots, myInitialTargetDirectory);
}
if (selectedDestination == null) return null;
@@ -211,9 +215,10 @@ public abstract class DestinationFolderComboBox extends ComboboxWithBrowseButton
DirectoryChooser.ItemWrapper itemWrapper = new DirectoryChooser.ItemWrapper(targetDirectory, pathsToCreate.get(targetDirectory));
items.add(itemWrapper);
final VirtualFile sourceRootForFile = fileIndex.getSourceRootForFile(targetDirectory.getVirtualFile());
if (sourceRootForFile == initialTargetDirectorySourceRoot) {
if (Comparing.equal(sourceRootForFile, initialTargetDirectorySourceRoot)) {
initial = itemWrapper;
} else if (sourceRootForFile == oldSelection) {
}
else if (Comparing.equal(sourceRootForFile, oldSelection)) {
oldOne = itemWrapper;
}
}
@@ -205,7 +205,7 @@ public class MoveInnerDialog extends RefactoringDialog {
final PsiDirectory[] directories = oldPackage.getDirectories();
final VirtualFile root = projectRootManager.getFileIndex().getContentRootForFile(psiDirectory.getVirtualFile());
for(PsiDirectory dir: directories) {
if (projectRootManager.getFileIndex().getContentRootForFile(dir.getVirtualFile()) == root) {
if (Comparing.equal(projectRootManager.getFileIndex().getContentRootForFile(dir.getVirtualFile()), root)) {
initialDir = dir;
}
}
@@ -20,6 +20,7 @@ import com.intellij.ide.highlighter.JavaClassFileType;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.roots.*;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileManager;
@@ -314,7 +315,7 @@ public abstract class JavaFileManagerBase implements JavaFileManager, Disposable
final VirtualFile root = ProjectRootManager.getInstance(myManager.getProject()).getFileIndex().getClassRootForFile(vFile);
VirtualFile parent = vFile.getParent();
final PsiNameHelper nameHelper = JavaPsiFacade.getInstance(myManager.getProject()).getNameHelper();
while (parent != null && parent != root) {
while (parent != null && !Comparing.equal(parent, root)) {
if (!nameHelper.isIdentifier(parent.getName())) return false;
parent = parent.getParent();
}
@@ -332,7 +333,7 @@ public abstract class JavaFileManagerBase implements JavaFileManager, Disposable
final ProjectFileIndex fileIndex = rootManager.getFileIndex();
for (final VirtualFile sourceRoot : sourceRoots) {
final String packageName = fileIndex.getPackageNameByDirectory(sourceRoot);
if (packageName != null && packageName.length() > 0) {
if (packageName != null && !packageName.isEmpty()) {
names.add(packageName);
}
}
@@ -1,9 +1,25 @@
/*
* Copyright 2000-2012 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.psi.impl.search;
import com.intellij.openapi.application.AccessToken;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ReadAction;
import com.intellij.openapi.progress.ProgressIndicatorProvider;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
@@ -179,7 +195,7 @@ public class JavaDirectInheritorsSearcher implements QueryExecutor<PsiClass, Dir
VirtualFile jarFile = PsiUtil.getJarFile(aClass);
if (jarFile != null) {
for (PsiClass sameNamedClass : sameNamedClasses) {
boolean fromSameJar = PsiUtil.getJarFile(sameNamedClass) == jarFile;
boolean fromSameJar = Comparing.equal(PsiUtil.getJarFile(sameNamedClass), jarFile);
if (fromSameJar) {
sameJarClassFound = true;
if (!consumer.process(sameNamedClass)) return false;
@@ -15,6 +15,7 @@
*/
package com.intellij.psi.impl.compiled;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
@@ -193,7 +194,7 @@ public class ClsJavaCodeReferenceElementImpl extends ClsElementImpl implements P
VirtualFile jarFile = PsiUtil.getJarFile(this);
if (jarFile != null) {
for (PsiClass aClass : classes) {
if (PsiUtil.getJarFile(aClass) == jarFile) return aClass;
if (Comparing.equal(PsiUtil.getJarFile(aClass), jarFile)) return aClass;
}
}
}
@@ -1,17 +1,27 @@
/*
* Copyright 2000-2012 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.daemon.quickFix;
import com.intellij.codeInspection.accessStaticViaInstance.AccessStaticViaInstance;
public class AccessStaticViaInstanceTest extends LightQuickFixTestCase {
public void test() throws Exception { enableInspectionTool(new AccessStaticViaInstance()); doAllTests(); }
@Override
protected String getBasePath() {
return "/codeInsight/daemonCodeAnalyzer/quickFix/accessStaticViaInstance";
}
public void test() throws Exception { enableInspectionTool(new AccessStaticViaInstance()); doAllTests(); }
}
@@ -5,6 +5,7 @@ import com.intellij.openapi.roots.ContentEntry;
import com.intellij.openapi.roots.ContentFolder;
import com.intellij.openapi.roots.ModifiableRootModel;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.testFramework.IdeaTestCase;
@@ -53,7 +54,7 @@ public class ManagingContentRootFoldersTest extends IdeaTestCase {
private void initModifiableModel() {
myModel = ModuleRootManager.getInstance(myModule).getModifiableModel();
for (ContentEntry e : myModel.getContentEntries()) {
if (e.getFile() == root) entry = e;
if (Comparing.equal(e.getFile(), root)) entry = e;
}
}
@@ -54,6 +54,13 @@ public abstract class LanguageFileType implements FileType{
@Override
public final boolean isReadOnly() {
return isSystem();
}
/**
* System file types cannot be editor and are not shown in the interface
*/
protected boolean isSystem() {
return false;
}
@@ -19,6 +19,7 @@
*/
package com.intellij.openapi.vfs.newvfs.events;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileSystem;
import org.jetbrains.annotations.NonNls;
@@ -67,7 +68,7 @@ public class VFileMoveEvent extends VFileEvent {
@Override
public boolean isValid() {
return myFile.isValid() && myFile.getParent() == myOldParent && myOldParent.isValid();
return myFile.isValid() && Comparing.equal(myFile.getParent(), myOldParent) && myOldParent.isValid();
}
public boolean equals(final Object o) {
@@ -216,7 +216,7 @@ public class LocalSearchScope extends SearchScope {
for (PsiElement element : myScope) {
PsiFile containingFile = element.getContainingFile();
if (containingFile == null) continue;
if (containingFile.getVirtualFile() == file) return true;
if (Comparing.equal(containingFile.getVirtualFile(), file)) return true;
}
return false;
}
@@ -142,7 +142,7 @@ public final class LoadTextUtil {
}
@Nullable("null means no luck, otherwise it's tuple(guessed encoding, hint about content if was unable to guess, BOM)")
public static Trinity<Charset, CharsetToolkit.GuessedEncoding,byte[]> guessFromContent(VirtualFile virtualFile, byte[] content, int length) {
public static Trinity<Charset, CharsetToolkit.GuessedEncoding, byte[]> guessFromContent(VirtualFile virtualFile, byte[] content, int length) {
EncodingRegistry settings = EncodingRegistry.getInstance();
boolean shouldGuess = settings != null && settings.isUseUTFGuessing(virtualFile);
CharsetToolkit toolkit = shouldGuess ? new CharsetToolkit(content, EncodingRegistry.getInstance().getDefaultCharset()) : null;
@@ -22,6 +22,7 @@ import com.intellij.openapi.roots.JdkOrderEntry;
import com.intellij.openapi.roots.OrderRootType;
import com.intellij.openapi.roots.ProjectFileIndex;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.util.containers.ContainerUtil;
@@ -74,8 +75,8 @@ public class JdkScope extends GlobalSearchScope {
final VirtualFile r1 = getFileRoot(file1);
final VirtualFile r2 = getFileRoot(file2);
for (VirtualFile root : myEntries) {
if (r1 == root) return 1;
if (r2 == root) return -1;
if (Comparing.equal(r1, root)) return 1;
if (Comparing.equal(r2, root)) return -1;
}
return 0;
}
@@ -21,6 +21,7 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.roots.*;
import com.intellij.openapi.roots.libraries.Library;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.search.GlobalSearchScope;
@@ -144,8 +145,8 @@ public class LibraryRuntimeClasspathScope extends GlobalSearchScope {
final VirtualFile r1 = getFileRoot(file1);
final VirtualFile r2 = getFileRoot(file2);
for (VirtualFile root : myEntries) {
if (r1 == root) return 1;
if (r2 == root) return -1;
if (Comparing.equal(r1, root)) return 1;
if (Comparing.equal(r2, root)) return -1;
}
return 0;
}
@@ -17,6 +17,7 @@ package com.intellij.openapi.module.impl.scopes;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.roots.*;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiBundle;
import com.intellij.psi.search.GlobalSearchScope;
@@ -147,14 +148,14 @@ public class ModuleWithDependenciesScope extends GlobalSearchScope {
public int compare(VirtualFile file1, VirtualFile file2) {
VirtualFile r1 = getFileRoot(file1);
VirtualFile r2 = getFileRoot(file2);
if (r1 == r2) return 0;
if (Comparing.equal(r1, r2)) return 0;
if (r1 == null) return -1;
if (r2 == null) return 1;
for (VirtualFile root : myRoots) {
if (r1 == root) return 1;
if (r2 == root) return -1;
if (Comparing.equal(r1, root)) return 1;
if (Comparing.equal(r2, root)) return -1;
}
return 0;
}
@@ -26,10 +26,7 @@ import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressIndicatorProvider;
import com.intellij.openapi.roots.FileIndexFacade;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.NullableComputable;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.*;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
@@ -767,7 +764,7 @@ public class PsiSearchHelperImpl implements PsiSearchHelper {
@Override
public boolean process(VirtualFile file) {
if (file == fileToIgnoreOccurencesInVirtualFile) return true;
if (Comparing.equal(file, fileToIgnoreOccurencesInVirtualFile)) return true;
if (!index.shouldBeFound(scope, file)) return true;
final int value = count.incrementAndGet();
return value < 10;
@@ -16,15 +16,26 @@
package com.intellij.codeInsight.lookup;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* @author peter
*/
public abstract class LookupElementWeigher {
private final String myId;
private final boolean myNegated;
protected LookupElementWeigher(String id, boolean negated) {
myId = id;
myNegated = negated;
}
protected LookupElementWeigher(String id) {
myId = id;
this(id, false);
}
public boolean isNegated() {
return myNegated;
}
@Override
@@ -32,7 +43,7 @@ public abstract class LookupElementWeigher {
return myId;
}
@NotNull
@Nullable
public abstract Comparable weigh(@NotNull LookupElement element);
}
@@ -18,6 +18,7 @@ package com.intellij.ide.projectView;
import com.intellij.ide.util.treeView.AbstractTreeNode;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.vfs.VfsUtil;
@@ -189,7 +190,7 @@ public abstract class ProjectViewNode <Value> extends AbstractTreeNode<Value> im
public boolean value(final VirtualFile virtualFile) {
return contains(virtualFile)
// in case of flattened packages, when package node a.b.c contains error file, node a.b might not.
&& (getValue() instanceof PsiElement && PsiUtilBase.getVirtualFile((PsiElement)getValue()) == virtualFile ||
&& (getValue() instanceof PsiElement && Comparing.equal(PsiUtilBase.getVirtualFile((PsiElement)getValue()), virtualFile) ||
someChildContainsFile(virtualFile));
}
});
@@ -1,371 +1,372 @@
/*
* Copyright 2000-2009 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.completion;
import com.intellij.codeInsight.CodeInsightBundle;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementPresentation;
import com.intellij.navigation.ChooseByNameContributor;
import com.intellij.openapi.actionSystem.IdeActions;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.fileTypes.FileNameMatcher;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.fileTypes.FileTypeManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ProjectFileIndex;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiFileSystemItem;
import com.intellij.psi.PsiReference;
import com.intellij.psi.impl.source.resolve.reference.impl.PsiMultiReference;
import com.intellij.psi.impl.source.resolve.reference.impl.providers.*;
import com.intellij.psi.search.FilenameIndex;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.ProjectScope;
import com.intellij.util.ArrayUtil;
import com.intellij.util.ProcessingContext;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.util.*;
import static com.intellij.patterns.PlatformPatterns.psiElement;
/**
* @author spleaner
*/
public class FilePathCompletionContributor extends CompletionContributor {
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.completion.FilePathCompletionContributor");
public FilePathCompletionContributor() {
extend(CompletionType.BASIC, psiElement(), new CompletionProvider<CompletionParameters>() {
@Override
protected void addCompletions(@NotNull CompletionParameters parameters,
ProcessingContext context,
@NotNull CompletionResultSet result) {
final PsiReference psiReference = parameters.getPosition().getContainingFile().findReferenceAt(parameters.getOffset());
if (getReference(psiReference) != null && parameters.getInvocationCount() == 1) {
final String shortcut = getActionShortcut(IdeActions.ACTION_CODE_COMPLETION);
if (shortcut != null) {
CompletionService.getCompletionService().setAdvertisementText(CodeInsightBundle.message("class.completion.file.path", shortcut));
}
}
}
});
CompletionProvider<CompletionParameters> provider = new CompletionProvider<CompletionParameters>() {
@Override
protected void addCompletions(@NotNull final CompletionParameters parameters,
ProcessingContext context,
@NotNull final CompletionResultSet _result) {
if (!parameters.isExtendedCompletion()) {
return;
}
@NotNull final CompletionResultSet result = _result.caseInsensitive();
final PsiElement e = parameters.getPosition();
final Project project = e.getProject();
final PsiReference psiReference = parameters.getPosition().getContainingFile().findReferenceAt(parameters.getOffset());
final Pair<FileReference, Boolean> fileReferencePair = getReference(psiReference);
if (fileReferencePair != null) {
final FileReference first = fileReferencePair.getFirst();
if (first == null) return;
final FileReferenceSet set = first.getFileReferenceSet();
String prefix = set.getPathString()
.substring(0, parameters.getOffset() - set.getElement().getTextRange().getStartOffset() - set.getStartInElement());
final String textBeforePosition = e.getContainingFile().getText().substring(0, parameters.getOffset());
if (!textBeforePosition.endsWith(prefix)) {
final int len = textBeforePosition.length();
final String fragment = len > 100 ? textBeforePosition.substring(len - 100) : textBeforePosition;
throw new AssertionError("prefix should be some actual file string just before caret: " +
prefix +
"\n text=" +
fragment +
";\npathString=" +
set.getPathString() +
";\nelementText=" +
e.getParent().getText());
}
List<String> pathPrefixParts = null;
int lastSlashIndex;
if ((lastSlashIndex = prefix.lastIndexOf('/')) != -1) {
pathPrefixParts = StringUtil.split(prefix.substring(0, lastSlashIndex), "/");
prefix = prefix.substring(lastSlashIndex + 1);
}
final CompletionResultSet __result = result.withPrefixMatcher(prefix).caseInsensitive();
final PsiFile originalFile = parameters.getOriginalFile();
final VirtualFile contextFile = originalFile.getVirtualFile();
if (contextFile != null) {
final String[] fileNames = getAllNames(project);
final Set<String> resultNames = new TreeSet<String>();
for (String fileName : fileNames) {
if (filenameMatchesPrefixOrType(fileName, prefix, set.getSuitableFileTypes(), parameters.getInvocationCount())) {
resultNames.add(fileName);
}
}
final ProjectFileIndex index = ProjectRootManager.getInstance(project).getFileIndex();
final Module contextModule = index.getModuleForFile(contextFile);
if (contextModule != null) {
final FileReferenceHelper contextHelper = FileReferenceHelperRegistrar.getNotNullHelper(originalFile);
final GlobalSearchScope scope = ProjectScope.getProjectScope(project);
for (final String name : resultNames) {
ProgressManager.checkCanceled();
final PsiFile[] files = FilenameIndex.getFilesByName(project, name, scope);
if (files.length > 0) {
for (final PsiFile file : files) {
ProgressManager.checkCanceled();
final VirtualFile virtualFile = file.getVirtualFile();
if (virtualFile != null && virtualFile.isValid() && virtualFile != contextFile) {
if (contextHelper.isMine(project, virtualFile)) {
if (pathPrefixParts == null ||
fileMatchesPathPrefix(contextHelper.getPsiFileSystemItem(project, virtualFile), pathPrefixParts)) {
__result.addElement(new FilePathLookupItem(file, contextHelper));
}
}
}
}
}
}
}
}
if (set.getSuitableFileTypes().length > 0 && parameters.getInvocationCount() == 1) {
final String shortcut = getActionShortcut(IdeActions.ACTION_CODE_COMPLETION);
if (shortcut != null) {
CompletionService.getCompletionService()
.setAdvertisementText(CodeInsightBundle.message("class.completion.file.path.all.variants", shortcut));
}
}
if (fileReferencePair.getSecond()) result.stopHere();
}
}
};
extend(CompletionType.BASIC, psiElement(), provider);
}
private static boolean filenameMatchesPrefixOrType(final String fileName, final String prefix, final FileType[] suitableFileTypes, final int invocationCount) {
final boolean prefixMatched = prefix.length() == 0 || StringUtil.startsWithIgnoreCase(fileName, prefix);
if (prefixMatched && (suitableFileTypes.length == 0 || invocationCount > 2)) return true;
if (prefixMatched) {
final String extension = FileUtil.getExtension(fileName);
if (extension.length() == 0) return false;
for (final FileType fileType : suitableFileTypes) {
final List<FileNameMatcher> matchers = FileTypeManager.getInstance().getAssociations(fileType);
for (final FileNameMatcher matcher : matchers) {
if (matcher.accept(fileName)) return true;
}
}
}
return false;
}
private static boolean fileMatchesPathPrefix(@Nullable final PsiFileSystemItem file, @NotNull final List<String> pathPrefix) {
if (file == null) return false;
final List<String> contextParts = new ArrayList<String>();
PsiFileSystemItem parentFile = file;
PsiFileSystemItem parent;
while ((parent = parentFile.getParent()) != null) {
if (parent.getName().length() > 0) contextParts.add(0, parent.getName().toLowerCase());
parentFile = parent;
}
final String path = StringUtil.join(contextParts, "/");
int nextIndex = 0;
for (final String s : pathPrefix) {
if ((nextIndex = path.indexOf(s.toLowerCase(), nextIndex)) == -1) return false;
}
return true;
}
private static String[] getAllNames(@NotNull final Project project) {
Set<String> names = new HashSet<String>();
final ChooseByNameContributor[] nameContributors = ChooseByNameContributor.FILE_EP_NAME.getExtensions();
for (final ChooseByNameContributor contributor : nameContributors) {
try {
names.addAll(Arrays.asList(contributor.getNames(project, false)));
}
catch (ProcessCanceledException ex) {
// index corruption detected, ignore
}
catch (Exception ex) {
LOG.error(ex);
}
}
return ArrayUtil.toStringArray(names);
}
@Nullable
private static Pair<FileReference, Boolean> getReference(final PsiReference original) {
if (original == null) {
return null;
}
if (original instanceof PsiMultiReference) {
final PsiMultiReference multiReference = (PsiMultiReference)original;
for (PsiReference reference : multiReference.getReferences()) {
if (reference instanceof FileReference) {
return Pair.create((FileReference) reference, false);
}
}
}
else if (original instanceof FileReferenceOwner) {
final FileReference fileReference = ((FileReferenceOwner)original).getLastFileReference();
if (fileReference != null) {
return Pair.create(fileReference, true);
}
}
return null;
}
public class FilePathLookupItem extends LookupElement {
private final String myName;
private final String myPath;
private final String myInfo;
private final Icon myIcon;
private final PsiFile myFile;
private final FileReferenceHelper myReferenceHelper;
public FilePathLookupItem(@NotNull final PsiFile file, @NotNull final FileReferenceHelper referenceHelper) {
myName = file.getName();
myPath = file.getVirtualFile().getPath();
myReferenceHelper = referenceHelper;
myInfo = FileInfoManager.getFileAdditionalInfo(file);
myIcon = file.getFileType().getIcon();
myFile = file;
}
@SuppressWarnings({"HardCodedStringLiteral"})
@Override
public String toString() {
return String.format("%s%s", myName, myInfo == null ? "" : " (" + myInfo + ")");
}
@NotNull
@Override
public Object getObject() {
return myFile;
}
@NotNull
public String getLookupString() {
return myName;
}
@Override
public void handleInsert(InsertionContext context) {
context.commitDocument();
if (myFile.isValid()) {
final PsiReference psiReference = context.getFile().findReferenceAt(context.getStartOffset());
final Pair<FileReference, Boolean> fileReferencePair = getReference(psiReference);
LOG.assertTrue(fileReferencePair != null);
FileReference ref = fileReferencePair.getFirst();
context.setTailOffset(ref.getRangeInElement().getEndOffset() + ref.getElement().getTextRange().getStartOffset());
ref.bindToElement(myFile, true);
}
}
@Override
public void renderElement(LookupElementPresentation presentation) {
final VirtualFile virtualFile = myFile.getVirtualFile();
LOG.assertTrue(virtualFile != null);
final PsiFileSystemItem root = myReferenceHelper.findRoot(myFile.getProject(), virtualFile);
final String relativePath = PsiFileSystemItemUtil.getRelativePath(root, myReferenceHelper.getPsiFileSystemItem(myFile.getProject(), virtualFile));
final StringBuilder sb = new StringBuilder();
if (myInfo != null) {
sb.append(" (").append(myInfo);
}
if (relativePath != null && !relativePath.equals(myName)) {
if (myInfo != null) {
sb.append(", ");
}
else {
sb.append(" (");
}
sb.append(relativePath);
}
if (sb.length() > 0) {
sb.append(')');
}
presentation.setItemText(myName);
if (sb.length() > 0) {
presentation.setTailText(sb.toString(), true);
}
presentation.setIcon(myIcon);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
FilePathLookupItem that = (FilePathLookupItem)o;
if (!myName.equals(that.myName)) return false;
if (!myPath.equals(that.myPath)) return false;
return true;
}
@Override
public int hashCode() {
int result = myName.hashCode();
result = 31 * result + myPath.hashCode();
return result;
}
}
}
/*
* Copyright 2000-2009 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.completion;
import com.intellij.codeInsight.CodeInsightBundle;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementPresentation;
import com.intellij.navigation.ChooseByNameContributor;
import com.intellij.openapi.actionSystem.IdeActions;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.fileTypes.FileNameMatcher;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.fileTypes.FileTypeManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ProjectFileIndex;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiFileSystemItem;
import com.intellij.psi.PsiReference;
import com.intellij.psi.impl.source.resolve.reference.impl.PsiMultiReference;
import com.intellij.psi.impl.source.resolve.reference.impl.providers.*;
import com.intellij.psi.search.FilenameIndex;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.ProjectScope;
import com.intellij.util.ArrayUtil;
import com.intellij.util.ProcessingContext;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.util.*;
import static com.intellij.patterns.PlatformPatterns.psiElement;
/**
* @author spleaner
*/
public class FilePathCompletionContributor extends CompletionContributor {
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.completion.FilePathCompletionContributor");
public FilePathCompletionContributor() {
extend(CompletionType.BASIC, psiElement(), new CompletionProvider<CompletionParameters>() {
@Override
protected void addCompletions(@NotNull CompletionParameters parameters,
ProcessingContext context,
@NotNull CompletionResultSet result) {
final PsiReference psiReference = parameters.getPosition().getContainingFile().findReferenceAt(parameters.getOffset());
if (getReference(psiReference) != null && parameters.getInvocationCount() == 1) {
final String shortcut = getActionShortcut(IdeActions.ACTION_CODE_COMPLETION);
if (shortcut != null) {
CompletionService.getCompletionService().setAdvertisementText(CodeInsightBundle.message("class.completion.file.path", shortcut));
}
}
}
});
CompletionProvider<CompletionParameters> provider = new CompletionProvider<CompletionParameters>() {
@Override
protected void addCompletions(@NotNull final CompletionParameters parameters,
ProcessingContext context,
@NotNull final CompletionResultSet _result) {
if (!parameters.isExtendedCompletion()) {
return;
}
@NotNull final CompletionResultSet result = _result.caseInsensitive();
final PsiElement e = parameters.getPosition();
final Project project = e.getProject();
final PsiReference psiReference = parameters.getPosition().getContainingFile().findReferenceAt(parameters.getOffset());
final Pair<FileReference, Boolean> fileReferencePair = getReference(psiReference);
if (fileReferencePair != null) {
final FileReference first = fileReferencePair.getFirst();
if (first == null) return;
final FileReferenceSet set = first.getFileReferenceSet();
String prefix = set.getPathString()
.substring(0, parameters.getOffset() - set.getElement().getTextRange().getStartOffset() - set.getStartInElement());
final String textBeforePosition = e.getContainingFile().getText().substring(0, parameters.getOffset());
if (!textBeforePosition.endsWith(prefix)) {
final int len = textBeforePosition.length();
final String fragment = len > 100 ? textBeforePosition.substring(len - 100) : textBeforePosition;
throw new AssertionError("prefix should be some actual file string just before caret: " +
prefix +
"\n text=" +
fragment +
";\npathString=" +
set.getPathString() +
";\nelementText=" +
e.getParent().getText());
}
List<String> pathPrefixParts = null;
int lastSlashIndex;
if ((lastSlashIndex = prefix.lastIndexOf('/')) != -1) {
pathPrefixParts = StringUtil.split(prefix.substring(0, lastSlashIndex), "/");
prefix = prefix.substring(lastSlashIndex + 1);
}
final CompletionResultSet __result = result.withPrefixMatcher(prefix).caseInsensitive();
final PsiFile originalFile = parameters.getOriginalFile();
final VirtualFile contextFile = originalFile.getVirtualFile();
if (contextFile != null) {
final String[] fileNames = getAllNames(project);
final Set<String> resultNames = new TreeSet<String>();
for (String fileName : fileNames) {
if (filenameMatchesPrefixOrType(fileName, prefix, set.getSuitableFileTypes(), parameters.getInvocationCount())) {
resultNames.add(fileName);
}
}
final ProjectFileIndex index = ProjectRootManager.getInstance(project).getFileIndex();
final Module contextModule = index.getModuleForFile(contextFile);
if (contextModule != null) {
final FileReferenceHelper contextHelper = FileReferenceHelperRegistrar.getNotNullHelper(originalFile);
final GlobalSearchScope scope = ProjectScope.getProjectScope(project);
for (final String name : resultNames) {
ProgressManager.checkCanceled();
final PsiFile[] files = FilenameIndex.getFilesByName(project, name, scope);
if (files.length > 0) {
for (final PsiFile file : files) {
ProgressManager.checkCanceled();
final VirtualFile virtualFile = file.getVirtualFile();
if (virtualFile != null && virtualFile.isValid() && !Comparing.equal(virtualFile, contextFile)) {
if (contextHelper.isMine(project, virtualFile)) {
if (pathPrefixParts == null ||
fileMatchesPathPrefix(contextHelper.getPsiFileSystemItem(project, virtualFile), pathPrefixParts)) {
__result.addElement(new FilePathLookupItem(file, contextHelper));
}
}
}
}
}
}
}
}
if (set.getSuitableFileTypes().length > 0 && parameters.getInvocationCount() == 1) {
final String shortcut = getActionShortcut(IdeActions.ACTION_CODE_COMPLETION);
if (shortcut != null) {
CompletionService.getCompletionService()
.setAdvertisementText(CodeInsightBundle.message("class.completion.file.path.all.variants", shortcut));
}
}
if (fileReferencePair.getSecond()) result.stopHere();
}
}
};
extend(CompletionType.BASIC, psiElement(), provider);
}
private static boolean filenameMatchesPrefixOrType(final String fileName, final String prefix, final FileType[] suitableFileTypes, final int invocationCount) {
final boolean prefixMatched = prefix.length() == 0 || StringUtil.startsWithIgnoreCase(fileName, prefix);
if (prefixMatched && (suitableFileTypes.length == 0 || invocationCount > 2)) return true;
if (prefixMatched) {
final String extension = FileUtil.getExtension(fileName);
if (extension.length() == 0) return false;
for (final FileType fileType : suitableFileTypes) {
final List<FileNameMatcher> matchers = FileTypeManager.getInstance().getAssociations(fileType);
for (final FileNameMatcher matcher : matchers) {
if (matcher.accept(fileName)) return true;
}
}
}
return false;
}
private static boolean fileMatchesPathPrefix(@Nullable final PsiFileSystemItem file, @NotNull final List<String> pathPrefix) {
if (file == null) return false;
final List<String> contextParts = new ArrayList<String>();
PsiFileSystemItem parentFile = file;
PsiFileSystemItem parent;
while ((parent = parentFile.getParent()) != null) {
if (parent.getName().length() > 0) contextParts.add(0, parent.getName().toLowerCase());
parentFile = parent;
}
final String path = StringUtil.join(contextParts, "/");
int nextIndex = 0;
for (final String s : pathPrefix) {
if ((nextIndex = path.indexOf(s.toLowerCase(), nextIndex)) == -1) return false;
}
return true;
}
private static String[] getAllNames(@NotNull final Project project) {
Set<String> names = new HashSet<String>();
final ChooseByNameContributor[] nameContributors = ChooseByNameContributor.FILE_EP_NAME.getExtensions();
for (final ChooseByNameContributor contributor : nameContributors) {
try {
names.addAll(Arrays.asList(contributor.getNames(project, false)));
}
catch (ProcessCanceledException ex) {
// index corruption detected, ignore
}
catch (Exception ex) {
LOG.error(ex);
}
}
return ArrayUtil.toStringArray(names);
}
@Nullable
private static Pair<FileReference, Boolean> getReference(final PsiReference original) {
if (original == null) {
return null;
}
if (original instanceof PsiMultiReference) {
final PsiMultiReference multiReference = (PsiMultiReference)original;
for (PsiReference reference : multiReference.getReferences()) {
if (reference instanceof FileReference) {
return Pair.create((FileReference) reference, false);
}
}
}
else if (original instanceof FileReferenceOwner) {
final FileReference fileReference = ((FileReferenceOwner)original).getLastFileReference();
if (fileReference != null) {
return Pair.create(fileReference, true);
}
}
return null;
}
public class FilePathLookupItem extends LookupElement {
private final String myName;
private final String myPath;
private final String myInfo;
private final Icon myIcon;
private final PsiFile myFile;
private final FileReferenceHelper myReferenceHelper;
public FilePathLookupItem(@NotNull final PsiFile file, @NotNull final FileReferenceHelper referenceHelper) {
myName = file.getName();
myPath = file.getVirtualFile().getPath();
myReferenceHelper = referenceHelper;
myInfo = FileInfoManager.getFileAdditionalInfo(file);
myIcon = file.getFileType().getIcon();
myFile = file;
}
@SuppressWarnings({"HardCodedStringLiteral"})
@Override
public String toString() {
return String.format("%s%s", myName, myInfo == null ? "" : " (" + myInfo + ")");
}
@NotNull
@Override
public Object getObject() {
return myFile;
}
@NotNull
public String getLookupString() {
return myName;
}
@Override
public void handleInsert(InsertionContext context) {
context.commitDocument();
if (myFile.isValid()) {
final PsiReference psiReference = context.getFile().findReferenceAt(context.getStartOffset());
final Pair<FileReference, Boolean> fileReferencePair = getReference(psiReference);
LOG.assertTrue(fileReferencePair != null);
FileReference ref = fileReferencePair.getFirst();
context.setTailOffset(ref.getRangeInElement().getEndOffset() + ref.getElement().getTextRange().getStartOffset());
ref.bindToElement(myFile, true);
}
}
@Override
public void renderElement(LookupElementPresentation presentation) {
final VirtualFile virtualFile = myFile.getVirtualFile();
LOG.assertTrue(virtualFile != null);
final PsiFileSystemItem root = myReferenceHelper.findRoot(myFile.getProject(), virtualFile);
final String relativePath = PsiFileSystemItemUtil.getRelativePath(root, myReferenceHelper.getPsiFileSystemItem(myFile.getProject(), virtualFile));
final StringBuilder sb = new StringBuilder();
if (myInfo != null) {
sb.append(" (").append(myInfo);
}
if (relativePath != null && !relativePath.equals(myName)) {
if (myInfo != null) {
sb.append(", ");
}
else {
sb.append(" (");
}
sb.append(relativePath);
}
if (sb.length() > 0) {
sb.append(')');
}
presentation.setItemText(myName);
if (sb.length() > 0) {
presentation.setTailText(sb.toString(), true);
}
presentation.setIcon(myIcon);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
FilePathLookupItem that = (FilePathLookupItem)o;
if (!myName.equals(that.myName)) return false;
if (!myPath.equals(that.myPath)) return false;
return true;
}
@Override
public int hashCode() {
int result = myName.hashCode();
result = 31 * result + myPath.hashCode();
return result;
}
}
}
@@ -1,356 +1,355 @@
/*
* Copyright 2000-2009 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.completion.impl;
import com.intellij.codeInsight.CodeInsightSettings;
import com.intellij.codeInsight.completion.*;
import com.intellij.codeInsight.lookup.*;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.project.ProjectManagerAdapter;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.Pair;
import com.intellij.patterns.ElementPattern;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.Weigher;
import com.intellij.psi.WeighingService;
import com.intellij.psi.codeStyle.MinusculeMatcher;
import com.intellij.psi.codeStyle.NameUtil;
import com.intellij.psi.impl.DebugUtil;
import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
import com.intellij.util.Consumer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
/**
* @author peter
*/
public class CompletionServiceImpl extends CompletionService{
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.completion.impl.CompletionServiceImpl");
private static volatile CompletionPhase ourPhase = CompletionPhase.NoCompletion;
private static String ourPhaseTrace;
private static CodeInsightSettings ourSettings = CodeInsightSettings.getInstance();
public CompletionServiceImpl() {
ProjectManager.getInstance().addProjectManagerListener(new ProjectManagerAdapter() {
@Override
public void projectClosing(Project project) {
CompletionProgressIndicator indicator = getCurrentCompletion();
if (indicator != null && indicator.getProject() == project) {
LookupManager.getInstance(indicator.getProject()).hideActiveLookup();
setCompletionPhase(CompletionPhase.NoCompletion);
}
else if (indicator == null) {
setCompletionPhase(CompletionPhase.NoCompletion);
}
}
});
}
@SuppressWarnings({"MethodOverridesStaticMethodOfSuperclass"})
public static CompletionServiceImpl getCompletionService() {
return (CompletionServiceImpl)CompletionService.getCompletionService();
}
@Override
public String getAdvertisementText() {
final CompletionProgressIndicator completion = getCompletionService().getCurrentCompletion();
return completion == null ? null : completion.getLookup().getAdvertisementText();
}
public void setAdvertisementText(@Nullable final String text) {
final CompletionProgressIndicator completion = getCompletionService().getCurrentCompletion();
if (completion != null) {
completion.getLookup().setAdvertisementText(text);
}
}
public CompletionResultSet createResultSet(final CompletionParameters parameters, final Consumer<CompletionResult> consumer,
@NotNull final CompletionContributor contributor) {
final PsiElement position = parameters.getPosition();
final String prefix = CompletionData.findPrefixStatic(position, parameters.getOffset());
final String textBeforePosition = parameters.getPosition().getContainingFile().getText().substring(0, parameters.getOffset());
ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator();
if (!(indicator instanceof CompletionProgressIndicator)) {
throw new AssertionError("createResultSet may be invoked only from completion thread: " + indicator + "!=" + getCurrentCompletion() + "; phase set at " + ourPhaseTrace);
}
CompletionProgressIndicator process = (CompletionProgressIndicator)indicator;
CamelHumpMatcher matcher = new CamelHumpMatcher(prefix);
CompletionSorterImpl sorter = defaultSorter(parameters, matcher);
return new CompletionResultSetImpl(consumer, textBeforePosition, matcher, contributor,parameters, sorter, process, null);
}
@Override
public CompletionProgressIndicator getCurrentCompletion() {
if (isPhase(CompletionPhase.BgCalculation.class, CompletionPhase.ItemsCalculated.class, CompletionPhase.CommittingDocuments.class,
CompletionPhase.Synchronous.class)) {
return ourPhase.indicator;
}
return null;
}
private static int getPrefixMatchingDegree(LookupElement item, CompletionLocation location) {
final MinusculeMatcher matcher = getMinusculeMatcher(location.getCompletionParameters().getLookup().itemPattern(item));
int max = Integer.MIN_VALUE;
for (String lookupString : item.getAllLookupStrings()) {
max = Math.max(max, matcher.matchingDegree(lookupString));
}
return max;
}
private static volatile Pair<String, MinusculeMatcher> lastMatcher;
private static MinusculeMatcher getMinusculeMatcher(String prefix) {
final int setting = ourSettings.COMPLETION_CASE_SENSITIVE;
final NameUtil.MatchingCaseSensitivity sensitivity =
setting == CodeInsightSettings.NONE ? NameUtil.MatchingCaseSensitivity.NONE :
setting == CodeInsightSettings.FIRST_LETTER ? NameUtil.MatchingCaseSensitivity.FIRST_LETTER : NameUtil.MatchingCaseSensitivity.ALL;
Pair<String, MinusculeMatcher> pair = lastMatcher;
if (pair != null && pair.first.equals(prefix)) {
return pair.second;
}
MinusculeMatcher matcher = new MinusculeMatcher(CamelHumpMatcher.applyMiddleMatching(prefix), sensitivity);
lastMatcher = Pair.create(prefix, matcher);
return matcher;
}
private static class CompletionResultSetImpl extends CompletionResultSet {
private final String myTextBeforePosition;
private final CompletionParameters myParameters;
private final CompletionSorterImpl mySorter;
private final CompletionProgressIndicator myProcess;
@Nullable private final CompletionResultSetImpl myOriginal;
public CompletionResultSetImpl(final Consumer<CompletionResult> consumer, final String textBeforePosition,
final PrefixMatcher prefixMatcher,
CompletionContributor contributor,
CompletionParameters parameters,
@NotNull CompletionSorterImpl sorter,
@NotNull CompletionProgressIndicator process,
@Nullable CompletionResultSetImpl original) {
super(prefixMatcher, consumer, contributor);
myTextBeforePosition = textBeforePosition;
myParameters = parameters;
mySorter = sorter;
myProcess = process;
myOriginal = original;
}
public void addElement(@NotNull final LookupElement element) {
CompletionResult matched = CompletionResult.wrap(element, getPrefixMatcher(), mySorter);
if (matched != null) {
passResult(matched);
}
}
@NotNull
public CompletionResultSet withPrefixMatcher(@NotNull final PrefixMatcher matcher) {
if (!myTextBeforePosition.endsWith(matcher.getPrefix())) {
final int len = myTextBeforePosition.length();
final String fragment = len > 100 ? myTextBeforePosition.substring(len - 100) : myTextBeforePosition;
PsiFile positionFile = myParameters.getPosition().getContainingFile();
LOG.error("prefix should be some actual file string just before caret: " + matcher.getPrefix() +
"\n text=" + fragment +
"\ninjected=" + (InjectedLanguageUtil.getTopLevelFile(positionFile) != positionFile) +
"\nlang=" + positionFile.getLanguage());
}
return new CompletionResultSetImpl(getConsumer(), myTextBeforePosition, matcher, myContributor, myParameters, mySorter, myProcess, this);
}
@Override
public void stopHere() {
super.stopHere();
if (myOriginal != null) {
myOriginal.stopHere();
}
}
@NotNull
public CompletionResultSet withPrefixMatcher(@NotNull final String prefix) {
return withPrefixMatcher(new CamelHumpMatcher(prefix));
}
@NotNull
@Override
public CompletionResultSet withRelevanceSorter(@NotNull CompletionSorter sorter) {
return new CompletionResultSetImpl(getConsumer(), myTextBeforePosition, getPrefixMatcher(), myContributor, myParameters, (CompletionSorterImpl)sorter, myProcess, this);
}
@NotNull
@Override
public CompletionResultSet caseInsensitive() {
return withPrefixMatcher(new CamelHumpMatcher(getPrefixMatcher().getPrefix(), false));
}
@Override
public void restartCompletionOnPrefixChange(ElementPattern<String> prefixCondition) {
final CompletionProgressIndicator indicator = getCompletionService().getCurrentCompletion();
if (indicator != null) {
indicator.addWatchedPrefix(myTextBeforePosition.length() - getPrefixMatcher().getPrefix().length(), prefixCondition);
}
}
@Override
public void restartCompletionWhenNothingMatches() {
final CompletionProgressIndicator indicator = getCompletionService().getCurrentCompletion();
if (indicator != null) {
indicator.getLookup().setStartCompletionWhenNothingMatches(true);
}
}
}
public static boolean assertPhase(Class<? extends CompletionPhase>... possibilities) {
if (!isPhase(possibilities)) {
LOG.error(ourPhase + "; set at " + ourPhaseTrace);
return false;
}
return true;
}
public static boolean isPhase(Class<? extends CompletionPhase>... possibilities) {
CompletionPhase phase = getCompletionPhase();
for (Class<? extends CompletionPhase> possibility : possibilities) {
if (possibility.isInstance(phase)) {
return true;
}
}
return false;
}
public static void setCompletionPhase(@NotNull CompletionPhase phase) {
ApplicationManager.getApplication().assertIsDispatchThread();
CompletionPhase oldPhase = getCompletionPhase();
CompletionProgressIndicator oldIndicator = oldPhase.indicator;
if (oldIndicator != null && !(phase instanceof CompletionPhase.BgCalculation)) {
LOG.assertTrue(!oldIndicator.isRunning() || oldIndicator.isCanceled(), "don't change phase during running completion: oldPhase=" + oldPhase);
}
Disposer.dispose(oldPhase);
ourPhase = phase;
ourPhaseTrace = DebugUtil.currentStackTrace();
}
public static CompletionPhase getCompletionPhase() {
// ApplicationManager.getApplication().assertIsDispatchThread();
CompletionPhase phase = getPhaseRaw();
ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator();
if (indicator != null) {
indicator.checkCanceled();
}
return phase;
}
public static CompletionPhase getPhaseRaw() {
return ourPhase;
}
public CompletionSorterImpl defaultSorter(CompletionParameters parameters, final PrefixMatcher matcher) {
final CompletionLocation location = new CompletionLocation(parameters);
CompletionSorterImpl sorter = emptySorter();
sorter = sorter.withClassifier(new PreferStartMatching(location));
for (final Weigher weigher : WeighingService.getWeighers(CompletionService.RELEVANCE_KEY)) {
final String id = weigher.toString();
if ("prefix".equals(id)) {
sorter = sorter.withClassifier(new PrefixMatchingClassifier(id, location));
}
else {
sorter = sorter.weigh(new LookupElementWeigher(id) {
@NotNull
@Override
public Comparable weigh(@NotNull LookupElement element) {
return new NegatingComparable(weigher.weigh(element, location));
}
});
}
}
if (parameters.getCompletionType() == CompletionType.SMART) {
return sorter;
}
return sorter.withClassifier("priority", true, new ClassifierFactory<LookupElement>("liftShorter") {
@Override
public Classifier<LookupElement> createClassifier(final Classifier<LookupElement> next) {
return new LiftShorterItemsClassifier(next, new LiftShorterItemsClassifier.LiftingCondition());
}
});
}
public CompletionSorterImpl emptySorter() {
return new CompletionSorterImpl(new ArrayList<ClassifierFactory<LookupElement>>());
}
private static class PreferStartMatching extends ClassifierFactory<LookupElement> {
private final CompletionLocation myLocation;
public PreferStartMatching(CompletionLocation location) {
super("startMatching");
myLocation = location;
}
@Override
public Classifier<LookupElement> createClassifier(Classifier<LookupElement> next) {
return new ComparingClassifier<LookupElement>(next, "startMatching") {
@NotNull
@Override
public Comparable getWeight(LookupElement element) {
PrefixMatcher itemMatcher = myLocation.getCompletionParameters().getLookup().itemMatcher(element);
for (String ls : element.getAllLookupStrings()) {
if (itemMatcher.isStartMatch(ls)) {
return false;
}
}
return true;
}
};
}
}
private static class PrefixMatchingClassifier extends ClassifierFactory<LookupElement> {
private final String myId;
private final CompletionLocation myLocation;
public PrefixMatchingClassifier(String id, CompletionLocation location) {
super(id);
myId = id;
myLocation = location;
}
@Override
public Classifier<LookupElement> createClassifier(Classifier<LookupElement> next) {
return new ComparingClassifier<LookupElement>(next, myId) {
@NotNull
@Override
public Comparable getWeight(LookupElement element) {
return -getPrefixMatchingDegree(element, myLocation);
}
};
}
}
}
/*
* Copyright 2000-2009 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.completion.impl;
import com.intellij.codeInsight.CodeInsightSettings;
import com.intellij.codeInsight.completion.*;
import com.intellij.codeInsight.lookup.*;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.project.ProjectManagerAdapter;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.Pair;
import com.intellij.patterns.ElementPattern;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.Weigher;
import com.intellij.psi.WeighingService;
import com.intellij.psi.codeStyle.MinusculeMatcher;
import com.intellij.psi.codeStyle.NameUtil;
import com.intellij.psi.impl.DebugUtil;
import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
import com.intellij.util.Consumer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
/**
* @author peter
*/
public class CompletionServiceImpl extends CompletionService{
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.completion.impl.CompletionServiceImpl");
private static volatile CompletionPhase ourPhase = CompletionPhase.NoCompletion;
private static String ourPhaseTrace;
private static CodeInsightSettings ourSettings = CodeInsightSettings.getInstance();
public CompletionServiceImpl() {
ProjectManager.getInstance().addProjectManagerListener(new ProjectManagerAdapter() {
@Override
public void projectClosing(Project project) {
CompletionProgressIndicator indicator = getCurrentCompletion();
if (indicator != null && indicator.getProject() == project) {
LookupManager.getInstance(indicator.getProject()).hideActiveLookup();
setCompletionPhase(CompletionPhase.NoCompletion);
}
else if (indicator == null) {
setCompletionPhase(CompletionPhase.NoCompletion);
}
}
});
}
@SuppressWarnings({"MethodOverridesStaticMethodOfSuperclass"})
public static CompletionServiceImpl getCompletionService() {
return (CompletionServiceImpl)CompletionService.getCompletionService();
}
@Override
public String getAdvertisementText() {
final CompletionProgressIndicator completion = getCompletionService().getCurrentCompletion();
return completion == null ? null : completion.getLookup().getAdvertisementText();
}
public void setAdvertisementText(@Nullable final String text) {
final CompletionProgressIndicator completion = getCompletionService().getCurrentCompletion();
if (completion != null) {
completion.getLookup().setAdvertisementText(text);
}
}
public CompletionResultSet createResultSet(final CompletionParameters parameters, final Consumer<CompletionResult> consumer,
@NotNull final CompletionContributor contributor) {
final PsiElement position = parameters.getPosition();
final String prefix = CompletionData.findPrefixStatic(position, parameters.getOffset());
final String textBeforePosition = parameters.getPosition().getContainingFile().getText().substring(0, parameters.getOffset());
ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator();
if (!(indicator instanceof CompletionProgressIndicator)) {
throw new AssertionError("createResultSet may be invoked only from completion thread: " + indicator + "!=" + getCurrentCompletion() + "; phase set at " + ourPhaseTrace);
}
CompletionProgressIndicator process = (CompletionProgressIndicator)indicator;
CamelHumpMatcher matcher = new CamelHumpMatcher(prefix);
CompletionSorterImpl sorter = defaultSorter(parameters, matcher);
return new CompletionResultSetImpl(consumer, textBeforePosition, matcher, contributor,parameters, sorter, process, null);
}
@Override
public CompletionProgressIndicator getCurrentCompletion() {
if (isPhase(CompletionPhase.BgCalculation.class, CompletionPhase.ItemsCalculated.class, CompletionPhase.CommittingDocuments.class,
CompletionPhase.Synchronous.class)) {
return ourPhase.indicator;
}
return null;
}
private static int getPrefixMatchingDegree(LookupElement item, CompletionLocation location) {
final MinusculeMatcher matcher = getMinusculeMatcher(location.getCompletionParameters().getLookup().itemPattern(item));
int max = Integer.MIN_VALUE;
for (String lookupString : item.getAllLookupStrings()) {
max = Math.max(max, matcher.matchingDegree(lookupString));
}
return max;
}
private static volatile Pair<String, MinusculeMatcher> lastMatcher;
private static MinusculeMatcher getMinusculeMatcher(String prefix) {
final int setting = ourSettings.COMPLETION_CASE_SENSITIVE;
final NameUtil.MatchingCaseSensitivity sensitivity =
setting == CodeInsightSettings.NONE ? NameUtil.MatchingCaseSensitivity.NONE :
setting == CodeInsightSettings.FIRST_LETTER ? NameUtil.MatchingCaseSensitivity.FIRST_LETTER : NameUtil.MatchingCaseSensitivity.ALL;
Pair<String, MinusculeMatcher> pair = lastMatcher;
if (pair != null && pair.first.equals(prefix)) {
return pair.second;
}
MinusculeMatcher matcher = new MinusculeMatcher(CamelHumpMatcher.applyMiddleMatching(prefix), sensitivity);
lastMatcher = Pair.create(prefix, matcher);
return matcher;
}
private static class CompletionResultSetImpl extends CompletionResultSet {
private final String myTextBeforePosition;
private final CompletionParameters myParameters;
private final CompletionSorterImpl mySorter;
private final CompletionProgressIndicator myProcess;
@Nullable private final CompletionResultSetImpl myOriginal;
public CompletionResultSetImpl(final Consumer<CompletionResult> consumer, final String textBeforePosition,
final PrefixMatcher prefixMatcher,
CompletionContributor contributor,
CompletionParameters parameters,
@NotNull CompletionSorterImpl sorter,
@NotNull CompletionProgressIndicator process,
@Nullable CompletionResultSetImpl original) {
super(prefixMatcher, consumer, contributor);
myTextBeforePosition = textBeforePosition;
myParameters = parameters;
mySorter = sorter;
myProcess = process;
myOriginal = original;
}
public void addElement(@NotNull final LookupElement element) {
CompletionResult matched = CompletionResult.wrap(element, getPrefixMatcher(), mySorter);
if (matched != null) {
passResult(matched);
}
}
@NotNull
public CompletionResultSet withPrefixMatcher(@NotNull final PrefixMatcher matcher) {
if (!myTextBeforePosition.endsWith(matcher.getPrefix())) {
final int len = myTextBeforePosition.length();
final String fragment = len > 100 ? myTextBeforePosition.substring(len - 100) : myTextBeforePosition;
PsiFile positionFile = myParameters.getPosition().getContainingFile();
LOG.error("prefix should be some actual file string just before caret: " + matcher.getPrefix() +
"\n text=" + fragment +
"\ninjected=" + (InjectedLanguageUtil.getTopLevelFile(positionFile) != positionFile) +
"\nlang=" + positionFile.getLanguage());
}
return new CompletionResultSetImpl(getConsumer(), myTextBeforePosition, matcher, myContributor, myParameters, mySorter, myProcess, this);
}
@Override
public void stopHere() {
super.stopHere();
if (myOriginal != null) {
myOriginal.stopHere();
}
}
@NotNull
public CompletionResultSet withPrefixMatcher(@NotNull final String prefix) {
return withPrefixMatcher(new CamelHumpMatcher(prefix));
}
@NotNull
@Override
public CompletionResultSet withRelevanceSorter(@NotNull CompletionSorter sorter) {
return new CompletionResultSetImpl(getConsumer(), myTextBeforePosition, getPrefixMatcher(), myContributor, myParameters, (CompletionSorterImpl)sorter, myProcess, this);
}
@NotNull
@Override
public CompletionResultSet caseInsensitive() {
return withPrefixMatcher(new CamelHumpMatcher(getPrefixMatcher().getPrefix(), false));
}
@Override
public void restartCompletionOnPrefixChange(ElementPattern<String> prefixCondition) {
final CompletionProgressIndicator indicator = getCompletionService().getCurrentCompletion();
if (indicator != null) {
indicator.addWatchedPrefix(myTextBeforePosition.length() - getPrefixMatcher().getPrefix().length(), prefixCondition);
}
}
@Override
public void restartCompletionWhenNothingMatches() {
final CompletionProgressIndicator indicator = getCompletionService().getCurrentCompletion();
if (indicator != null) {
indicator.getLookup().setStartCompletionWhenNothingMatches(true);
}
}
}
public static boolean assertPhase(Class<? extends CompletionPhase>... possibilities) {
if (!isPhase(possibilities)) {
LOG.error(ourPhase + "; set at " + ourPhaseTrace);
return false;
}
return true;
}
public static boolean isPhase(Class<? extends CompletionPhase>... possibilities) {
CompletionPhase phase = getCompletionPhase();
for (Class<? extends CompletionPhase> possibility : possibilities) {
if (possibility.isInstance(phase)) {
return true;
}
}
return false;
}
public static void setCompletionPhase(@NotNull CompletionPhase phase) {
ApplicationManager.getApplication().assertIsDispatchThread();
CompletionPhase oldPhase = getCompletionPhase();
CompletionProgressIndicator oldIndicator = oldPhase.indicator;
if (oldIndicator != null && !(phase instanceof CompletionPhase.BgCalculation)) {
LOG.assertTrue(!oldIndicator.isRunning() || oldIndicator.isCanceled(), "don't change phase during running completion: oldPhase=" + oldPhase);
}
Disposer.dispose(oldPhase);
ourPhase = phase;
ourPhaseTrace = DebugUtil.currentStackTrace();
}
public static CompletionPhase getCompletionPhase() {
// ApplicationManager.getApplication().assertIsDispatchThread();
CompletionPhase phase = getPhaseRaw();
ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator();
if (indicator != null) {
indicator.checkCanceled();
}
return phase;
}
public static CompletionPhase getPhaseRaw() {
return ourPhase;
}
public CompletionSorterImpl defaultSorter(CompletionParameters parameters, final PrefixMatcher matcher) {
final CompletionLocation location = new CompletionLocation(parameters);
CompletionSorterImpl sorter = emptySorter();
sorter = sorter.withClassifier(new PreferStartMatching(location));
for (final Weigher weigher : WeighingService.getWeighers(CompletionService.RELEVANCE_KEY)) {
final String id = weigher.toString();
if ("prefix".equals(id)) {
sorter = sorter.withClassifier(new PrefixMatchingClassifier(id, location));
}
else {
sorter = sorter.weigh(new LookupElementWeigher(id, true) {
@Override
public Comparable weigh(@NotNull LookupElement element) {
return weigher.weigh(element, location);
}
});
}
}
if (parameters.getCompletionType() == CompletionType.SMART) {
return sorter;
}
return sorter.withClassifier("priority", true, new ClassifierFactory<LookupElement>("liftShorter") {
@Override
public Classifier<LookupElement> createClassifier(final Classifier<LookupElement> next) {
return new LiftShorterItemsClassifier(next, new LiftShorterItemsClassifier.LiftingCondition());
}
});
}
public CompletionSorterImpl emptySorter() {
return new CompletionSorterImpl(new ArrayList<ClassifierFactory<LookupElement>>());
}
private static class PreferStartMatching extends ClassifierFactory<LookupElement> {
private final CompletionLocation myLocation;
public PreferStartMatching(CompletionLocation location) {
super("startMatching");
myLocation = location;
}
@Override
public Classifier<LookupElement> createClassifier(Classifier<LookupElement> next) {
return new ComparingClassifier<LookupElement>(next, "startMatching") {
@NotNull
@Override
public Comparable getWeight(LookupElement element) {
PrefixMatcher itemMatcher = myLocation.getCompletionParameters().getLookup().itemMatcher(element);
for (String ls : element.getAllLookupStrings()) {
if (itemMatcher.isStartMatch(ls)) {
return false;
}
}
return true;
}
};
}
}
private static class PrefixMatchingClassifier extends ClassifierFactory<LookupElement> {
private final String myId;
private final CompletionLocation myLocation;
public PrefixMatchingClassifier(String id, CompletionLocation location) {
super(id);
myId = id;
myLocation = location;
}
@Override
public Classifier<LookupElement> createClassifier(Classifier<LookupElement> next) {
return new ComparingClassifier<LookupElement>(next, myId) {
@NotNull
@Override
public Comparable getWeight(LookupElement element) {
return -getPrefixMatchingDegree(element, myLocation);
}
};
}
}
}
@@ -22,7 +22,6 @@ import com.intellij.util.ProcessingContext;
import com.intellij.util.SmartList;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.MultiMap;
import gnu.trove.THashMap;
import gnu.trove.THashSet;
import gnu.trove.TObjectHashingStrategy;
import org.jetbrains.annotations.Nullable;
@@ -35,8 +34,8 @@ import java.util.*;
public class LiftShorterItemsClassifier extends Classifier<LookupElement> {
private final TreeSet<String> mySortedStrings = new TreeSet<String>();
private final MultiMap<String, LookupElement> myElements = new MultiMap<String, LookupElement>();
private final Map<LookupElement, Set<LookupElement>> myToLiftForSorting = new THashMap<LookupElement, Set<LookupElement>>(TObjectHashingStrategy.IDENTITY);
private final Map<LookupElement, Set<LookupElement>> myToLiftForPreselection = new THashMap<LookupElement, Set<LookupElement>>(TObjectHashingStrategy.IDENTITY);
private final Map<LookupElement, Set<LookupElement>> myToLiftForSorting = new IdentityHashMap<LookupElement, Set<LookupElement>>();
private final Map<LookupElement, Set<LookupElement>> myToLiftForPreselection = new IdentityHashMap<LookupElement, Set<LookupElement>>();
private final MultiMap<String, String> myPrefixes = new MultiMap<String, String>();
private final Classifier<LookupElement> myNext;
private final LiftingCondition myCondition;
@@ -122,14 +121,12 @@ public class LiftShorterItemsClassifier extends Classifier<LookupElement> {
private List<LookupElement> liftShorterElements(Iterable<LookupElement> source, THashSet<LookupElement> lifted, ProcessingContext context) {
final Set<LookupElement> srcSet = new THashSet<LookupElement>(TObjectHashingStrategy.IDENTITY);
ContainerUtil.addAll(srcSet, source);
final Set<LookupElement> processed = new THashSet<LookupElement>(TObjectHashingStrategy.IDENTITY);
final Set<LookupElement> processed = new THashSet<LookupElement>(srcSet.size(), TObjectHashingStrategy.IDENTITY);
boolean forSorting = context.get(CompletionLookupArranger.PURE_RELEVANCE) != Boolean.TRUE;
final List<LookupElement> result = new ArrayList<LookupElement>();
final List<LookupElement> result = new ArrayList<LookupElement>(srcSet.size());
for (LookupElement element : myNext.classify(source, context)) {
assert srcSet.contains(element) : myNext;
if (processed.add(element)) {
//System.out.println("element = " + element);
List<LookupElement> shorter = addShorterElements(srcSet, processed, null, myToLiftForPreselection.get(element));
if (forSorting) {
shorter = addShorterElements(srcSet, processed, shorter, myToLiftForSorting.get(element));
@@ -151,7 +148,6 @@ public class LiftShorterItemsClassifier extends Classifier<LookupElement> {
@Nullable Set<LookupElement> from) {
if (from != null) {
for (LookupElement shorterElement : from) {
//System.out.println("shorterElement = " + shorterElement);
if (srcSet.contains(shorterElement) && processed.add(shorterElement)) {
if (toLift == null) toLift = new SmartList<LookupElement>();
toLift.add(shorterElement);
@@ -22,6 +22,7 @@ import com.intellij.lang.annotation.AnnotationHolder;
import com.intellij.lang.annotation.AnnotationSession;
import com.intellij.lang.annotation.HighlightSeverity;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement;
@@ -130,7 +131,7 @@ public class AnnotationHolderImpl extends SmartList<Annotation> implements Annot
LOG.assertTrue(containingFile != null, node);
VirtualFile containingVFile = containingFile.getVirtualFile();
VirtualFile myVFile = myFile.getVirtualFile();
if (containingVFile != myVFile) {
if (!Comparing.equal(containingVFile, myVFile)) {
LOG.error(
"Annotation must be registered for an element inside '" + myFile + "' which is in '" + myVFile + "'.\n" +
"Element passed: '" + node + "' is inside the '" + containingFile + "' which is in '" + containingVFile + "'");
@@ -200,7 +200,7 @@ public class QuickEditHandler extends DocumentAdapter implements Disposable {
boolean unsplit = false;
if (mySplittedWindow != null && !mySplittedWindow.isDisposed()) {
final EditorWithProviderComposite[] editors = mySplittedWindow.getEditors();
if (editors.length == 1 && editors[0].getFile() == myNewVirtualFile) {
if (editors.length == 1 && Comparing.equal(editors[0].getFile(), myNewVirtualFile)) {
unsplit = true;
}
}
@@ -15,36 +15,31 @@
*/
package com.intellij.codeInsight.lookup;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Ref;
import com.intellij.psi.ForceableComparable;
import com.intellij.util.ProcessingContext;
import gnu.trove.THashMap;
import gnu.trove.TObjectHashingStrategy;
import org.jetbrains.annotations.NotNull;
import java.util.IdentityHashMap;
import java.util.Map;
/**
* @author peter
*/
public class CachingComparingClassifier extends ComparingClassifier<LookupElement> {
private final Map<LookupElement, Comparable> myWeights = new THashMap<LookupElement, Comparable>(TObjectHashingStrategy.IDENTITY);
private final Map<LookupElement, Comparable> myWeights = new IdentityHashMap<LookupElement, Comparable>();
private final LookupElementWeigher myWeigher;
private Comparable myFirstWeight;
private Ref<Comparable> myFirstWeight;
private boolean myPrimitive = true;
public CachingComparingClassifier(Classifier<LookupElement> next, LookupElementWeigher weigher) {
super(next, weigher.toString());
super(next, weigher.toString(), weigher.isNegated());
myWeigher = weigher;
}
@NotNull
@Override
public final Comparable getWeight(LookupElement t) {
final Comparable weight = myWeights.get(t);
if (weight == null) {
throw new AssertionError(myName + "; " + myWeights.containsKey(t) + "; element=" + t);
}
return weight;
return myWeights.get(t);
}
@Override
@@ -64,8 +59,8 @@ public class CachingComparingClassifier extends ComparingClassifier<LookupElemen
}
if (myPrimitive) {
if (myFirstWeight == null) {
myFirstWeight = weight;
} else if (!myFirstWeight.equals(weight)) {
myFirstWeight = Ref.create(weight);
} else if (!Comparing.equal(myFirstWeight.get(), weight)) {
myPrimitive = false;
}
}
@@ -18,8 +18,7 @@ package com.intellij.codeInsight.lookup;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.util.ProcessingContext;
import com.intellij.util.SmartList;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
@@ -29,54 +28,69 @@ import java.util.*;
public abstract class ComparingClassifier<T> extends Classifier<T> {
protected final Classifier<T> myNext;
protected final String myName;
private final boolean myNegated;
public ComparingClassifier(Classifier<T> next, String name) {
myNext = next;
myName = name;
this(next, name, false);
}
@NotNull
protected ComparingClassifier(Classifier<T> next, String name, boolean negated) {
myNext = next;
myName = name;
myNegated = negated;
}
@Nullable
public abstract Comparable getWeight(T t);
public void addElement(T t) {
myNext.addElement(t);
}
private TreeMap<Comparable, List<T>> groupByWeights(Iterable<T> source) {
TreeMap<Comparable, List<T>> map = new TreeMap<Comparable, List<T>>();
for (T t : source) {
final Comparable weight = getWeight(t);
List<T> list = map.get(weight);
if (list == null) {
map.put(weight, list = new SmartList<T>());
}
list.add(t);
}
return map;
}
@Override
public Iterable<T> classify(Iterable<T> source, ProcessingContext context) {
List<T> result = new ArrayList<T>();
for (List<T> list : groupByWeights(source).values()) {
ContainerUtil.addAll(result, myNext.classify(list, context));
List<T> nulls = null;
TreeMap<Comparable, List<T>> map = new TreeMap<Comparable, List<T>>();
int count = 0;
for (T t : myNext.classify(source, context)) {
count++;
final Comparable weight = getWeight(t);
if (weight == null) {
if (nulls == null) nulls = new SmartList<T>();
nulls.add(t);
} else {
List<T> list = map.get(weight);
if (list == null) {
map.put(weight, list = new SmartList<T>());
}
list.add(t);
}
}
ArrayList<T> result = new ArrayList<T>(count);
Collection<List<T>> values = myNegated ? map.descendingMap().values() : map.values();
for (List<T> value : values) {
result.addAll(value);
}
if (nulls != null) {
result.addAll(nulls);
}
return result;
}
@Override
public void describeItems(LinkedHashMap<T, StringBuilder> map, ProcessingContext context) {
final Map<Comparable, List<T>> treeMap = groupByWeights(new ArrayList<T>(map.keySet()));
if (treeMap.size() > 1 || ApplicationManager.getApplication().isUnitTestMode()) {
for (Map.Entry<Comparable, List<T>> entry: treeMap.entrySet()){
for (T t : entry.getValue()) {
final StringBuilder builder = map.get(t);
if (builder.length() > 0) {
builder.append(", ");
}
builder.append(myName).append("=").append(entry.getKey());
Map<T, String> weights = new IdentityHashMap<T, String>();
for (T t : map.keySet()) {
weights.put(t, String.valueOf(getWeight(t)));
}
if (new HashSet<String>(weights.values()).size() > 1 || ApplicationManager.getApplication().isUnitTestMode() || true) {
for (T t : map.keySet()) {
final StringBuilder builder = map.get(t);
if (builder.length() > 0) {
builder.append(", ");
}
builder.append(myName).append("=").append(weights.get(t));
}
}
myNext.describeItems(map, context);
@@ -33,10 +33,7 @@ import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.*;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vcs.FileStatusListener;
import com.intellij.openapi.vcs.FileStatusManager;
@@ -333,7 +330,7 @@ public class WolfTheProblemSolverImpl extends WolfTheProblemSolver {
Document document = ((TextEditor)editor).getEditor().getDocument();
PsiFile psiFile = PsiDocumentManager.getInstance(myProject).getCachedPsiFile(document);
if (psiFile == null) continue;
if (file == psiFile.getVirtualFile()) return true;
if (Comparing.equal(file, psiFile.getVirtualFile())) return true;
}
return false;
}
@@ -51,10 +51,7 @@ import com.intellij.openapi.fileEditor.impl.FileDocumentManagerImpl;
import com.intellij.openapi.fileEditor.impl.FileEditorManagerImpl;
import com.intellij.openapi.fileTypes.FileTypes;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.*;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiFile;
@@ -583,7 +580,7 @@ public class LanguageConsoleImpl implements Disposable, TypeSafeDataProvider {
myProject.getMessageBus().connect(this).subscribe(FileEditorManagerListener.FILE_EDITOR_MANAGER, new FileEditorManagerAdapter() {
@Override
public void fileOpened(FileEditorManager source, VirtualFile file) {
if (file != myFile.getVirtualFile()) return;
if (!Comparing.equal(file, myFile.getVirtualFile())) return;
if (myConsoleEditor != null) {
Editor selectedTextEditor = source.getSelectedTextEditor();
for (FileEditor fileEditor : source.getAllEditors(file)) {
@@ -608,7 +605,7 @@ public class LanguageConsoleImpl implements Disposable, TypeSafeDataProvider {
@Override
public void fileClosed(FileEditorManager source, VirtualFile file) {
if (file != myFile.getVirtualFile()) return;
if (!Comparing.equal(file, myFile.getVirtualFile())) return;
if (myUiUpdateRunnable != null && !Boolean.TRUE.equals(file.getUserData(FileEditorManagerImpl.CLOSING_TO_REOPEN))) {
if (myCurrentEditor.isDisposed()) myCurrentEditor = null;
ApplicationManager.getApplication().runReadAction(myUiUpdateRunnable);
@@ -656,6 +656,7 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo
}
if (strings.length > 0) {
document.insertString(document.getTextLength(), strings[strings.length - 1]);
myContentSize -= strings.length - 1;
}
}
finally {
@@ -1574,8 +1575,8 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo
* replace text
*
* @param s text for replace
* @param start relativly to all document text
* @param end relativly to all document text
* @param start relatively to all document text
* @param end relatively to all document text
*/
private void replaceUserText(final String s, int start, int end) {
if (start == end) {
@@ -301,7 +301,7 @@ public abstract class RemoteProcessSupport<Target, EntryPoint, Parameters> {
RemoteDeadHand.TwoMinutesTurkish.startCooking("localhost", result.port);
}
catch (Exception e) {
LOG.error(e);
LOG.warn("The cook failed to start due to " + ExceptionUtil.getRootCause(e));
}
}
}
@@ -1,4 +1,3 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
*
@@ -414,7 +413,7 @@ public class FindManagerImpl extends FindManager implements PersistentStateCompo
if(lang == null) return NOT_FOUND_RESULT;
CommentsLiteralsSearchData data = model.getUserData(ourCommentsLiteralsSearchDataKey);
if (data == null || data.lastFile != file) {
if (data == null || !Comparing.equal(data.lastFile, file)) {
Lexer lexer = getLexer(file, lang);
TokenSet tokensOfInterest = TokenSet.EMPTY;
@@ -13,10 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @author Alexey
*/
package com.intellij.ide.actions;
import com.intellij.codeInsight.TargetElementUtilBase;
@@ -53,10 +49,69 @@ import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.jar.JarFile;
import java.util.zip.ZipEntry;
/**
* @author Alexey
*/
public class CopyReferenceAction extends AnAction {
public static final DataFlavor ourFlavor = FileCopyPasteUtil.createJvmDataFlavor(MyTransferable.class);
public static final DataFlavor ourFlavor;
static {
try {
ourFlavor = FileCopyPasteUtil.createJvmDataFlavor(MyTransferable.class);
}
catch (Exception e) {
// todo[r.sh] delete in IDEA 12
final StringBuilder msg = new StringBuilder();
final ClassLoader loader = CopyReferenceAction.class.getClassLoader();
msg.append("loader=").append(loader);
if (loader != null) {
final URL url = loader.getResource("com/intellij/ide/actions/CopyReferenceAction.class");
msg.append(" url=").append(url);
if (url != null) {
if ("jar".equals(url.getProtocol())) {
String path = url.getFile();
msg.append(" path=").append(path);
if (path != null && !path.isEmpty()) {
if (path.startsWith("file:") && path.length() > 5) path = path.substring(5);
if (path.startsWith("//") && path.length() > 2) path = path.substring(2);
final String[] parts = path.split("!/");
if (parts.length == 2) {
try {
final JarFile jar = new JarFile(parts[0]);
try {
msg.append(" jar=").append(jar);
final ZipEntry entry = jar.getEntry(parts[1].replace("CopyReferenceAction.class", "CopyReferenceAction$MyTransferable.class"));
msg.append(" entry=").append(entry);
}
finally {
jar.close();
}
}
catch (IOException e1) {
msg.append(" io=").append(e1.getMessage());
throw new RuntimeException(msg.toString(), e);
}
}
}
}
else {
final String path = url.getFile();
msg.append(" path=").append(path);
if (path != null && !path.isEmpty()) {
final boolean exists = new File(path.replace("CopyReferenceAction.class", "CopyReferenceAction$MyTransferable.class")).exists();
msg.append(" exists=").append(exists);
}
}
}
}
throw new RuntimeException(msg.toString(), e);
}
}
public CopyReferenceAction() {
super();
@@ -28,6 +28,7 @@ import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.project.DumbAwareRunnable;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.startup.StartupManager;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
@@ -79,7 +80,7 @@ public class BookmarkManager extends AbstractProjectComponent implements Persist
public void run() {
if (myProject.isDisposed()) return;
for (Bookmark bookmark : myBookmarks) {
if (bookmark.getFile() == file) {
if (Comparing.equal(bookmark.getFile(), file)) {
bookmark.createHighlighter((MarkupModelEx)DocumentMarkupModel.forDocument(document, myProject, true));
}
}
@@ -165,7 +166,7 @@ public class BookmarkManager extends AbstractProjectComponent implements Persist
@Nullable
public Bookmark findFileBookmark(@NotNull VirtualFile file) {
for (Bookmark bookmark : myBookmarks) {
if (bookmark.getFile() == file && bookmark.getLine() == -1) return bookmark;
if (Comparing.equal(bookmark.getFile(), file) && bookmark.getLine() == -1) return bookmark;
}
return null;
@@ -26,6 +26,7 @@ import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.roots.impl.ModifiableModelCommitter;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.*;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VfsUtil;
@@ -104,7 +105,7 @@ public class PatchProjectUtil {
if (included.isEmpty()) return;
final Set<VirtualFile> parents = new HashSet<VirtualFile>();
for (VirtualFile file : included) {
if (file == contentEntry.getFile()) return;
if (Comparing.equal(file, contentEntry.getFile())) return;
final VirtualFile parent = file.getParent();
if (parent == null || parents.contains(parent)) continue;
parents.add(parent);
@@ -24,6 +24,7 @@ import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ProjectFileIndex;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiFileSystemItem;
@@ -57,7 +58,7 @@ public class ProjectPaneSelectInTarget extends ProjectViewSelectInTarget impleme
return true;
}
return vFile.getParent() == myProject.getBaseDir();
return Comparing.equal(vFile.getParent(), myProject.getBaseDir());
}
return false;
@@ -22,6 +22,7 @@ import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.roots.*;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
@@ -65,7 +66,7 @@ public class MarkRootAction extends AnAction {
if (entry != null) {
final SourceFolder[] sourceFolders = entry.getSourceFolders();
for (SourceFolder sourceFolder : sourceFolders) {
if (sourceFolder.getFile() == vFile) {
if (Comparing.equal(sourceFolder.getFile(), vFile)) {
entry.removeSourceFolder(sourceFolder);
break;
}
@@ -126,7 +127,7 @@ public class MarkRootAction extends AnAction {
if (!fileIndex.isInContent(vFile)) {
return false;
}
if (fileIndex.getSourceRootForFile(vFile) == vFile) {
if (Comparing.equal(fileIndex.getSourceRootForFile(vFile), vFile)) {
boolean isTestSourceRoot = fileIndex.isInTestSourceContent(vFile);
if (acceptSourceRoot && !isTestSourceRoot) {
if (rootType != null) rootType.set(true);
@@ -18,6 +18,7 @@ package com.intellij.ide.projectView.impl;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.*;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiDirectory;
@@ -63,7 +64,7 @@ public class ProjectRootsUtil {
for (ContentEntry contentEntry : contentEntries) {
final SourceFolder[] sourceFolders = contentEntry.getSourceFolders();
for (SourceFolder sourceFolder : sourceFolders) {
if (virtualFile == sourceFolder.getFile()) return true;
if (Comparing.equal(virtualFile, sourceFolder.getFile())) return true;
}
}
return false;
@@ -113,7 +113,7 @@ public class ProjectViewDirectoryHelper {
public boolean canRepresent(Object element, PsiDirectory directory) {
if (element instanceof VirtualFile) {
VirtualFile vFile = (VirtualFile) element;
return directory.getVirtualFile() == vFile;
return Comparing.equal(directory.getVirtualFile(), vFile);
}
return false;
}
@@ -180,7 +180,7 @@ public class ProjectViewDirectoryHelper {
while (current != null) {
VirtualFile parent = current.getParent();
if (parent == dir) {
if (Comparing.equal(parent, dir)) {
final PsiDirectory psi = manager.findDirectory(current);
if (psi != null) {
directoriesOnTheWayToContentRoots.add(psi);
@@ -298,7 +298,7 @@ public class PsiDirectoryNode extends BasePsiNode<PsiDirectory> implements Navig
if (ProjectAttachProcessor.canAttachToProject()) {
// primary module is always on top; attached modules are sorted alphabetically
final VirtualFile file = getVirtualFile();
if (file == myProject.getBaseDir()) {
if (Comparing.equal(file, myProject.getBaseDir())) {
return ""; // sorts before any other name
}
return getTitle();
@@ -26,6 +26,7 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.OrderEntry;
import com.intellij.openapi.roots.libraries.LibraryUtil;
import com.intellij.openapi.roots.ui.configuration.ProjectSettingsService;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Iconable;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.JarFileSystem;
@@ -175,6 +176,6 @@ public class PsiFileNode extends BasePsiNode<PsiFile> implements NavigatableWith
@Override
public boolean contains(@NotNull VirtualFile file) {
return super.contains(file) || isArchive() && PathUtil.getLocalFile(file) == getVirtualFile();
return super.contains(file) || isArchive() && Comparing.equal(PathUtil.getLocalFile(file), getVirtualFile());
}
}
@@ -21,6 +21,7 @@ import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.impl.FilePropertyPusher;
import com.intellij.openapi.roots.impl.PushedFilePropertiesUpdater;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileManager;
import com.intellij.testFramework.LightVirtualFile;
@@ -76,7 +77,7 @@ public abstract class LanguagePerFileMappings<T> implements PersistentStateCompo
file = window.getDelegate();
}
VirtualFile originalFile = file instanceof LightVirtualFile ? ((LightVirtualFile)file).getOriginalFile() : null;
if (originalFile == file) originalFile = null;
if (Comparing.equal(originalFile, file)) originalFile = null;
if (file != null) {
final FilePropertyPusher<T> pusher = getFilePropertyPusher();
@@ -1,168 +1,170 @@
/*
* Copyright 2000-2012 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.openapi.fileEditor.impl;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.fileEditor.impl.text.TextEditorPsiDataProvider;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleUtil;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.problems.WolfTheProblemSolver;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
import com.intellij.ui.ColorUtil;
import com.intellij.ui.docking.DockManager;
import org.jetbrains.annotations.NotNull;
import java.awt.*;
/**
* @author yole
*/
public class PsiAwareFileEditorManagerImpl extends FileEditorManagerImpl {
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.fileEditor.impl.text.PsiAwareFileEditorManagerImpl");
private final PsiManager myPsiManager;
private final WolfTheProblemSolver myProblemSolver;
/**
* Updates icons for open files when project roots change
*/
private final MyPsiTreeChangeListener myPsiTreeChangeListener;
private final WolfTheProblemSolver.ProblemListener myProblemListener;
public PsiAwareFileEditorManagerImpl(final Project project, final PsiManager psiManager, final WolfTheProblemSolver problemSolver, DockManager dockManager) {
super(project, dockManager);
myPsiManager = psiManager;
myProblemSolver = problemSolver;
myPsiTreeChangeListener = new MyPsiTreeChangeListener();
myProblemListener = new MyProblemListener();
registerExtraEditorDataProvider(new TextEditorPsiDataProvider(), null);
}
@Override
public void projectOpened() {
super.projectOpened(); //To change body of overridden methods use File | Settings | File Templates.
myPsiManager.addPsiTreeChangeListener(myPsiTreeChangeListener);
myProblemSolver.addProblemListener(myProblemListener);
}
@Override
public Color getFileColor(@NotNull final VirtualFile file) {
Color color = super.getFileColor(file);
if (myProblemSolver.isProblemFile(file)) {
return ColorUtil.toAlpha(color, WaverGraphicsDecorator.WAVE_ALPHA_KEY);
}
return color;
}
public boolean isProblem(@NotNull final VirtualFile file) {
return myProblemSolver.isProblemFile(file);
}
public String getFileTooltipText(final VirtualFile file) {
final StringBuilder tooltipText = new StringBuilder();
final Module module = ModuleUtil.findModuleForFile(file, getProject());
if (module != null) {
tooltipText.append("[");
tooltipText.append(module.getName());
tooltipText.append("] ");
}
tooltipText.append(FileUtil.getLocationRelativeToUserHome(file.getPresentableUrl()));
return tooltipText.toString();
}
@Override
protected Editor getOpenedEditor(final Editor editor, final boolean focusEditor) {
PsiDocumentManager documentManager = PsiDocumentManager.getInstance(getProject());
Document document = editor.getDocument();
PsiFile psiFile = documentManager.getPsiFile(document);
if (!focusEditor || documentManager.isUncommited(document)) {
return editor;
}
return InjectedLanguageUtil.getEditorForInjectedLanguageNoCommit(editor, psiFile);
}
/**
* Updates attribute of open files when roots change
*/
private final class MyPsiTreeChangeListener extends PsiTreeChangeAdapter {
public void propertyChanged(@NotNull final PsiTreeChangeEvent e) {
if (PsiTreeChangeEvent.PROP_ROOTS.equals(e.getPropertyName())) {
ApplicationManager.getApplication().assertIsDispatchThread();
final VirtualFile[] openFiles = getOpenFiles();
for (int i = openFiles.length - 1; i >= 0; i--) {
final VirtualFile file = openFiles[i];
LOG.assertTrue(file != null);
updateFileIcon(file);
}
}
}
public void childAdded(@NotNull PsiTreeChangeEvent event) {
doChange(event);
}
public void childRemoved(@NotNull PsiTreeChangeEvent event) {
doChange(event);
}
public void childReplaced(@NotNull PsiTreeChangeEvent event) {
doChange(event);
}
public void childMoved(@NotNull PsiTreeChangeEvent event) {
doChange(event);
}
public void childrenChanged(@NotNull PsiTreeChangeEvent event) {
doChange(event);
}
private void doChange(final PsiTreeChangeEvent event) {
final PsiFile psiFile = event.getFile();
final VirtualFile currentFile = getCurrentFile();
if (currentFile != null && psiFile != null && psiFile.getVirtualFile() == currentFile) {
updateFileIcon(currentFile);
}
}
}
private class MyProblemListener extends WolfTheProblemSolver.ProblemListener {
public void problemsAppeared(final VirtualFile file) {
updateFile(file);
}
public void problemsDisappeared(VirtualFile file) {
updateFile(file);
}
public void problemsChanged(VirtualFile file) {
updateFile(file);
}
private void updateFile(final VirtualFile file) {
queueUpdateFile(file);
}
}
}
/*
* Copyright 2000-2012 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.openapi.fileEditor.impl;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.fileEditor.impl.text.TextEditorPsiDataProvider;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleUtil;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.problems.WolfTheProblemSolver;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
import com.intellij.ui.ColorUtil;
import com.intellij.ui.docking.DockManager;
import org.jetbrains.annotations.NotNull;
import java.awt.*;
/**
* @author yole
*/
public class PsiAwareFileEditorManagerImpl extends FileEditorManagerImpl {
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.fileEditor.impl.text.PsiAwareFileEditorManagerImpl");
private final PsiManager myPsiManager;
private final WolfTheProblemSolver myProblemSolver;
/**
* Updates icons for open files when project roots change
*/
private final MyPsiTreeChangeListener myPsiTreeChangeListener;
private final WolfTheProblemSolver.ProblemListener myProblemListener;
public PsiAwareFileEditorManagerImpl(final Project project, final PsiManager psiManager, final WolfTheProblemSolver problemSolver, DockManager dockManager) {
super(project, dockManager);
myPsiManager = psiManager;
myProblemSolver = problemSolver;
myPsiTreeChangeListener = new MyPsiTreeChangeListener();
myProblemListener = new MyProblemListener();
registerExtraEditorDataProvider(new TextEditorPsiDataProvider(), null);
}
@Override
public void projectOpened() {
super.projectOpened(); //To change body of overridden methods use File | Settings | File Templates.
myPsiManager.addPsiTreeChangeListener(myPsiTreeChangeListener);
myProblemSolver.addProblemListener(myProblemListener);
}
@Override
public Color getFileColor(@NotNull final VirtualFile file) {
Color color = super.getFileColor(file);
if (myProblemSolver.isProblemFile(file)) {
return ColorUtil.toAlpha(color, WaverGraphicsDecorator.WAVE_ALPHA_KEY);
}
return color;
}
public boolean isProblem(@NotNull final VirtualFile file) {
return myProblemSolver.isProblemFile(file);
}
public String getFileTooltipText(final VirtualFile file) {
final StringBuilder tooltipText = new StringBuilder();
final Module module = ModuleUtil.findModuleForFile(file, getProject());
if (module != null) {
tooltipText.append("[");
tooltipText.append(module.getName());
tooltipText.append("] ");
}
tooltipText.append(FileUtil.getLocationRelativeToUserHome(file.getPresentableUrl()));
return tooltipText.toString();
}
@Override
protected Editor getOpenedEditor(final Editor editor, final boolean focusEditor) {
PsiDocumentManager documentManager = PsiDocumentManager.getInstance(getProject());
Document document = editor.getDocument();
PsiFile psiFile = documentManager.getPsiFile(document);
if (!focusEditor || documentManager.isUncommited(document)) {
return editor;
}
return InjectedLanguageUtil.getEditorForInjectedLanguageNoCommit(editor, psiFile);
}
/**
* Updates attribute of open files when roots change
*/
private final class MyPsiTreeChangeListener extends PsiTreeChangeAdapter {
public void propertyChanged(@NotNull final PsiTreeChangeEvent e) {
if (PsiTreeChangeEvent.PROP_ROOTS.equals(e.getPropertyName())) {
ApplicationManager.getApplication().assertIsDispatchThread();
final VirtualFile[] openFiles = getOpenFiles();
for (int i = openFiles.length - 1; i >= 0; i--) {
final VirtualFile file = openFiles[i];
LOG.assertTrue(file != null);
updateFileIcon(file);
}
}
}
public void childAdded(@NotNull PsiTreeChangeEvent event) {
doChange(event);
}
public void childRemoved(@NotNull PsiTreeChangeEvent event) {
doChange(event);
}
public void childReplaced(@NotNull PsiTreeChangeEvent event) {
doChange(event);
}
public void childMoved(@NotNull PsiTreeChangeEvent event) {
doChange(event);
}
public void childrenChanged(@NotNull PsiTreeChangeEvent event) {
doChange(event);
}
private void doChange(final PsiTreeChangeEvent event) {
final PsiFile psiFile = event.getFile();
final VirtualFile currentFile = getCurrentFile();
if (currentFile != null && psiFile != null && Comparing.equal(psiFile.getVirtualFile(), currentFile)) {
updateFileIcon(currentFile);
}
}
}
private class MyProblemListener extends WolfTheProblemSolver.ProblemListener {
public void problemsAppeared(final VirtualFile file) {
updateFile(file);
}
public void problemsDisappeared(VirtualFile file) {
updateFile(file);
}
public void problemsChanged(VirtualFile file) {
updateFile(file);
}
private void updateFile(final VirtualFile file) {
queueUpdateFile(file);
}
}
}
@@ -33,6 +33,7 @@ import com.intellij.openapi.fileEditor.impl.text.TextEditorPsiDataProvider;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.ActionCallback;
import com.intellij.openapi.util.AsyncResult;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
@@ -331,7 +332,7 @@ import java.util.Map;
if (editor != null){
EditorFactory.getInstance().releaseEditor(editor);
}
if (file == myActiveFile) myActiveFile = null;
if (Comparing.equal(file, myActiveFile)) myActiveFile = null;
}
@Override
@@ -17,6 +17,7 @@
package com.intellij.openapi.vcs.changes.patch;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiFile;
@@ -47,7 +48,7 @@ public class PsiPatchBaseDirectoryDetector extends PatchBaseDirectoryDetector {
if (psiFiles.length == 1) {
PsiDirectory parent = psiFiles [0].getContainingDirectory();
for(int i=nameComponents.length-2; i >= 0; i--) {
if (!parent.getName().equals(nameComponents [i]) || parent.getVirtualFile() == myProject.getBaseDir()) {
if (!parent.getName().equals(nameComponents[i]) || Comparing.equal(parent.getVirtualFile(), myProject.getBaseDir())) {
return new Result(parent.getVirtualFile().getPresentableUrl(), i+1);
}
parent = parent.getParentDirectory();
@@ -20,6 +20,7 @@ import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ProjectFileIndex;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.Nullable;
@@ -48,7 +49,7 @@ public class ChangesModuleGroupingPolicy implements ChangesGroupingPolicy {
ProjectFileIndex index = ProjectRootManager.getInstance(myProject).getFileIndex();
VirtualFile vFile = node.getVf();
if (vFile != null && vFile == index.getContentRootForFile(vFile)) {
if (vFile != null && Comparing.equal(vFile, index.getContentRootForFile(vFile))) {
Module module = index.getModuleForFile(vFile);
return getNodeForModule(module, rootNode);
}
@@ -21,6 +21,7 @@ import com.intellij.ide.projectView.impl.nodes.ProjectViewDirectoryHelper;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ProjectFileIndex;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
@@ -61,12 +62,12 @@ public class DirectoryNode extends PackageDependenciesNode {
if (showFQName) {
final VirtualFile contentRoot = index.getContentRootForFile(myVDirectory);
if (contentRoot != null) {
if (myVDirectory == contentRoot) {
if (Comparing.equal(myVDirectory, contentRoot)) {
myFQName = dirName;
}
else {
final VirtualFile sourceRoot = index.getSourceRootForFile(myVDirectory);
if (myVDirectory == sourceRoot) {
if (Comparing.equal(myVDirectory, sourceRoot)) {
myFQName = VfsUtilCore.getRelativePath(myVDirectory, contentRoot, '/');
}
else if (sourceRoot != null) {
@@ -96,10 +97,11 @@ public class DirectoryNode extends PackageDependenciesNode {
private String getContentRootName(final VirtualFile baseDir, final String dirName) {
if (baseDir != null) {
if (myVDirectory != baseDir) {
if (!Comparing.equal(myVDirectory, baseDir)) {
if (VfsUtil.isAncestor(baseDir, myVDirectory, false)) {
return VfsUtilCore.getRelativePath(myVDirectory, baseDir, '/');
} else {
}
else {
return myVDirectory.getPresentableUrl();
}
}
@@ -140,7 +142,7 @@ public class DirectoryNode extends PackageDependenciesNode {
final ProjectFileIndex index = ProjectRootManager.getInstance(myProject).getFileIndex();
VirtualFile directory = myVDirectory;
VirtualFile contentRoot = index.getContentRootForFile(directory);
if (directory == contentRoot) {
if (Comparing.equal(directory, contentRoot)) {
return "";
}
if (contentRoot == null) {
@@ -30,6 +30,7 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ContentIterator;
import com.intellij.openapi.roots.ProjectFileIndex;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VfsUtil;
@@ -431,7 +432,7 @@ public class FileTreeModelBuilder {
else if (node instanceof FileNode) { //non java files
psiFile = ((PsiFile)node.getPsiElement());
}
if (psiFile != null && psiFile.getVirtualFile() == ((PsiFile)element).getVirtualFile()) {
if (psiFile != null && Comparing.equal(psiFile.getVirtualFile(), ((PsiFile)element).getVirtualFile())) {
result.add(node);
}
}
@@ -497,7 +498,7 @@ public class FileTreeModelBuilder {
final VirtualFile directory = virtualFile.getParent();
if (!myFlattenPackages && directory != null) {
if (myCompactEmptyMiddlePackages && sourceRoot != virtualFile && contentRoot != virtualFile) {//compact
if (myCompactEmptyMiddlePackages && !Comparing.equal(sourceRoot, virtualFile) && !Comparing.equal(contentRoot, virtualFile)) {//compact
((DirectoryNode)directoryNode).setCompactedDirNode(childNode);
}
if (fileIndex.getModuleForFile(directory) == module) {
@@ -505,7 +506,7 @@ public class FileTreeModelBuilder {
if (parentDirectoryNode != null
|| !myCompactEmptyMiddlePackages
|| (sourceRoot != null && VfsUtil.isAncestor(directory, sourceRoot, false) && fileIndex.getSourceRootForFile(directory) != null)
|| directory == contentRoot) {
|| Comparing.equal(directory, contentRoot)) {
getModuleDirNode(directory, module, (DirectoryNode)directoryNode).add(directoryNode);
}
else {
@@ -517,15 +518,18 @@ public class FileTreeModelBuilder {
}
}
else {
if (contentRoot == virtualFile) {
if (Comparing.equal(contentRoot, virtualFile)) {
getModuleNode(module).add(directoryNode);
} else {
}
else {
final VirtualFile root;
if (sourceRoot != virtualFile && sourceRoot != null) {
if (!Comparing.equal(sourceRoot, virtualFile) && sourceRoot != null) {
root = sourceRoot;
} else if (contentRoot != null) {
}
else if (contentRoot != null) {
root = contentRoot;
} else {
}
else {
root = null;
}
if (root != null) {
@@ -586,7 +590,7 @@ public class FileTreeModelBuilder {
public boolean processFile(VirtualFile fileOrDir) {
if (!fileOrDir.isDirectory()) {
if (lastParent != null && dir != fileOrDir.getParent()) {
if (lastParent != null && !Comparing.equal(dir, fileOrDir.getParent())) {
lastParent = null;
}
lastParent = buildFileNode(fileOrDir, lastParent);
@@ -29,6 +29,7 @@ import com.intellij.openapi.project.ex.ProjectManagerEx;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.roots.ModuleRootModificationUtil;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vcs.AbstractVcs;
@@ -160,7 +161,7 @@ public class ModuleAttachProcessor extends ProjectAttachProcessor {
for (Module module : ModuleManager.getInstance(project).getModules()) {
final VirtualFile[] roots = ModuleRootManager.getInstance(module).getContentRoots();
for (VirtualFile root : roots) {
if (root == project.getBaseDir()) {
if (Comparing.equal(root, project.getBaseDir())) {
return module;
}
}
@@ -23,6 +23,7 @@ import com.intellij.ide.util.treeView.AbstractTreeNode;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ProjectFileIndex;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiDirectory;
@@ -43,7 +44,7 @@ public class PlatformProjectViewStructureProvider implements TreeStructureProvid
public Collection<AbstractTreeNode> modify(final AbstractTreeNode parent, final Collection<AbstractTreeNode> children, final ViewSettings settings) {
if (parent instanceof PsiDirectoryNode) {
final VirtualFile vFile = ((PsiDirectoryNode)parent).getVirtualFile();
if (vFile != null && ProjectFileIndex.SERVICE.getInstance(myProject).getContentRootForFile(vFile) == vFile) {
if (vFile != null && Comparing.equal(ProjectFileIndex.SERVICE.getInstance(myProject).getContentRootForFile(vFile), vFile)) {
final Collection<AbstractTreeNode> moduleChildren = ((PsiDirectoryNode) parent).getChildren();
Collection<AbstractTreeNode> result = new ArrayList<AbstractTreeNode>();
for (AbstractTreeNode moduleChild : moduleChildren) {
@@ -71,7 +71,7 @@ class FileElementInfo implements SmartPointerElementInfo {
@Override
public boolean pointsToTheSameElementAs(@NotNull SmartPointerElementInfo other) {
if (other instanceof FileElementInfo) {
return myVirtualFile == ((FileElementInfo)other).myVirtualFile;
return Comparing.equal(myVirtualFile, ((FileElementInfo)other).myVirtualFile);
}
return Comparing.equal(restoreElement(), other.restoreElement());
}
@@ -286,12 +286,12 @@ public class SelfElementInfo implements SmartPointerElementInfo {
public boolean pointsToTheSameElementAs(@NotNull SmartPointerElementInfo other) {
if (other instanceof SelfElementInfo) {
SelfElementInfo otherInfo = (SelfElementInfo)other;
return myVirtualFile == otherInfo.myVirtualFile
&& myType == otherInfo.myType
&& mySyncMarkerIsValid
&& otherInfo.mySyncMarkerIsValid
&& mySyncStartOffset == otherInfo.mySyncStartOffset
&& mySyncEndOffset == otherInfo.mySyncEndOffset
return Comparing.equal(myVirtualFile, otherInfo.myVirtualFile)
&& myType == otherInfo.myType
&& mySyncMarkerIsValid
&& otherInfo.mySyncMarkerIsValid
&& mySyncStartOffset == otherInfo.mySyncStartOffset
&& mySyncEndOffset == otherInfo.mySyncEndOffset
;
}
return Comparing.equal(restoreElement(), other.restoreElement());
@@ -23,6 +23,7 @@ import com.intellij.openapi.module.ModuleUtil;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.*;
import com.intellij.openapi.roots.impl.DirectoryIndex;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
@@ -84,7 +85,7 @@ public class PsiFileReferenceHelper extends FileReferenceHelper {
if (orderEntry instanceof ModuleSourceOrderEntry) {
for(ContentEntry e: ((ModuleSourceOrderEntry)orderEntry).getRootModel().getContentEntries()) {
for(SourceFolder sf:e.getSourceFolders()) {
if (sf.getFile() == root) {
if (Comparing.equal(sf.getFile(), root)) {
String s = sf.getPackagePrefix();
if (s.length() > 0) {
path = s + "." + path;
@@ -345,7 +345,10 @@ public class MultiHostRegistrarImpl implements MultiHostRegistrar, ModificationT
assert documentWindow.getText().equals(psiFile.getText()) : "Document window text mismatch";
assert injectedFileViewProvider.getDocument() == documentWindow : "Provider document mismatch";
assert documentManager.getCachedDocument(psiFile) == documentWindow : "Cached document mismatch";
assert psiFile.getVirtualFile() == injectedFileViewProvider.getVirtualFile() : "Virtual file mismatch: "+psiFile.getVirtualFile()+"; "+injectedFileViewProvider.getVirtualFile();
assert Comparing.equal(psiFile.getVirtualFile(), injectedFileViewProvider.getVirtualFile()) : "Virtual file mismatch: " +
psiFile.getVirtualFile() +
"; " +
injectedFileViewProvider.getVirtualFile();
PsiDocumentManagerImpl.checkConsistency(psiFile, documentWindow);
}
@@ -29,6 +29,7 @@ import com.intellij.openapi.roots.ProjectFileIndex;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiDirectory;
@@ -67,7 +68,7 @@ public abstract class DirectoryAsPackageRenameHandlerBase<T extends PsiDirectory
if (element instanceof PsiDirectory) {
final VirtualFile virtualFile = ((PsiDirectory)element).getVirtualFile();
final Project project = element.getProject();
if (project.getBaseDir() == virtualFile) return false;
if (Comparing.equal(project.getBaseDir(), virtualFile)) return false;
if (ProjectRootManager.getInstance(project).getFileIndex().isInContent(virtualFile)) {
return true;
}
@@ -194,7 +194,7 @@ public abstract class InplaceRefactoring {
}
protected boolean notSameFile(@Nullable VirtualFile file, PsiFile containingFile) {
return getTopLevelVirtualFile(containingFile.getViewProvider()) != file;
return !Comparing.equal(getTopLevelVirtualFile(containingFile.getViewProvider()), file);
}
protected SearchScope getReferencesSearchScope(VirtualFile file) {
@@ -1437,7 +1437,7 @@ public class FileBasedIndexImpl extends FileBasedIndex {
}
if (restrictedFile != null) {
if(vFile != restrictedFile) {
if (!Comparing.equal(vFile, restrictedFile)) {
return false;
}
}
@@ -2000,7 +2000,7 @@ public class FileBasedIndexImpl extends FileBasedIndex {
boolean onlyRemoveOutdatedData) {
myChangedFilesCollector.ensureAllInvalidateTasksCompleted();
for (VirtualFile file: getAllFilesToUpdate()) {
if (filter == null || filter.accept(file) || file == restrictedTo) {
if (filter == null || filter.accept(file) || Comparing.equal(file, restrictedTo)) {
try {
myForceUpdateSemaphore.down();
// process only files that can affect result
@@ -1,218 +1,219 @@
/*
* Copyright 2000-2009 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.util.indexing;
import com.intellij.openapi.vfs.InvalidVirtualFileAccessException;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.newvfs.FileAttribute;
import com.intellij.openapi.vfs.newvfs.NewVirtualFile;
import com.intellij.util.containers.ConcurrentHashMap;
import com.intellij.util.io.DataInputOutputUtil;
import gnu.trove.TObjectLongHashMap;
import gnu.trove.TObjectLongProcedure;
import org.jetbrains.annotations.Nullable;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.concurrent.ArrayBlockingQueue;
/**
* @author Eugene Zhuravlev
* Date: Dec 25, 2007
*/
public class IndexingStamp {
private IndexingStamp() {
}
/**
* The class is meant to be accessed from synchronized block only
*/
private static class Timestamps {
private static final FileAttribute PERSISTENCE = new FileAttribute("__index_stamps__", 1, false);
private TObjectLongHashMap<ID<?, ?>> myIndexStamps;
private boolean myIsDirty = false;
private Timestamps(@Nullable DataInputStream stream) throws IOException {
if (stream != null) {
try {
if (stream.available() > 0) {
long dominatingIndexStamp = DataInputOutputUtil.readTIME(stream);
while(stream.available() > 0) {
ID<?, ?> id = ID.findById(DataInputOutputUtil.readINT(stream));
if (id != null) {
long stamp = IndexInfrastructure.getIndexCreationStamp(id);
if (myIndexStamps == null) myIndexStamps = new TObjectLongHashMap<ID<?, ?>>(5, 0.98f);
if (stamp <= dominatingIndexStamp) myIndexStamps.put(id, stamp);
}
}
}
}
finally {
stream.close();
}
}
}
private void writeToStream(final DataOutputStream stream) throws IOException {
if (myIndexStamps != null) {
final long[] dominatingIndexStamp = new long[1];
myIndexStamps.forEachEntry(
new TObjectLongProcedure<ID<?, ?>>() {
@Override
public boolean execute(ID<?, ?> a, long b) {
dominatingIndexStamp[0] = Math.max(dominatingIndexStamp[0], b);
return true;
}
}
);
DataInputOutputUtil.writeTIME(stream, dominatingIndexStamp[0]);
myIndexStamps.forEachEntry(new TObjectLongProcedure<ID<?, ?>>() {
@Override
public boolean execute(final ID<?, ?> id, final long timestamp) {
try {
DataInputOutputUtil.writeINT(stream, id.getUniqueId());
return true;
}
catch (IOException e) {
throw new RuntimeException(e);
}
}
});
}
}
public long get(ID<?, ?> id) {
return myIndexStamps != null? myIndexStamps.get(id) : 0L;
}
public void set(ID<?, ?> id, long tmst) {
try {
if (tmst < 0) {
if (myIndexStamps == null) return;
myIndexStamps.remove(id);
return;
}
if (myIndexStamps == null) myIndexStamps = new TObjectLongHashMap<ID<?, ?>>(5, 0.98f);
myIndexStamps.put(id, tmst);
}
finally {
myIsDirty = true;
}
}
public boolean isDirty() {
return myIsDirty;
}
}
private static final ConcurrentHashMap<VirtualFile, Timestamps> myTimestampsCache = new ConcurrentHashMap<VirtualFile, Timestamps>();
private static final int CAPACITY = 100;
private static final ArrayBlockingQueue<VirtualFile> myFinishedFiles = new ArrayBlockingQueue<VirtualFile>(CAPACITY);
public static boolean isFileIndexed(VirtualFile file, ID<?, ?> indexName, final long indexCreationStamp) {
try {
return getIndexStamp(file, indexName) == indexCreationStamp;
}
catch (RuntimeException e) {
final Throwable cause = e.getCause();
if (!(cause instanceof IOException)) {
throw e; // in case of IO exceptions consider file unindexed
}
}
return false;
}
public static long getIndexStamp(VirtualFile file, ID<?, ?> indexName) {
synchronized (file) {
Timestamps stamp = createOrGetTimeStamp(file);
if (stamp != null) return stamp.get(indexName);
return 0;
}
}
private static Timestamps createOrGetTimeStamp(VirtualFile file) {
if (file instanceof NewVirtualFile && file.isValid()) {
Timestamps timestamps = myTimestampsCache.get(file);
if (timestamps == null) {
synchronized (myTimestampsCache) { // avoid synchroneous reads TODO:
timestamps = myTimestampsCache.get(file);
if (timestamps == null) {
final DataInputStream stream = Timestamps.PERSISTENCE.readAttribute(file);
try {
timestamps = new Timestamps(stream);
}
catch (IOException e) {
throw new RuntimeException(e);
}
myTimestampsCache.put(file, timestamps);
}
}
}
return timestamps;
}
return null;
}
public static void update(final VirtualFile file, final ID<?, ?> indexName, final long indexCreationStamp) {
synchronized (file) {
try {
Timestamps stamp = createOrGetTimeStamp(file);
if (stamp != null) stamp.set(indexName, indexCreationStamp);
}
catch (InvalidVirtualFileAccessException ignored /*ok to ignore it here*/) {
}
}
}
public static void flushCache(@Nullable VirtualFile finishedFile) {
if (finishedFile == null || !myFinishedFiles.offer(finishedFile)) {
VirtualFile[] files = null;
synchronized (myFinishedFiles) {
int size = myFinishedFiles.size();
if ((finishedFile == null && size > 0) || size == CAPACITY) {
files = myFinishedFiles.toArray(new VirtualFile[size]);
myFinishedFiles.clear();
}
}
if (files != null) {
for(VirtualFile file:files) {
synchronized (file) {
Timestamps timestamp = myTimestampsCache.remove(file);
if (timestamp == null) continue;
synchronized (myTimestampsCache) {
try {
if (timestamp.isDirty() && file.isValid()) {
final DataOutputStream sink = Timestamps.PERSISTENCE.writeAttribute(file);
timestamp.writeToStream(sink);
sink.close();
}
}
catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
}
if (finishedFile != null) myFinishedFiles.offer(finishedFile);
}
}
}
/*
* Copyright 2000-2009 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.util.indexing;
import com.intellij.openapi.vfs.InvalidVirtualFileAccessException;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.newvfs.FileAttribute;
import com.intellij.openapi.vfs.newvfs.NewVirtualFile;
import com.intellij.util.containers.ConcurrentHashMap;
import com.intellij.util.io.DataInputOutputUtil;
import gnu.trove.TObjectLongHashMap;
import gnu.trove.TObjectLongProcedure;
import org.jetbrains.annotations.Nullable;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.concurrent.ArrayBlockingQueue;
/**
* @author Eugene Zhuravlev
* Date: Dec 25, 2007
*/
public class IndexingStamp {
private IndexingStamp() {
}
/**
* The class is meant to be accessed from synchronized block only
*/
private static class Timestamps {
private static final FileAttribute PERSISTENCE = new FileAttribute("__index_stamps__", 1, false);
private TObjectLongHashMap<ID<?, ?>> myIndexStamps;
private boolean myIsDirty = false;
private Timestamps(@Nullable DataInputStream stream) throws IOException {
if (stream != null) {
try {
long dominatingIndexStamp = DataInputOutputUtil.readTIME(stream);
while(stream.available() > 0) {
ID<?, ?> id = ID.findById(DataInputOutputUtil.readINT(stream));
if (id != null) {
long stamp = IndexInfrastructure.getIndexCreationStamp(id);
if (myIndexStamps == null) myIndexStamps = new TObjectLongHashMap<ID<?, ?>>(5, 0.98f);
if (stamp <= dominatingIndexStamp) myIndexStamps.put(id, stamp);
}
}
}
finally {
stream.close();
}
}
}
private void writeToStream(final DataOutputStream stream) throws IOException {
if (myIndexStamps != null && !myIndexStamps.isEmpty()) {
final long[] dominatingIndexStamp = new long[1];
myIndexStamps.forEachEntry(
new TObjectLongProcedure<ID<?, ?>>() {
@Override
public boolean execute(ID<?, ?> a, long b) {
dominatingIndexStamp[0] = Math.max(dominatingIndexStamp[0], b);
return true;
}
}
);
DataInputOutputUtil.writeTIME(stream, dominatingIndexStamp[0]);
myIndexStamps.forEachEntry(new TObjectLongProcedure<ID<?, ?>>() {
@Override
public boolean execute(final ID<?, ?> id, final long timestamp) {
try {
DataInputOutputUtil.writeINT(stream, id.getUniqueId());
return true;
}
catch (IOException e) {
throw new RuntimeException(e);
}
}
});
} else {
DataInputOutputUtil.writeTIME(stream, DataInputOutputUtil.timeBase);
}
}
public long get(ID<?, ?> id) {
return myIndexStamps != null? myIndexStamps.get(id) : 0L;
}
public void set(ID<?, ?> id, long tmst) {
try {
if (tmst < 0) {
if (myIndexStamps == null) return;
myIndexStamps.remove(id);
return;
}
if (myIndexStamps == null) myIndexStamps = new TObjectLongHashMap<ID<?, ?>>(5, 0.98f);
myIndexStamps.put(id, tmst);
}
finally {
myIsDirty = true;
}
}
public boolean isDirty() {
return myIsDirty;
}
}
private static final ConcurrentHashMap<VirtualFile, Timestamps> myTimestampsCache = new ConcurrentHashMap<VirtualFile, Timestamps>();
private static final int CAPACITY = 100;
private static final ArrayBlockingQueue<VirtualFile> myFinishedFiles = new ArrayBlockingQueue<VirtualFile>(CAPACITY);
public static boolean isFileIndexed(VirtualFile file, ID<?, ?> indexName, final long indexCreationStamp) {
try {
return getIndexStamp(file, indexName) == indexCreationStamp;
}
catch (RuntimeException e) {
final Throwable cause = e.getCause();
if (!(cause instanceof IOException)) {
throw e; // in case of IO exceptions consider file unindexed
}
}
return false;
}
public static long getIndexStamp(VirtualFile file, ID<?, ?> indexName) {
synchronized (file) {
Timestamps stamp = createOrGetTimeStamp(file);
if (stamp != null) return stamp.get(indexName);
return 0;
}
}
private static Timestamps createOrGetTimeStamp(VirtualFile file) {
if (file instanceof NewVirtualFile && file.isValid()) {
Timestamps timestamps = myTimestampsCache.get(file);
if (timestamps == null) {
synchronized (myTimestampsCache) { // avoid synchroneous reads TODO:
timestamps = myTimestampsCache.get(file);
if (timestamps == null) {
final DataInputStream stream = Timestamps.PERSISTENCE.readAttribute(file);
try {
timestamps = new Timestamps(stream);
}
catch (IOException e) {
throw new RuntimeException(e);
}
myTimestampsCache.put(file, timestamps);
}
}
}
return timestamps;
}
return null;
}
public static void update(final VirtualFile file, final ID<?, ?> indexName, final long indexCreationStamp) {
synchronized (file) {
try {
Timestamps stamp = createOrGetTimeStamp(file);
if (stamp != null) stamp.set(indexName, indexCreationStamp);
}
catch (InvalidVirtualFileAccessException ignored /*ok to ignore it here*/) {
}
}
}
public static void flushCache(@Nullable VirtualFile finishedFile) {
if (finishedFile == null || !myFinishedFiles.offer(finishedFile)) {
VirtualFile[] files = null;
synchronized (myFinishedFiles) {
int size = myFinishedFiles.size();
if ((finishedFile == null && size > 0) || size == CAPACITY) {
files = myFinishedFiles.toArray(new VirtualFile[size]);
myFinishedFiles.clear();
}
}
if (files != null) {
for(VirtualFile file:files) {
synchronized (file) {
Timestamps timestamp = myTimestampsCache.remove(file);
if (timestamp == null) continue;
synchronized (myTimestampsCache) {
try {
if (timestamp.isDirty() && file.isValid()) {
final DataOutputStream sink = Timestamps.PERSISTENCE.writeAttribute(file);
timestamp.writeToStream(sink);
sink.close();
}
}
catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
}
if (finishedFile != null) myFinishedFiles.offer(finishedFile);
}
}
}
@@ -22,6 +22,7 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ProjectFileIndex;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileFilter;
@@ -212,7 +213,7 @@ public abstract class AbstractFileTreeTable<T> extends TreeTable {
TreeNode child = root.getChildAt(i);
VirtualFile file = ((FileNode)child).getObject();
if (VfsUtil.isAncestor(file, toSelect, false)) {
if (file == toSelect) {
if (Comparing.equal(file, toSelect)) {
TreeUtil.selectNode(getTree(), child);
getSelectionModel().clearSelection();
addSelectedPath(TreeUtil.getPathFromRoot(child));
@@ -32,6 +32,7 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.util.Clock;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vfs.*;
@@ -60,7 +61,7 @@ public class IdeaGateway {
for (Project each : openProjects) {
if (each.isDefault()) continue;
if (!each.isInitialized()) continue;
if (each.getWorkspaceFile() == f) return false;
if (Comparing.equal(each.getWorkspaceFile(), f)) return false;
if (ProjectRootManager.getInstance(each).getFileIndex().isIgnored(f)) return false;
}
@@ -25,6 +25,7 @@ import com.intellij.history.integration.IdeaGateway;
import com.intellij.openapi.command.impl.DocumentUndoProvider;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.containers.HashSet;
@@ -101,7 +102,7 @@ public class UndoChangeRevertingVisitor extends ChangeVisitor {
if (f != null) {
VirtualFile existing = f.getParent().findChild(c.getOldName());
try {
if (existing != null && existing != f) {
if (existing != null && !Comparing.equal(existing, f)) {
existing.delete(LocalHistory.VFS_EVENT_REQUESTOR);
}
f.rename(LocalHistory.VFS_EVENT_REQUESTOR, c.getOldName());
@@ -22,6 +22,7 @@ import com.intellij.openapi.editor.event.DocumentAdapter;
import com.intellij.openapi.editor.event.DocumentEvent;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.UserDataHolderBase;
import com.intellij.openapi.vfs.VirtualFile;
@@ -53,7 +54,7 @@ public class LazyRangeMarkerFactory extends AbstractProjectComponent {
List<LazyMarker> markers = lazyMarkers.toStrongList();
List<LazyMarker> markersToRemove = new ArrayList<LazyMarker>();
for (final LazyMarker marker : markers) {
if (marker.getFile() == docFile) {
if (Comparing.equal(marker.getFile(), docFile)) {
marker.ensureDelegate();
markersToRemove.add(marker);
}
@@ -16,6 +16,7 @@
package com.intellij.openapi.fileChooser;
import com.intellij.openapi.fileTypes.FileTypes;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.vfs.JarFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.StringBuilderSpinAllocator;
@@ -84,7 +85,7 @@ public class FileElement {
@Override
public boolean equals(Object obj) {
if (obj instanceof FileElement) {
if (((FileElement)obj).myFile == myFile) return true;
if (Comparing.equal(((FileElement)obj).myFile, myFile)) return true;
}
return false;
}
@@ -1,264 +1,265 @@
/*
* Copyright 2000-2009 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.openapi.fileEditor;
import com.intellij.ide.*;
import com.intellij.ide.FileEditorProvider;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.actionSystem.DataKey;
import com.intellij.openapi.editor.*;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.fileTypes.FileTypeManager;
import com.intellij.openapi.fileTypes.INativeFileType;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.wm.IdeFocusManager;
import com.intellij.pom.Navigatable;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
public class OpenFileDescriptor implements Navigatable {
/**
* Tells descriptor to navigate in specific editor rather than file editor
* in main IDEA window.
* For example if you want to navigate in editor embedded into modal dialog,
* you should provide this data.
*/
public static final DataKey<Editor> NAVIGATE_IN_EDITOR = DataKey.create("NAVIGATE_IN_EDITOR");
@NotNull
private final VirtualFile myFile;
private final int myOffset;
private final int myLogicalLine;
private final int myLogicalColumn;
private final RangeMarker myRangeMarker;
@NotNull
private final Project myProject;
private boolean myUseCurrentWindow = false;
public OpenFileDescriptor(@NotNull Project project, @NotNull VirtualFile file, int offset) {
this(project, file, -1, -1, offset, false);
}
public OpenFileDescriptor(@NotNull Project project, @NotNull VirtualFile file, int logicalLine, int logicalColumn) {
this(project, file, logicalLine, logicalColumn, -1, false);
}
public OpenFileDescriptor(@NotNull Project project, @NotNull VirtualFile file,
int logicalLine, int logicalColumn, boolean persistent) {
this(project, file, logicalLine, logicalColumn, -1, persistent);
}
public OpenFileDescriptor(@NotNull Project project, @NotNull VirtualFile file) {
this(project, file, -1, -1, -1, false);
}
private OpenFileDescriptor(@NotNull Project project, @NotNull VirtualFile file,
int logicalLine, int logicalColumn, int offset, boolean persistent) {
myProject = project;
myFile = file;
myLogicalLine = logicalLine;
myLogicalColumn = logicalColumn;
myOffset = offset;
if (offset >= 0) {
myRangeMarker = LazyRangeMarkerFactory.getInstance(project).createRangeMarker(file, offset);
}
else if (logicalLine >= 0 ){
myRangeMarker = LazyRangeMarkerFactory.getInstance(project).createRangeMarker(file, logicalLine, Math.max(0, logicalColumn), persistent);
}
else {
myRangeMarker = null;
}
}
@NotNull
public VirtualFile getFile() {
return myFile;
}
@Nullable
public RangeMarker getRangeMarker() {
return myRangeMarker;
}
public int getOffset() {
return myRangeMarker != null && myRangeMarker.isValid() ? myRangeMarker.getStartOffset() : myOffset;
}
public int getLine() {
return myLogicalLine;
}
public int getColumn() {
return myLogicalColumn;
}
@Override
public void navigate(boolean requestFocus) {
if (!canNavigate()) {
throw new IllegalStateException("Navigation is not possible with null project");
}
if (!myFile.isDirectory() && navigateInEditor(myProject, requestFocus)) return;
navigateInProjectView();
}
private boolean navigateInEditor(@NotNull Project project, boolean requestFocus) {
FileType type = FileTypeManager.getInstance().getKnownFileTypeOrAssociate(myFile,project);
if (type == null || !myFile.isValid()) return false;
if (type instanceof INativeFileType) {
return ((INativeFileType) type).openFileInAssociatedApplication(project, myFile);
}
return navigateInRequestedEditor() || navigateInAnyFileEditor(project, requestFocus);
}
private boolean navigateInRequestedEditor() {
DataContext ctx = DataManager.getInstance().getDataContext();
Editor e = NAVIGATE_IN_EDITOR.getData(ctx);
if (e == null) return false;
if (FileDocumentManager.getInstance().getFile(e.getDocument()) != myFile) return false;
navigateIn(e);
return true;
}
private boolean navigateInAnyFileEditor(Project project, boolean focusEditor) {
List<FileEditor> editors = FileEditorManager.getInstance(project).openEditor(this, focusEditor);
for (FileEditor editor : editors) {
if (editor instanceof TextEditor) {
Editor e = ((TextEditor)editor).getEditor();
unfoldCurrentLine(e);
if (focusEditor) {
IdeFocusManager.getInstance(myProject).requestFocus(e.getContentComponent(), true);
}
}
}
return !editors.isEmpty();
}
private void navigateInProjectView() {
SelectInContext context = new SelectInContext() {
@Override
@NotNull
public Project getProject() {
return myProject;
}
@Override
@NotNull
public VirtualFile getVirtualFile() {
return myFile;
}
@Override
@Nullable
public Object getSelectorInFile() {
return null;
}
@Override
@Nullable
public FileEditorProvider getFileEditorProvider() {
return null;
}
};
for (SelectInTarget target : SelectInManager.getInstance(myProject).getTargets()) {
if (target.canSelect(context)) {
target.selectIn(context, true);
return;
}
}
}
public void navigateIn(@NotNull Editor e) {
final int offset = getOffset();
CaretModel caretModel = e.getCaretModel();
boolean caretMoved = false;
if (myLogicalLine >= 0) {
LogicalPosition pos = new LogicalPosition(myLogicalLine, Math.max(myLogicalColumn, 0));
if (offset < 0 || offset == e.logicalPositionToOffset(pos)) {
caretModel.moveToLogicalPosition(pos);
caretMoved = true;
}
}
if (!caretMoved && offset >= 0) {
caretModel.moveToOffset(Math.min(offset, e.getDocument().getTextLength()));
caretMoved = true;
}
if (caretMoved) {
e.getSelectionModel().removeSelection();
scrollToCaret(e);
unfoldCurrentLine(e);
}
}
private static void unfoldCurrentLine(@NotNull final Editor editor) {
final FoldRegion[] allRegions = editor.getFoldingModel().getAllFoldRegions();
final int offset = editor.getCaretModel().getOffset();
int line = editor.getDocument().getLineNumber(offset);
int start = editor.getDocument().getLineStartOffset(line);
int end = editor.getDocument().getLineEndOffset(line);
final TextRange range = new TextRange(start, end);
editor.getFoldingModel().runBatchFoldingOperation(new Runnable() {
@Override
public void run() {
for (FoldRegion region : allRegions) {
if (!region.isExpanded() && range.intersects(TextRange.create(region))) {
region.setExpanded(true);
}
}
}
});
}
private static void scrollToCaret(@NotNull Editor e) {
e.getScrollingModel().scrollToCaret(ScrollType.CENTER);
}
@Override
public boolean canNavigate() {
return myFile.isValid();
}
@Override
public boolean canNavigateToSource() {
return canNavigate();
}
@NotNull
public Project getProject() {
return myProject;
}
public OpenFileDescriptor setUseCurrentWindow(boolean search) {
myUseCurrentWindow = search;
return this;
}
public boolean isUseCurrentWindow() {
return myUseCurrentWindow;
}
}
/*
* Copyright 2000-2009 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.openapi.fileEditor;
import com.intellij.ide.*;
import com.intellij.ide.FileEditorProvider;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.actionSystem.DataKey;
import com.intellij.openapi.editor.*;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.fileTypes.FileTypeManager;
import com.intellij.openapi.fileTypes.INativeFileType;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.wm.IdeFocusManager;
import com.intellij.pom.Navigatable;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
public class OpenFileDescriptor implements Navigatable {
/**
* Tells descriptor to navigate in specific editor rather than file editor
* in main IDEA window.
* For example if you want to navigate in editor embedded into modal dialog,
* you should provide this data.
*/
public static final DataKey<Editor> NAVIGATE_IN_EDITOR = DataKey.create("NAVIGATE_IN_EDITOR");
@NotNull
private final VirtualFile myFile;
private final int myOffset;
private final int myLogicalLine;
private final int myLogicalColumn;
private final RangeMarker myRangeMarker;
@NotNull
private final Project myProject;
private boolean myUseCurrentWindow = false;
public OpenFileDescriptor(@NotNull Project project, @NotNull VirtualFile file, int offset) {
this(project, file, -1, -1, offset, false);
}
public OpenFileDescriptor(@NotNull Project project, @NotNull VirtualFile file, int logicalLine, int logicalColumn) {
this(project, file, logicalLine, logicalColumn, -1, false);
}
public OpenFileDescriptor(@NotNull Project project, @NotNull VirtualFile file,
int logicalLine, int logicalColumn, boolean persistent) {
this(project, file, logicalLine, logicalColumn, -1, persistent);
}
public OpenFileDescriptor(@NotNull Project project, @NotNull VirtualFile file) {
this(project, file, -1, -1, -1, false);
}
private OpenFileDescriptor(@NotNull Project project, @NotNull VirtualFile file,
int logicalLine, int logicalColumn, int offset, boolean persistent) {
myProject = project;
myFile = file;
myLogicalLine = logicalLine;
myLogicalColumn = logicalColumn;
myOffset = offset;
if (offset >= 0) {
myRangeMarker = LazyRangeMarkerFactory.getInstance(project).createRangeMarker(file, offset);
}
else if (logicalLine >= 0 ){
myRangeMarker = LazyRangeMarkerFactory.getInstance(project).createRangeMarker(file, logicalLine, Math.max(0, logicalColumn), persistent);
}
else {
myRangeMarker = null;
}
}
@NotNull
public VirtualFile getFile() {
return myFile;
}
@Nullable
public RangeMarker getRangeMarker() {
return myRangeMarker;
}
public int getOffset() {
return myRangeMarker != null && myRangeMarker.isValid() ? myRangeMarker.getStartOffset() : myOffset;
}
public int getLine() {
return myLogicalLine;
}
public int getColumn() {
return myLogicalColumn;
}
@Override
public void navigate(boolean requestFocus) {
if (!canNavigate()) {
throw new IllegalStateException("Navigation is not possible with null project");
}
if (!myFile.isDirectory() && navigateInEditor(myProject, requestFocus)) return;
navigateInProjectView();
}
private boolean navigateInEditor(@NotNull Project project, boolean requestFocus) {
FileType type = FileTypeManager.getInstance().getKnownFileTypeOrAssociate(myFile,project);
if (type == null || !myFile.isValid()) return false;
if (type instanceof INativeFileType) {
return ((INativeFileType) type).openFileInAssociatedApplication(project, myFile);
}
return navigateInRequestedEditor() || navigateInAnyFileEditor(project, requestFocus);
}
private boolean navigateInRequestedEditor() {
DataContext ctx = DataManager.getInstance().getDataContext();
Editor e = NAVIGATE_IN_EDITOR.getData(ctx);
if (e == null) return false;
if (!Comparing.equal(FileDocumentManager.getInstance().getFile(e.getDocument()), myFile)) return false;
navigateIn(e);
return true;
}
private boolean navigateInAnyFileEditor(Project project, boolean focusEditor) {
List<FileEditor> editors = FileEditorManager.getInstance(project).openEditor(this, focusEditor);
for (FileEditor editor : editors) {
if (editor instanceof TextEditor) {
Editor e = ((TextEditor)editor).getEditor();
unfoldCurrentLine(e);
if (focusEditor) {
IdeFocusManager.getInstance(myProject).requestFocus(e.getContentComponent(), true);
}
}
}
return !editors.isEmpty();
}
private void navigateInProjectView() {
SelectInContext context = new SelectInContext() {
@Override
@NotNull
public Project getProject() {
return myProject;
}
@Override
@NotNull
public VirtualFile getVirtualFile() {
return myFile;
}
@Override
@Nullable
public Object getSelectorInFile() {
return null;
}
@Override
@Nullable
public FileEditorProvider getFileEditorProvider() {
return null;
}
};
for (SelectInTarget target : SelectInManager.getInstance(myProject).getTargets()) {
if (target.canSelect(context)) {
target.selectIn(context, true);
return;
}
}
}
public void navigateIn(@NotNull Editor e) {
final int offset = getOffset();
CaretModel caretModel = e.getCaretModel();
boolean caretMoved = false;
if (myLogicalLine >= 0) {
LogicalPosition pos = new LogicalPosition(myLogicalLine, Math.max(myLogicalColumn, 0));
if (offset < 0 || offset == e.logicalPositionToOffset(pos)) {
caretModel.moveToLogicalPosition(pos);
caretMoved = true;
}
}
if (!caretMoved && offset >= 0) {
caretModel.moveToOffset(Math.min(offset, e.getDocument().getTextLength()));
caretMoved = true;
}
if (caretMoved) {
e.getSelectionModel().removeSelection();
scrollToCaret(e);
unfoldCurrentLine(e);
}
}
private static void unfoldCurrentLine(@NotNull final Editor editor) {
final FoldRegion[] allRegions = editor.getFoldingModel().getAllFoldRegions();
final int offset = editor.getCaretModel().getOffset();
int line = editor.getDocument().getLineNumber(offset);
int start = editor.getDocument().getLineStartOffset(line);
int end = editor.getDocument().getLineEndOffset(line);
final TextRange range = new TextRange(start, end);
editor.getFoldingModel().runBatchFoldingOperation(new Runnable() {
@Override
public void run() {
for (FoldRegion region : allRegions) {
if (!region.isExpanded() && range.intersects(TextRange.create(region))) {
region.setExpanded(true);
}
}
}
});
}
private static void scrollToCaret(@NotNull Editor e) {
e.getScrollingModel().scrollToCaret(ScrollType.CENTER);
}
@Override
public boolean canNavigate() {
return myFile.isValid();
}
@Override
public boolean canNavigateToSource() {
return canNavigate();
}
@NotNull
public Project getProject() {
return myProject;
}
public OpenFileDescriptor setUseCurrentWindow(boolean search) {
myUseCurrentWindow = search;
return this;
}
public boolean isUseCurrentWindow() {
return myUseCurrentWindow;
}
}
@@ -20,6 +20,7 @@ import com.intellij.openapi.application.WriteAction;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.fileTypes.FileTypeManager;
import com.intellij.openapi.fileTypes.FileTypes;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
@@ -327,6 +328,16 @@ public class VfsUtil extends VfsUtilCore {
return virtualFileManager.findFileByUrl(vfUrl);
}
@Nullable
public static VirtualFile findFileByIoFile(@NotNull File file, boolean refreshIfNeeded) {
LocalFileSystem fileSystem = LocalFileSystem.getInstance();
VirtualFile virtualFile = fileSystem.findFileByIoFile(file);
if (virtualFile == null && refreshIfNeeded) {
virtualFile = fileSystem.refreshAndFindFileByIoFile(file);
}
return virtualFile;
}
/**
* Converts VsfUrl info java.net.URL. Does not support "jar:" protocol.
*
@@ -473,8 +484,8 @@ public class VfsUtil extends VfsUtilCore {
final VirtualFile commonAncestor = getCommonAncestor(src, dst);
if (commonAncestor != null) {
StringBuilder buffer = new StringBuilder();
if (src != commonAncestor) {
while (src.getParent() != commonAncestor) {
if (!Comparing.equal(src, commonAncestor)) {
while (!Comparing.equal(src.getParent(), commonAncestor)) {
buffer.append("..").append(separatorChar);
src = src.getParent();
}
@@ -47,6 +47,7 @@ public class RowsDnDSupport {
}
private static void installImpl(@NotNull final JComponent component, @NotNull final EditableModel model) {
component.setTransferHandler(new TransferHandler(null));
DnDSupport.createBuilder(component)
.setBeanProvider(new Function<DnDActionInfo, DnDDragStartBean>() {
@Override
@@ -72,8 +73,10 @@ public class RowsDnDSupport {
event.setHighlighting(rectangle, 2);
}
else {
event.setDropPossible(false);
if (oldIndex != newIndex) // Drag&Drop always starts with new==old and we shouldn't display 'rejecting' cursor in this case
event.setDropPossible(false, "");
event.hideHighlighter();
return true;
}
return false;
}
@@ -122,7 +125,7 @@ public class RowsDnDSupport {
} else if (component instanceof JList) {
return ((JList)component).locationToIndex(point);
} else if (component instanceof JTree) {
return ((JTree)component).getRowForLocation(point.x, point.y);
return ((JTree)component).getClosestRowForLocation(point.x, point.y);
} else {
throw new IllegalArgumentException("Unsupported component: " + component);
}
@@ -1,4 +1,3 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
*
@@ -24,6 +23,7 @@ import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx;
import com.intellij.openapi.fileEditor.impl.EditorWindow;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.vfs.VirtualFile;
public class CloseAllEditorsButActiveAction extends AnAction implements DumbAware {
@@ -39,7 +39,7 @@ public class CloseAllEditorsButActiveAction extends AnAction implements DumbAwar
selectedFile = fileEditorManager.getSelectedFiles()[0];
final VirtualFile[] siblings = fileEditorManager.getSiblings(selectedFile);
for (final VirtualFile sibling : siblings) {
if (selectedFile != sibling) {
if (!Comparing.equal(selectedFile, sibling)) {
fileEditorManager.closeFile(sibling);
}
}
@@ -231,6 +231,14 @@ public class CommandMerger {
return !myCurrentActions.isEmpty();
}
public boolean isPhysical() {
if (myAllAffectedDocuments.isEmpty()) return false;
for (DocumentReference each : myAllAffectedDocuments) {
if (each.getFile() == null) return false;
}
return true;
}
public boolean isUndoAvailable(@NotNull Collection<DocumentReference> refs) {
if (hasNonUndoableActions()) {
return false;
@@ -21,6 +21,7 @@ import com.intellij.openapi.command.undo.DocumentReferenceManager;
import com.intellij.openapi.components.ApplicationComponent;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileAdapter;
@@ -75,7 +76,7 @@ public class DocumentReferenceManagerImpl extends DocumentReferenceManager imple
List<VirtualFile> files = f.getUserData(DELETED_FILES);
f.putUserData(DELETED_FILES, null);
assert files != null;
assert files != null : f;
for (VirtualFile each : files) {
Reference<VirtualFile> r = new WeakReferenceWithEquals<VirtualFile>(each);
DocumentReference ref = myFileToRef.remove(r);
@@ -159,7 +160,7 @@ public class DocumentReferenceManagerImpl extends DocumentReferenceManager imple
@Override
public boolean equals(Object obj) {
T doc = get();
return doc != null && obj instanceof Reference && ((Reference)obj).get() == doc;
return doc != null && obj instanceof Reference && Comparing.equal(doc, ((Reference)obj).get());
}
}
}
@@ -283,7 +283,7 @@ public class UndoManagerImpl extends UndoManager implements ProjectComponent, Ap
myCommandLevel--;
if (myCommandLevel > 0) return;
if (myProject != null && myCurrentMerger.hasActions() && !myCurrentMerger.isTransparent()) {
if (myProject != null && myCurrentMerger.hasActions() && !myCurrentMerger.isTransparent() && myCurrentMerger.isPhysical()) {
addFocusedDocumentAsAffected();
}
myOriginatorReference = null;
@@ -181,7 +181,7 @@ public abstract class EditorComposite implements Disposable {
public void selectionChanged(final FileEditorManagerEvent event) {
final VirtualFile oldFile = event.getOldFile();
final VirtualFile newFile = event.getNewFile();
if (oldFile == newFile && getFile() == newFile) {
if (Comparing.equal(oldFile, newFile) && Comparing.equal(getFile(), newFile)) {
final FileEditor oldEditor = event.getOldEditor();
if (oldEditor != null) oldEditor.deselectNotify();
final FileEditor newEditor = event.getNewEditor();
@@ -26,6 +26,7 @@ import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.project.DumbAwareRunnable;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.startup.StartupManager;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.InvalidDataException;
import com.intellij.openapi.util.JDOMExternalizable;
import com.intellij.openapi.util.Pair;
@@ -254,7 +255,7 @@ public final class EditorHistoryManager extends AbstractProjectComponent impleme
public boolean hasBeenOpen(@NotNull VirtualFile f) {
for (HistoryEntry each : myEntriesList) {
if (each.myFile == f) return true;
if (Comparing.equal(each.myFile, f)) return true;
}
return false;
}
@@ -122,7 +122,7 @@ public class EditorWindow {
public void closeAllExcept(final VirtualFile selectedFile) {
final VirtualFile[] files = getFiles();
for (final VirtualFile file : files) {
if (file != selectedFile && !isFilePinned(file)) {
if (!Comparing.equal(file, selectedFile) && !isFilePinned(file)) {
closeFile(file);
}
}
@@ -1090,7 +1090,7 @@ public class EditorWindow {
if (fileCanBeClosed(file, fileToIgnore)) {
boolean found = false;
for (int j = 0; j != histFiles.length; j++) {
if (histFiles[j] == file) {
if (Comparing.equal(histFiles[j], file)) {
found = true;
break;
}
@@ -1146,7 +1146,7 @@ public class EditorWindow {
if (fileCanBeClosed(file, fileToIgnore)) {
boolean found = false;
for (int j = 0; j != histFiles.length; j++) {
if (histFiles[j] == file) {
if (Comparing.equal(histFiles[j], file)) {
found = true;
break;
}
@@ -387,7 +387,7 @@ public class EditorsSplitters extends JPanel {
final VirtualFile currentFile = getCurrentFile();
if (currentFile != null) {
for (int i = 0; i != virtualFiles.length; ++i) {
if (virtualFiles[i] == currentFile) {
if (Comparing.equal(virtualFiles[i], currentFile)) {
virtualFiles[i] = virtualFiles[0];
virtualFiles[0] = currentFile;
break;
@@ -572,7 +572,7 @@ public class EditorsSplitters extends JPanel {
for (int i = 0; i != windows.length; ++i) {
final VirtualFile[] files = windows[i].getFiles();
for (final VirtualFile fileAt : files) {
if (fileAt != file) {
if (!Comparing.equal(fileAt, file)) {
return fileAt;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2011 JetBrains s.r.o.
* Copyright 2000-2012 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.
@@ -36,6 +36,7 @@ import com.intellij.openapi.vcs.FileStatus;
import com.intellij.openapi.vcs.FileStatusListener;
import com.intellij.openapi.vcs.FileStatusManager;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.testFramework.LightVirtualFile;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.HashMap;
import org.jetbrains.annotations.NotNull;
@@ -50,7 +51,6 @@ import java.util.Map;
*/
public class FileStatusManagerImpl extends FileStatusManager implements ProjectComponent {
private final Map<VirtualFile, FileStatus> myCachedStatuses = Collections.synchronizedMap(new HashMap<VirtualFile, FileStatus>());
private final Project myProject;
private final List<FileStatusListener> myListeners = ContainerUtil.createEmptyCOWList();
private FileStatusProvider myFileStatusProvider;
@@ -123,7 +123,11 @@ public class FileStatusManagerImpl extends FileStatusManager implements ProjectC
}
}
};
EditorFactory.getInstance().getEventMulticaster().addDocumentListener(documentListener, myProject);
final EditorFactory factory = EditorFactory.getInstance();
if (factory != null) {
factory.getEventMulticaster().addDocumentListener(documentListener, myProject);
}
}
public void disposeComponent() {
@@ -138,9 +142,7 @@ public class FileStatusManagerImpl extends FileStatusManager implements ProjectC
public void initComponent() { }
public void addFileStatusListener(@NotNull FileStatusListener listener) {
if (listener != null) {
myListeners.add(listener);
}
myListeners.add(listener);
}
public void addFileStatusListener(final FileStatusListener listener, Disposable parentDisposable) {
@@ -202,6 +204,10 @@ public class FileStatusManagerImpl extends FileStatusManager implements ProjectC
}
public FileStatus getStatus(final VirtualFile file) {
if (file instanceof LightVirtualFile) {
return FileStatus.NOT_CHANGED; // do not leak light files via cache
}
FileStatus status = getCachedStatus(file);
if (status == null || status == FileStatusNull.INSTANCE) {
status = calcStatus(file);
@@ -224,5 +230,4 @@ public class FileStatusManagerImpl extends FileStatusManager implements ProjectC
myFileStatusProvider.refreshFileStatusFromDocument(file, doc);
}
}
}
@@ -17,6 +17,7 @@ package com.intellij.openapi.vfs.impl;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.components.ApplicationComponent;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.*;
import com.intellij.openapi.util.io.FileUtil;
@@ -27,7 +28,10 @@ import com.intellij.openapi.vfs.ex.VirtualFileManagerEx;
import com.intellij.openapi.vfs.ex.temp.TempFileSystem;
import com.intellij.openapi.vfs.newvfs.BulkFileListener;
import com.intellij.openapi.vfs.newvfs.events.*;
import com.intellij.openapi.vfs.pointers.*;
import com.intellij.openapi.vfs.pointers.VirtualFilePointer;
import com.intellij.openapi.vfs.pointers.VirtualFilePointerContainer;
import com.intellij.openapi.vfs.pointers.VirtualFilePointerListener;
import com.intellij.openapi.vfs.pointers.VirtualFilePointerManager;
import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.messages.MessageBus;
@@ -41,11 +45,11 @@ import org.jetbrains.annotations.TestOnly;
import java.util.*;
public class VirtualFilePointerManagerImpl extends VirtualFilePointerManager implements ModificationTracker, BulkFileListener {
public class VirtualFilePointerManagerImpl extends VirtualFilePointerManager implements ApplicationComponent, ModificationTracker, BulkFileListener {
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.vfs.impl.VirtualFilePointerManagerImpl");
private static final TempFileSystem TEMP_FILE_SYSTEM = TempFileSystem.getInstance();
private static final LocalFileSystem LOCAL_FILE_SYSTEM = LocalFileSystem.getInstance();
private static final JarFileSystem JAR_FILE_SYSTEM = JarFileSystem.getInstance();
private final TempFileSystem TEMP_FILE_SYSTEM;
private final LocalFileSystem LOCAL_FILE_SYSTEM;
private final JarFileSystem JAR_FILE_SYSTEM;
private long myVfsModificationCounter;
// guarded by this
private final Map<VirtualFilePointerListener, FilePointerPartNode> myPointers = new LinkedHashMap<VirtualFilePointerListener, FilePointerPartNode>();
@@ -67,10 +71,17 @@ public class VirtualFilePointerManagerImpl extends VirtualFilePointerManager imp
}
};
VirtualFilePointerManagerImpl(@NotNull VirtualFileManagerEx virtualFileManagerEx, @NotNull MessageBus bus) {
VirtualFilePointerManagerImpl(@NotNull VirtualFileManagerEx virtualFileManagerEx,
@NotNull MessageBus bus,
@NotNull TempFileSystem tempFileSystem,
@NotNull LocalFileSystem localFileSystem,
@NotNull JarFileSystem jarFileSystem) {
myVirtualFileManager = virtualFileManagerEx;
myBus = bus;
bus.connect().subscribe(VirtualFileManager.VFS_CHANGES, this);
TEMP_FILE_SYSTEM = tempFileSystem;
LOCAL_FILE_SYSTEM = localFileSystem;
JAR_FILE_SYSTEM = jarFileSystem;
}
@@ -79,6 +90,20 @@ public class VirtualFilePointerManagerImpl extends VirtualFilePointerManager imp
return myVfsModificationCounter;
}
@Override
public void initComponent() {
}
@Override
public void disposeComponent() {
}
@NotNull
@Override
public String getComponentName() {
return "VirtualFilePointerManager";
}
private static class EventDescriptor {
@NotNull private final VirtualFilePointerListener myListener;
@NotNull private final VirtualFilePointer[] myPointers;
@@ -15,6 +15,7 @@
*/
package com.intellij.openapi.vfs.newvfs.persistent;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.VfsUtil;
@@ -67,7 +68,7 @@ public class RefreshWorker {
final VirtualFileSystemEntry file = (VirtualFileSystemEntry)myRefreshQueue.pullFirst();
if (!file.isDirty()) continue;
int attributes = file == root ? rootAttributes : delegate.getBooleanAttributes(file, -1);
int attributes = Comparing.equal(file, root) ? rootAttributes : delegate.getBooleanAttributes(file, -1);
VirtualFileSystemEntry parent = file.getParent();
if (parent != null && checkAndScheduleAttributesChange(parent, file, delegate, attributes)) {
// ignore everything else
@@ -13,8 +13,6 @@
<applicationService serviceInterface="com.intellij.openapi.vfs.tracker.VirtualFileTracker"
serviceImplementation="com.intellij.openapi.vfs.tracker.VirtualFileTrackerImpl"/>
<applicationService serviceInterface="com.intellij.openapi.vfs.pointers.VirtualFilePointerManager"
serviceImplementation="com.intellij.openapi.vfs.impl.VirtualFilePointerManagerImpl"/>
<applicationService serviceInterface="com.intellij.concurrency.JobScheduler"
serviceImplementation="com.intellij.concurrency.JobSchedulerImpl"/>
@@ -20,6 +20,11 @@
<implementation-class>com.intellij.openapi.vfs.impl.VirtualFileManagerImpl</implementation-class>
</component>
<component>
<interface-class>com.intellij.openapi.vfs.pointers.VirtualFilePointerManager</interface-class>
<implementation-class>com.intellij.openapi.vfs.impl.VirtualFilePointerManagerImpl</implementation-class>
</component>
<component>
<interface-class>com.intellij.openapi.vfs.newvfs.ManagingFS</interface-class>
<implementation-class>com.intellij.openapi.vfs.newvfs.persistent.PersistentFS</implementation-class>
@@ -30,6 +30,7 @@ import com.intellij.openapi.roots.ContentEntry;
import com.intellij.openapi.roots.ModifiableRootModel;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.util.Clock;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.*;
@@ -177,7 +178,7 @@ public abstract class IntegrationTestCase extends PlatformTestCase {
ModuleRootManager rm = ModuleRootManager.getInstance(myModule);
ModifiableRootModel m = rm.getModifiableModel();
for (ContentEntry e : m.getContentEntries()) {
if (e.getFile() != myRoot) continue;
if (!Comparing.equal(e.getFile(), myRoot)) continue;
e.addExcludeFolder(VfsUtilCore.pathToUrl(FileUtil.toSystemIndependentName(path)));
}
m.commit();
@@ -31,6 +31,7 @@ import com.intellij.openapi.roots.impl.ContentEntryImpl;
import com.intellij.openapi.roots.impl.libraries.ProjectLibraryTable;
import com.intellij.openapi.roots.libraries.Library;
import com.intellij.openapi.roots.libraries.LibraryTable;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.*;
@@ -189,7 +190,7 @@ public class PsiTestUtil {
}
}.execute().throwException();
for (ContentEntry entry : rootManager.getContentEntries()) {
if (entry.getFile() == vDir) {
if (Comparing.equal(entry.getFile(), vDir)) {
Assert.assertFalse(((ContentEntryImpl)entry).isDisposed());
return entry;
}
@@ -308,7 +308,7 @@ public class UsageInfo2UsageAdapter implements UsageInModule,
if (!(other instanceof UsageInfo2UsageAdapter)) return false;
UsageInfo2UsageAdapter u2 = (UsageInfo2UsageAdapter)other;
assert u2 != this;
if (myLineNumber != u2.myLineNumber || getFile() != u2.getFile()) return false;
if (myLineNumber != u2.myLineNumber || !Comparing.equal(getFile(), u2.getFile())) return false;
myMergedUsageInfos.addAll(u2.myMergedUsageInfos);
Collections.sort(myMergedUsageInfos, new Comparator<UsageInfo>() {
@Override
@@ -22,7 +22,7 @@ public class Pair<A, B> {
public final A first;
public final B second;
public static <A, B> Pair<A, B> create(@Nullable A first, @Nullable B second) {
public static <A, B> Pair<A, B> create(A first, B second) {
return new Pair<A, B>(first, second);
}
@@ -52,17 +52,15 @@ public class Pair<A, B> {
return EMPTY;
}
public Pair(@Nullable A first, @Nullable B second) {
public Pair(A first, B second) {
this.first = first;
this.second = second;
}
@Nullable
public final A getFirst() {
return first;
}
@Nullable
public final B getSecond() {
return second;
}
@@ -15,6 +15,7 @@
*/
package com.intellij.openapi.util;
import com.intellij.util.containers.ConcurrentWeakValueHashMap;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -33,9 +34,11 @@ public class Key<T> {
private static final AtomicInteger ourKeysCounter = new AtomicInteger();
private final int myIndex = ourKeysCounter.getAndIncrement();
private final String myName; // for debug purposes only
private static final ConcurrentWeakValueHashMap<Integer, Key> allKeys = new ConcurrentWeakValueHashMap<Integer, Key>();
public Key(@NotNull @NonNls String name) {
myName = name;
allKeys.put(myIndex, this);
}
public final int hashCode() {
@@ -62,6 +65,7 @@ public class Key<T> {
@Nullable
public T get(@Nullable Map<Key, ?> holder) {
//noinspection unchecked
return holder == null ? null : (T)holder.get(this);
}
@@ -93,4 +97,9 @@ public class Key<T> {
holder.put(this, value);
}
}
public static <T> Key<T> getKeyByIndex(int index) {
//noinspection unchecked
return (Key<T>)allKeys.get(index);
}
}
@@ -16,39 +16,37 @@
package com.intellij.openapi.util;
import com.intellij.util.SmartFMap;
import com.intellij.util.concurrency.AtomicFieldUpdater;
import com.intellij.util.keyFMap.KeyFMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.TestOnly;
import java.util.Map;
public class UserDataHolderBase implements UserDataHolderEx, Cloneable {
private static final Key<SmartFMap<Key, Object>> COPYABLE_USER_MAP_KEY = Key.create("COPYABLE_USER_MAP_KEY");
public static final Key<KeyFMap> COPYABLE_USER_MAP_KEY = Key.create("COPYABLE_USER_MAP_KEY");
/**
* Concurrent writes to this field are via CASes only, using the {@link #updater}
*/
@NotNull private volatile SmartFMap<Key, Object> myUserMap = SmartFMap.emptyMap();
@NotNull private volatile KeyFMap myUserMap = KeyFMap.EMPTY_MAP;
@Override
protected Object clone() {
try {
UserDataHolderBase clone = (UserDataHolderBase)super.clone();
clone.myUserMap = SmartFMap.emptyMap();
clone.myUserMap = KeyFMap.EMPTY_MAP;
copyCopyableDataTo(clone);
return clone;
}
catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
@TestOnly
public String getUserDataString() {
final SmartFMap<Key, Object> userMap = myUserMap;
final Map copyableMap = getUserData(COPYABLE_USER_MAP_KEY);
final KeyFMap userMap = myUserMap;
final KeyFMap copyableMap = getUserData(COPYABLE_USER_MAP_KEY);
return userMap.toString() + (copyableMap == null ? "" : copyableMap.toString());
}
@@ -56,64 +54,68 @@ public class UserDataHolderBase implements UserDataHolderEx, Cloneable {
other.myUserMap = myUserMap;
}
@Override
public <T> T getUserData(@NotNull Key<T> key) {
//noinspection unchecked
return (T)myUserMap.get(key);
return myUserMap.get(key);
}
@Override
public <T> void putUserData(@NotNull Key<T> key, @Nullable T value) {
while (true) {
SmartFMap<Key, Object> map = myUserMap;
SmartFMap<Key, Object> newMap = value == null ? map.minus(key) : map.plus(key, value);
KeyFMap map = myUserMap;
KeyFMap newMap = value == null ? map.minus(key) : map.plus(key, value);
if (newMap == map || updater.compareAndSet(this, map, newMap)) {
return;
break;
}
}
}
public <T> T getCopyableUserData(Key<T> key) {
SmartFMap<Key, Object> map = getUserData(COPYABLE_USER_MAP_KEY);
KeyFMap map = getUserData(COPYABLE_USER_MAP_KEY);
//noinspection unchecked,ConstantConditions
return map == null ? null : (T)map.get(key);
return map == null ? null : map.get(key);
}
public <T> void putCopyableUserData(Key<T> key, T value) {
while (true) {
SmartFMap<Key, Object> map = myUserMap;
@SuppressWarnings("unchecked") SmartFMap<Key, Object> copyableMap = (SmartFMap<Key, Object>)map.get(COPYABLE_USER_MAP_KEY);
KeyFMap map = myUserMap;
KeyFMap copyableMap = map.get(COPYABLE_USER_MAP_KEY);
if (copyableMap == null) {
copyableMap = SmartFMap.emptyMap();
copyableMap = KeyFMap.EMPTY_MAP;
}
SmartFMap<Key, Object> newCopyableMap = value == null ? copyableMap.minus(key) : copyableMap.plus(key, value);
SmartFMap<Key, Object> newMap = newCopyableMap.isEmpty() ? map.minus(COPYABLE_USER_MAP_KEY) : map.plus(COPYABLE_USER_MAP_KEY, newCopyableMap);
KeyFMap newCopyableMap = value == null ? copyableMap.minus(key) : copyableMap.plus(key, value);
KeyFMap newMap = newCopyableMap.isEmpty() ? map.minus(COPYABLE_USER_MAP_KEY) : map.plus(COPYABLE_USER_MAP_KEY, newCopyableMap);
if (newMap == map || updater.compareAndSet(this, map, newMap)) {
return;
}
}
}
@Override
public <T> boolean replace(@NotNull Key<T> key, @Nullable T oldValue, @Nullable T newValue) {
while (true) {
SmartFMap<Key, Object> map = myUserMap;
KeyFMap map = myUserMap;
if (map.get(key) != oldValue) {
return false;
}
SmartFMap<Key, Object> newMap = newValue == null ? map.minus(key) : map.plus(key, newValue);
KeyFMap newMap = newValue == null ? map.minus(key) : map.plus(key, newValue);
if (newMap == map || updater.compareAndSet(this, map, newMap)) {
return true;
}
}
}
@Override
@NotNull
public <T> T putUserDataIfAbsent(@NotNull final Key<T> key, @NotNull final T value) {
while (true) {
SmartFMap<Key, Object> map = myUserMap;
@SuppressWarnings("unchecked") T oldValue = (T)map.get(key);
KeyFMap map = myUserMap;
T oldValue = map.get(key);
if (oldValue != null) {
return oldValue;
}
SmartFMap<Key, Object> newMap = map.plus(key, value);
KeyFMap newMap = map.plus(key, value);
if (newMap == map || updater.compareAndSet(this, map, newMap)) {
return value;
}
@@ -125,8 +127,12 @@ public class UserDataHolderBase implements UserDataHolderEx, Cloneable {
}
protected void clearUserData() {
myUserMap = SmartFMap.emptyMap();
myUserMap = KeyFMap.EMPTY_MAP;
}
private static final AtomicFieldUpdater<UserDataHolderBase, SmartFMap> updater = AtomicFieldUpdater.forFieldOfType(UserDataHolderBase.class, SmartFMap.class);
public boolean isUserDataEmpty() {
return myUserMap.isEmpty();
}
private static final AtomicFieldUpdater<UserDataHolderBase, KeyFMap> updater = AtomicFieldUpdater.forFieldOfType(UserDataHolderBase.class, KeyFMap.class);
}
@@ -375,6 +375,17 @@ public class ArrayUtil extends ArrayUtilRt {
System.arraycopy(src, idx + 1, result, idx, length - idx - 1);
return result;
}
@NotNull
public static short[] remove(@NotNull final short[] src, int idx) {
int length = src.length;
if (idx < 0 || idx >= length) {
throw new IllegalArgumentException("invalid index: " + idx);
}
short[] result = new short[src.length - 1];
System.arraycopy(src, 0, result, 0, idx);
System.arraycopy(src, idx + 1, result, idx, length - idx - 1);
return result;
}
/**
* @param src source array.
@@ -650,6 +661,13 @@ public class ArrayUtil extends ArrayUtilRt {
return -1;
}
public static int indexOf(@NotNull short[] ints, short value) {
for (int i = 0; i < ints.length; i++) {
if (ints[i] == value) return i;
}
return -1;
}
public static boolean contains(final Object o, final Object... objects) {
return indexOf(objects, o) >= 0;
@@ -17,6 +17,7 @@ package com.intellij.util.containers;
import gnu.trove.THashMap;
import gnu.trove.TObjectHashingStrategy;
import org.jetbrains.annotations.NotNull;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
@@ -27,9 +28,9 @@ public final class WeakValueHashMap<K,V> implements Map<K,V>{
private final ReferenceQueue<V> myQueue = new ReferenceQueue<V>();
private static class MyReference<K,T> extends WeakReference<T> {
final K key;
private final K key;
public MyReference(K key, T referent, ReferenceQueue<? super T> q) {
private MyReference(K key, T referent, ReferenceQueue<? super T> q) {
super(referent, q);
this.key = key;
}
@@ -39,7 +40,7 @@ public final class WeakValueHashMap<K,V> implements Map<K,V>{
myMap = new THashMap<K, MyReference<K,V>>();
}
public WeakValueHashMap(TObjectHashingStrategy<K> strategy) {
public WeakValueHashMap(@NotNull TObjectHashingStrategy<K> strategy) {
myMap = new THashMap<K, MyReference<K,V>>(strategy);
}
@@ -49,58 +50,71 @@ public final class WeakValueHashMap<K,V> implements Map<K,V>{
if (ref == null) {
return;
}
if (myMap.get(ref.key) == ref){
myMap.remove(ref.key);
@SuppressWarnings("unchecked")
K key = (K)ref.key;
if (myMap.get(key) == ref){
myMap.remove(key);
}
}
}
@Override
public V get(Object key) {
MyReference<K,V> ref = myMap.get(key);
if (ref == null) return null;
return ref.get();
}
@Override
public V put(K key, V value) {
processQueue();
MyReference<K,V> oldRef = myMap.put(key, new MyReference<K,V>(key, value, myQueue));
return oldRef != null ? oldRef.get() : null;
}
@Override
public V remove(Object key) {
processQueue();
MyReference<K,V> ref = myMap.remove(key);
return ref != null ? ref.get() : null;
}
@Override
public void putAll(Map<? extends K, ? extends V> t) {
throw new RuntimeException("method not implemented");
}
@Override
public void clear() {
myMap.clear();
}
@Override
public int size() {
return myMap.size(); //?
}
@Override
public boolean isEmpty() {
return myMap.isEmpty(); //?
}
@Override
public boolean containsKey(Object key) {
return get(key) != null;
}
@Override
public boolean containsValue(Object value) {
throw new RuntimeException("method not implemented");
}
@Override
public Set<K> keySet() {
return myMap.keySet();
}
@Override
public Collection<V> values() {
List<V> result = new ArrayList<V>();
final Collection<MyReference<K, V>> refs = myMap.values();
@@ -113,6 +127,7 @@ public final class WeakValueHashMap<K,V> implements Map<K,V>{
return result;
}
@Override
public Set<Entry<K, V>> entrySet() {
throw new RuntimeException("method not implemented");
}
@@ -0,0 +1,107 @@
/*
* Copyright 2000-2012 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.util.containers;
import gnu.trove.TIntObjectHashMap;
import org.jetbrains.annotations.NotNull;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public class WeakValueIntObjectHashMap<V> {
private final TIntObjectHashMap<MyReference<V>> myMap = new TIntObjectHashMap<MyReference<V>>();
private final ReferenceQueue<V> myQueue = new ReferenceQueue<V>();
private static class MyReference<T> extends WeakReference<T> {
private final int key;
String name;
private MyReference(int key, T referent, ReferenceQueue<? super T> q) {
super(referent, q);
this.key = key;
}
}
private void processQueue() {
while(true){
MyReference ref = (MyReference)myQueue.poll();
if (ref == null) {
return;
}
int key = ref.key;
myMap.remove(key);
keyExpired(key);
}
}
protected void keyExpired(int key) {
}
public final V get(int key) {
MyReference<V> ref = myMap.get(key);
if (ref == null) return null;
return ref.get();
}
public final V put(int key, @NotNull V value) {
processQueue();
MyReference<V> ref = new MyReference<V>(key, value, myQueue);
ref.name = value.toString();
MyReference<V> oldRef = myMap.put(key, ref);
return oldRef != null ? oldRef.get() : null;
}
public final V remove(int key) {
processQueue();
MyReference<V> ref = myMap.remove(key);
return ref != null ? ref.get() : null;
}
public final void clear() {
myMap.clear();
processQueue();
}
public final int size() {
return myMap.size();
}
public final boolean isEmpty() {
return myMap.isEmpty();
}
public final boolean containsKey(int key) {
return get(key) != null;
}
@NotNull
public final Collection<V> values() {
List<V> result = new ArrayList<V>();
Object[] refs = myMap.getValues();
for (Object o : refs) {
@SuppressWarnings("unchecked")
final V value = ((MyReference<V>)o).get();
if (value != null) {
result.add(value);
}
}
return result;
}
}
@@ -0,0 +1,132 @@
/*
* Copyright 2000-2012 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.util.keyFMap;
import com.intellij.openapi.util.Key;
import org.jetbrains.annotations.NotNull;
class ArrayBackedFMap implements KeyFMap {
static final int ARRAY_THRESHOLD = 8;
private final int[] keys;
private final Object[] values;
ArrayBackedFMap(@NotNull int[] keys, @NotNull Object[] values) {
this.keys = keys;
this.values = values;
}
@NotNull
@Override
public <V> KeyFMap plus(@NotNull Key<V> key, @NotNull V value) {
int oldSize = size();
int keyCode = key.hashCode();
int[] newKeys = null;
Object[] newValues = null;
int i;
for (i = 0; i < oldSize; i++) {
int oldKey = keys[i];
if (keyCode == oldKey) {
if (value == values[i]) return this;
newKeys = new int[oldSize];
newValues = new Object[oldSize];
System.arraycopy(keys, 0, newKeys, 0, oldSize);
System.arraycopy(values, 0, newValues, 0, oldSize);
newValues[i] = value;
break;
}
}
if (i == oldSize) {
if (oldSize == ARRAY_THRESHOLD) {
return new MapBackedFMap(keys, keyCode, values, value);
}
int newSize = oldSize + 1;
newKeys = new int[newSize];
newValues = new Object[newSize];
System.arraycopy(keys, 0, newKeys, 0, oldSize);
System.arraycopy(values, 0, newValues, 0, oldSize);
newKeys[oldSize] = keyCode;
newValues[oldSize] = value;
}
return new ArrayBackedFMap(newKeys, newValues);
}
private int size() {
return keys.length;
}
@NotNull
@Override
public KeyFMap minus(@NotNull Key<?> key) {
int oldSize = size();
int keyCode = key.hashCode();
for (int i = 0; i< oldSize; i++) {
int oldKey = keys[i];
if (keyCode == oldKey) {
if (oldSize == 3) {
int i1 = (2-i)/2;
int i2 = 3 - (i+2)/2;
return new PairElementsFMap(keys[i1], values[i1], keys[i2], values[i2]);
}
int newSize = oldSize - 1;
int[] newKeys = new int[newSize];
Object[] newValues = new Object[newSize];
System.arraycopy(keys, 0, newKeys, 0, i);
System.arraycopy(values, 0, newValues, 0, i);
System.arraycopy(keys, i+1, newKeys, i, oldSize-i-1);
System.arraycopy(values, i+1, newValues, i, oldSize-i-1);
return new ArrayBackedFMap(newKeys, newValues);
}
}
return this;
//if (i == oldSize) {
//newKeys = new int[oldSize];
//newValues = new Object[oldSize];
//System.arraycopy(keys, 0, newKeys, 0, oldSize);
//System.arraycopy(values, 0, newValues, 0, oldSize);
//}
}
@Override
public <V> V get(@NotNull Key<V> key) {
int oldSize = size();
int keyCode = key.hashCode();
for (int i = 0; i < oldSize; i++) {
int oldKey = keys[i];
if (keyCode == oldKey) {
//noinspection unchecked
return (V)values[i];
}
}
return null;
}
@Override
public String toString() {
String s = "";
for (int i = 0; i < keys.length; i++) {
int key = keys[i];
Object value = values[i];
s += (s.isEmpty() ? "" : ", ") + Key.getKeyByIndex(key) + " -> " + value;
}
return "(" + s + ")";
}
@Override
public boolean isEmpty() {
return false;
}
}
@@ -0,0 +1,51 @@
/*
* Copyright 2000-2012 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.util.keyFMap;
import com.intellij.openapi.util.Key;
import org.jetbrains.annotations.NotNull;
class EmptyFMap implements KeyFMap {
EmptyFMap() {
}
@NotNull
@Override
public <V> KeyFMap plus(@NotNull Key<V> key, @NotNull V value) {
return new OneElementFMap<V>(key.hashCode(), value);
}
@NotNull
@Override
public KeyFMap minus(@NotNull Key<?> key) {
return this;
}
@Override
public <V> V get(@NotNull Key<V> key) {
return null;
}
@Override
public String toString() {
return "<empty>";
}
@Override
public boolean isEmpty() {
return true;
}
}
@@ -0,0 +1,42 @@
/*
* Copyright 2000-2012 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.util.keyFMap;
import com.intellij.openapi.util.Key;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* An immutable map optimized for storing few {@link Key} entries with relatively rare updates
* To construct a map, start with {@link KeyFMap#EMPTY_MAP} and call {@link #plus} and {@link #minus}
*
* @author peter
*/
public interface KeyFMap {
KeyFMap EMPTY_MAP = new EmptyFMap();
@NotNull
<V> KeyFMap plus(@NotNull Key<V> key, @NotNull V value);
@NotNull
KeyFMap minus(@NotNull Key<?> key);
@Nullable
<V> V get(@NotNull Key<V> key);
String toString();
boolean isEmpty();
}
@@ -0,0 +1,100 @@
/*
* Copyright 2000-2012 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.util.keyFMap;
import com.intellij.openapi.util.Key;
import com.intellij.util.ArrayUtil;
import gnu.trove.TIntObjectHashMap;
import gnu.trove.TIntObjectProcedure;
import org.jetbrains.annotations.NotNull;
class MapBackedFMap extends TIntObjectHashMap<Object> implements KeyFMap {
private MapBackedFMap(@NotNull MapBackedFMap oldMap, final int exclude) {
super(oldMap.size());
oldMap.forEachEntry(new TIntObjectProcedure<Object>() {
@Override
public boolean execute(int key, Object val) {
if (key != exclude) put(key, val);
assert key >= 0 : key;
return true;
}
});
assert size() > ArrayBackedFMap.ARRAY_THRESHOLD;
}
MapBackedFMap(@NotNull int[] keys, int newKey, @NotNull Object[] values, @NotNull Object newValue) {
for (int i = 0; i < keys.length; i++) {
int key = keys[i];
Object value = values[i];
put(key, value);
assert key >= 0 : key;
}
put(newKey, newValue);
assert newKey >= 0 : newKey;
assert size() > ArrayBackedFMap.ARRAY_THRESHOLD;
}
@NotNull
@Override
public <V> KeyFMap plus(@NotNull Key<V> key, @NotNull V value) {
int keyCode = key.hashCode();
assert keyCode >= 0 : key;
@SuppressWarnings("unchecked")
V oldValue = (V)get(keyCode);
if (value == oldValue) return this;
MapBackedFMap newMap = new MapBackedFMap(this, -1);
newMap.put(keyCode, value);
return newMap;
}
@NotNull
@Override
public KeyFMap minus(@NotNull Key<?> key) {
int oldSize = size();
int keyCode = key.hashCode();
if (!containsKey(keyCode)) {
return this;
}
if (oldSize == ArrayBackedFMap.ARRAY_THRESHOLD + 1) {
int[] keys = keys();
Object[] values = getValues();
int i = ArrayUtil.indexOf(keys, keyCode);
keys = ArrayUtil.remove(keys, i);
values = ArrayUtil.remove(values, i);
return new ArrayBackedFMap(keys, values);
}
return new MapBackedFMap(this, keyCode);
}
@Override
public <V> V get(@NotNull Key<V> key) {
//noinspection unchecked
return (V)get(key.hashCode());
}
@Override
public String toString() {
final StringBuilder s = new StringBuilder();
forEachEntry(new TIntObjectProcedure<Object>() {
@Override
public boolean execute(int key, Object value) {
s.append(s.length() == 0 ? "" : ", ").append(Key.getKeyByIndex(key)).append(" -> ").append(value);
return true;
}
});
return "[" + s.toString() + "]";
}
}

Some files were not shown because too many files have changed in this diff Show More