mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge branch 'master' into upsource-master
Conflicts: plugins/gettext/src/com/jetbrains/gettext/highlighter/GetTextHighlighterData.java
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+3
-1
@@ -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;
|
||||
|
||||
+2
-1
@@ -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);
|
||||
|
||||
+2
-1
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
+9
-4
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
+3
-2
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
+17
-1
@@ -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;
|
||||
|
||||
+2
-1
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+16
-6
@@ -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;
|
||||
}
|
||||
|
||||
+3
-2
@@ -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;
|
||||
}
|
||||
|
||||
+4
-3
@@ -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));
|
||||
}
|
||||
});
|
||||
|
||||
+372
-371
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+355
-356
@@ -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);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+4
-8
@@ -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);
|
||||
|
||||
+2
-1
@@ -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 + "'");
|
||||
|
||||
+1
-1
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
+9
-14
@@ -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);
|
||||
|
||||
+2
-5
@@ -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;
|
||||
|
||||
+2
-2
@@ -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);
|
||||
|
||||
+1
-1
@@ -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();
|
||||
|
||||
+170
-168
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -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
|
||||
|
||||
+2
-1
@@ -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();
|
||||
|
||||
+2
-1
@@ -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) {
|
||||
|
||||
+13
-9
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -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());
|
||||
|
||||
+2
-1
@@ -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;
|
||||
|
||||
+4
-1
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -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;
|
||||
}
|
||||
|
||||
+1
-1
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -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;
|
||||
}
|
||||
|
||||
+265
-264
@@ -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);
|
||||
}
|
||||
|
||||
+2
-2
@@ -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;
|
||||
|
||||
+3
-2
@@ -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;
|
||||
|
||||
+1
-1
@@ -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();
|
||||
|
||||
+2
-1
@@ -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;
|
||||
}
|
||||
|
||||
+2
-2
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
+1801
-1801
File diff suppressed because it is too large
Load Diff
+12
-7
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+31
-6
@@ -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;
|
||||
|
||||
+2
-1
@@ -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>
|
||||
|
||||
+2
-1
@@ -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
Reference in New Issue
Block a user