summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDana Dahlstrom <dahlstrom@google.com>2022-06-24 20:00:00 -0700
committerDana Dahlstrom <dahlstrom@google.com>2022-06-24 20:00:00 -0700
commit4d573076b17387943d28b5733899900405a0ed32 (patch)
treed8c70b0e7ac9197a6d63125e090d41657e2495f7
parentbc61b8c5206ae3afb2455cbba7cd15989f58a4ad (diff)
parentd5bf17fe27f61040fa11032fd075fc375658a567 (diff)
downloadidea-4d573076b17387943d28b5733899900405a0ed32.tar.gz
Merge IntelliJ IDEA 2022.1.3 221.5921.22
Change-Id: Id5bf17fe27f61040fa11032fd075fc375658a567
-rwxr-xr-xbin/mac/libmacscreenmenu64.dylibbin197128 -> 213941 bytes
-rw-r--r--build.txt2
-rw-r--r--community-resources/src/idea/IdeaApplicationInfo.xml2
-rw-r--r--java/debugger/impl/src/com/intellij/debugger/engine/CompoundPositionManager.java3
-rw-r--r--java/java-impl/src/com/intellij/spi/psi/SPIFile.java4
-rw-r--r--java/java-impl/src/com/intellij/spi/psi/SPIPackageOrClassReferenceElement.java9
-rw-r--r--java/java-tests/testSrc/com/intellij/java/openapi/vfs/JrtFileSystemTest.java26
-rw-r--r--java/java-tests/testSrc/com/intellij/util/indexing/IndexDiagnosticTest.kt3
-rw-r--r--native/MacScreenMenu/src/Menu.m20
-rw-r--r--platform/analysis-api/src/com/intellij/lang/refactoring/NamesValidator.java37
-rw-r--r--platform/core-api/src/com/intellij/openapi/components/AbstractProjectComponent.java4
-rw-r--r--platform/core-api/src/com/intellij/openapi/components/ProjectComponent.java12
-rw-r--r--platform/diff-impl/src/com/intellij/diff/impl/DiffViewerWrapper.java2
-rw-r--r--platform/editor-ui-api/src/com/intellij/ui/breadcrumbs/BreadcrumbsProvider.java21
-rw-r--r--platform/extensions/src/com/intellij/openapi/components/BaseComponent.java6
-rw-r--r--platform/external-system-api/src/com/intellij/openapi/externalSystem/util/ExternalSystemApiUtil.java9
-rw-r--r--platform/lang-api/src/com/intellij/codeInsight/completion/PlainTextSymbolCompletionContributor.java19
-rw-r--r--platform/lang-api/src/com/intellij/lang/surroundWith/SurroundDescriptor.java31
-rw-r--r--platform/lang-api/src/com/intellij/lang/surroundWith/Surrounder.java32
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/StatusItemMerger.java1
-rw-r--r--platform/lang-impl/src/com/intellij/find/EditorSearchSession.java4
-rw-r--r--platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/ActionSearchEverywhereContributor.java8
-rw-r--r--platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SEResultsEqualityProvider.kt37
-rw-r--r--platform/lang-impl/src/com/intellij/ide/projectView/ProjectViewNodeDecorator.java3
-rw-r--r--platform/lang-impl/src/com/intellij/psi/impl/cache/impl/IndexTodoCacheManagerImpl.java16
-rw-r--r--platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexProjectHandler.java5
-rw-r--r--platform/lang-impl/src/com/intellij/util/indexing/ForceIndexRescanningAction.java6
-rw-r--r--platform/lang-impl/src/com/intellij/util/indexing/RescanIndexesAction.kt8
-rw-r--r--platform/lang-impl/src/com/intellij/util/indexing/UnindexedFilesUpdater.java31
-rw-r--r--platform/lang-impl/src/com/intellij/util/indexing/diagnostic/ProjectIndexingHistory.kt52
-rw-r--r--platform/lang-impl/src/com/intellij/util/indexing/diagnostic/ProjectIndexingHistoryFusReporterListener.kt13
-rw-r--r--platform/lang-impl/src/com/intellij/util/indexing/diagnostic/ProjectIndexingHistoryImpl.kt6
-rw-r--r--platform/lang-impl/src/com/intellij/util/indexing/diagnostic/dto/JsonConverter.kt2
-rw-r--r--platform/lang-impl/src/com/intellij/util/indexing/diagnostic/dto/JsonProjectIndexingHistoryTimes.kt3
-rw-r--r--platform/lang-impl/src/com/intellij/util/indexing/diagnostic/presentation/jsonToHtmlConverter.kt5
-rw-r--r--platform/lang-impl/testSources/com/intellij/util/indexing/diagnostic/ProjectIndexingHistoryImplTest.kt18
-rw-r--r--platform/lvcs-impl/src/com/intellij/history/core/Paths.java2
-rw-r--r--platform/platform-api/resources/messages/IdeBundle.properties181
-rw-r--r--platform/platform-api/src/com/intellij/openapi/GitSilentFileAdder.java12
-rw-r--r--platform/platform-api/src/com/intellij/openapi/GitSilentFileAdderProvider.java10
-rw-r--r--platform/platform-api/src/com/intellij/ui/jcef/JBCefApp.java14
-rw-r--r--platform/platform-api/src/com/intellij/ui/jcef/JBCefAppCache.kt61
-rw-r--r--platform/platform-api/src/com/intellij/ui/jcef/JBCefAppCacheInvalidator.kt19
-rw-r--r--platform/platform-impl/src/com/intellij/application/options/editor/EditorTabsConfigurableEP.java20
-rw-r--r--platform/platform-impl/src/com/intellij/application/options/editor/EditorTabsOptionsCustomSection.java4
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionToolbarImpl.java1
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/PopupMenuPreloader.java2
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/command/impl/DefaultUndoReportHandler.java2
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/command/impl/UndoReportHandler.java2
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/wm/impl/headertoolbar/MainToolbarAppWidgetFactory.kt11
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/wm/impl/headertoolbar/MainToolbarProjectWidgetFactory.kt15
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/wm/impl/headertoolbar/MainToolbarWidgetFactory.kt15
-rw-r--r--platform/platform-impl/src/com/intellij/ui/GotItTooltip.kt47
-rw-r--r--platform/platform-impl/src/com/intellij/ui/Splash.java2
-rw-r--r--platform/platform-impl/src/com/intellij/ui/popup/list/ListPopupImpl.java2
-rw-r--r--platform/platform-resources/src/META-INF/PlatformExtensions.xml1
-rw-r--r--platform/platform-tests/testSrc/com/intellij/openapi/project/DumbServiceImplTest.groovy5
-rw-r--r--platform/platform-tests/testSrc/com/intellij/openapi/vfs/impl/VirtualFilePointerTest.java56
-rw-r--r--platform/platform-tests/testSrc/com/intellij/openapi/vfs/local/FileWatcherTest.kt40
-rw-r--r--platform/platform-tests/testSrc/com/intellij/openapi/vfs/local/WslFileWatcherTest.kt41
-rw-r--r--platform/platform-tests/testSrc/com/intellij/openapi/vfs/newvfs/persistent/PersistentFsTest.java19
-rw-r--r--platform/platform-tests/testSrc/com/intellij/util/io/PersistencePerformanceTest.java5
-rw-r--r--platform/projectModel-api/src/com/intellij/openapi/module/ModuleComponent.java10
-rw-r--r--platform/refactoring/src/com/intellij/refactoring/extractMethod/ExtractMethodHelper.java5
-rw-r--r--platform/refactoring/src/com/intellij/refactoring/rename/RenameInputValidator.java13
-rw-r--r--platform/refactoring/src/com/intellij/refactoring/rename/RenameInputValidatorEx.java8
-rw-r--r--platform/remoteDev-util/src/com/intellij/remoteDev/downloader/CodeWithMeClientDownloader.kt12
-rw-r--r--platform/remoteDev-util/src/com/intellij/remoteDev/downloader/CodeWithMeGuestLauncher.kt9
-rw-r--r--platform/testFramework/src/com/intellij/openapi/util/io/IoTestUtil.java21
-rw-r--r--platform/util/src/com/intellij/openapi/util/io/OSAgnosticPathUtil.java9
-rw-r--r--platform/util/testSrc/com/intellij/openapi/util/io/FileAttributesReadingTest.java8
-rw-r--r--platform/vcs-impl/src/com/intellij/codeInsight/hints/VcsCodeVisionProvider.kt38
-rw-r--r--platform/vfs-impl/src/com/intellij/openapi/vfs/impl/FilePartNodeRoot.java33
-rw-r--r--platform/vfs-impl/src/com/intellij/openapi/vfs/impl/VirtualFilePointerManagerImpl.java51
-rw-r--r--platform/vfs-impl/src/com/intellij/openapi/vfs/newvfs/VfsImplUtil.java7
-rw-r--r--platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/actions/XNewWatchAction.java46
-rw-r--r--platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/DebuggerUIUtil.java29
-rw-r--r--platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/actions/XAddToWatchesTreeAction.java25
-rw-r--r--plugins/InspectionGadgets/src/com/siyeh/ig/resources/AutoCloseableResourceInspection.java4
-rw-r--r--plugins/coverage/src/com/intellij/coverage/JavaCoverageEngine.java25
-rw-r--r--plugins/editorconfig/src/org/editorconfig/configmanagement/EditorConfigEncodingCache.java3
-rw-r--r--plugins/gradle/java/resources/META-INF/plugin.xml3
-rw-r--r--plugins/gradle/java/src/config/GradlePositionManager.java8
-rw-r--r--plugins/gradle/java/src/service/GradleProjectOutputsUpdater.kt44
-rw-r--r--plugins/gradle/plugin-resources/META-INF/plugin.xml2
-rw-r--r--plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/CommonGradleProjectResolverExtension.java18
-rw-r--r--plugins/gradle/src/org/jetbrains/plugins/gradle/service/task/GradleTaskManager.java1
-rw-r--r--plugins/gradle/src/org/jetbrains/plugins/gradle/service/task/GradleTaskResultListener.java26
-rw-r--r--plugins/gradle/testSources/org/jetbrains/plugins/gradle/importing/GradleDependenciesImportingTest.java11
-rw-r--r--plugins/gradle/testSources/org/jetbrains/plugins/gradle/importing/GradleFoldersImportingTest.java10
-rw-r--r--plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/builder/ExternalProjectBuilderImpl.groovy12
-rw-r--r--plugins/grazie/src/test/kotlin/com/intellij/grazie/text/TextExtractionTest.java20
-rw-r--r--plugins/grazie/src/test/testData/ide/language/properties/Example.properties1
-rw-r--r--plugins/grazie/src/test/testData/ide/language/xml/Example.xml1
-rw-r--r--plugins/grazie/xml/main/kotlin/com/intellij/grazie/ide/language/xml/XmlProblemFilter.java10
-rw-r--r--plugins/grazie/xml/main/kotlin/com/intellij/grazie/ide/language/xml/XmlTextExtractor.java20
-rw-r--r--plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/codeInspection/confusing/GroovyPointlessBooleanInspection.java8
-rw-r--r--plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/typing/DefaultMethodCallTypeCalculator.kt18
-rw-r--r--plugins/groovy/src/org/jetbrains/plugins/groovy/debugger/GroovyPositionManager.java39
-rw-r--r--plugins/groovy/src/org/jetbrains/plugins/groovy/extensions/debugger/ScriptPositionManagerHelper.java13
-rw-r--r--plugins/groovy/test/org/jetbrains/plugins/groovy/codeInspection/confusing/GroovyPointlessBooleanInspectionTest.groovy7
-rw-r--r--plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/TypeInferenceTest.groovy7
-rw-r--r--plugins/ide-features-trainer/src/training/util/Utils.kt2
-rw-r--r--python/helpers/pydev/_pydevd_bundle/pydevd_console_output.py22
-rw-r--r--python/ideCoreSrc/idea/PyCharmCoreApplicationInfo.xml2
-rw-r--r--python/src/com/jetbrains/python/sdk/PythonSdkUpdater.java5
-rw-r--r--python/testSrc/com/jetbrains/python/sdk/PySdkPathsTest.kt3
-rw-r--r--spellchecker/src/com/intellij/spellchecker/inspections/IdentifierSplitter.java1
-rw-r--r--spellchecker/src/com/intellij/spellchecker/inspections/TextSplitter.java13
-rw-r--r--spellchecker/testData/inspection/commentsWithMistakes/test.txt1
-rw-r--r--spellchecker/testSrc/com/intellij/spellchecker/inspector/SplitterTest.java6
-rw-r--r--xml/dom-openapi/src/com/intellij/util/xml/ui/UndoHelper.java6
112 files changed, 1176 insertions, 569 deletions
diff --git a/bin/mac/libmacscreenmenu64.dylib b/bin/mac/libmacscreenmenu64.dylib
index 2763946a05c1..8aabfd7209f6 100755
--- a/bin/mac/libmacscreenmenu64.dylib
+++ b/bin/mac/libmacscreenmenu64.dylib
Binary files differ
diff --git a/build.txt b/build.txt
index c4d55ece6d28..66d5774b2fdb 100644
--- a/build.txt
+++ b/build.txt
@@ -1 +1 @@
-221.5787.30.2211.SNAPSHOT
+221.5921.22.2211.SNAPSHOT
diff --git a/community-resources/src/idea/IdeaApplicationInfo.xml b/community-resources/src/idea/IdeaApplicationInfo.xml
index 0de0448af119..6db949992468 100644
--- a/community-resources/src/idea/IdeaApplicationInfo.xml
+++ b/community-resources/src/idea/IdeaApplicationInfo.xml
@@ -1,7 +1,7 @@
<component xmlns="http://jetbrains.org/intellij/schema/application-info"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://jetbrains.org/intellij/schema/application-info http://jetbrains.org/intellij/schema/ApplicationInfo.xsd">
- <version major="2022" minor="1.2"/>
+ <version major="2022" minor="1.3"/>
<company name="JetBrains s.r.o." url="https://www.jetbrains.com"/>
<build number="IC-__BUILD__" date="__BUILD_DATE__" majorReleaseDate="20220412" />
<logo url="/idea_community_logo.png" textcolor="ffffff" progressColor="ffae00" progressY="396" progressHeight="4" />
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/CompoundPositionManager.java b/java/debugger/impl/src/com/intellij/debugger/engine/CompoundPositionManager.java
index b89b2daf11da..63f8c932d959 100644
--- a/java/debugger/impl/src/com/intellij/debugger/engine/CompoundPositionManager.java
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/CompoundPositionManager.java
@@ -15,6 +15,7 @@ import com.intellij.execution.filters.LineNumbersMapping;
import com.intellij.openapi.application.ReadAction;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.fileTypes.FileTypeManager;
+import com.intellij.openapi.fileTypes.UnknownFileType;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiFile;
@@ -70,7 +71,7 @@ public class CompoundPositionManager implements PositionManagerWithConditionEval
private <T> T iterate(Producer<? extends T> processor, T defaultValue, @Nullable FileType fileType, boolean ignorePCE) {
for (PositionManager positionManager : myPositionManagers) {
- if (fileType != null) {
+ if (fileType != null && fileType != UnknownFileType.INSTANCE) {
Set<? extends FileType> types = positionManager.getAcceptedFileTypes();
if (types != null && !types.contains(fileType)) {
continue;
diff --git a/java/java-impl/src/com/intellij/spi/psi/SPIFile.java b/java/java-impl/src/com/intellij/spi/psi/SPIFile.java
index 91eb1946fd1d..3efd04d0f833 100644
--- a/java/java-impl/src/com/intellij/spi/psi/SPIFile.java
+++ b/java/java-impl/src/com/intellij/spi/psi/SPIFile.java
@@ -22,6 +22,7 @@ import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
+import com.intellij.psi.impl.source.resolve.reference.ReferenceProvidersRegistry;
import com.intellij.psi.util.ClassUtil;
import com.intellij.spi.SPIFileType;
import com.intellij.util.IncorrectOperationException;
@@ -45,6 +46,9 @@ public class SPIFile extends PsiFileBase {
@Override
public PsiReference @NotNull [] getReferences() {
+ PsiReference[] references = ReferenceProvidersRegistry.getReferencesFromProviders(this);
+ if (references.length > 0) return references;
+
return ReadAction.compute(() -> {
final List<PsiReference> refs = new ArrayList<>();
diff --git a/java/java-impl/src/com/intellij/spi/psi/SPIPackageOrClassReferenceElement.java b/java/java-impl/src/com/intellij/spi/psi/SPIPackageOrClassReferenceElement.java
index 16908aca1cdb..7a65f14f380e 100644
--- a/java/java-impl/src/com/intellij/spi/psi/SPIPackageOrClassReferenceElement.java
+++ b/java/java-impl/src/com/intellij/spi/psi/SPIPackageOrClassReferenceElement.java
@@ -19,6 +19,7 @@ import com.intellij.extapi.psi.ASTWrapperPsiElement;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.*;
+import com.intellij.psi.impl.source.resolve.reference.ReferenceProvidersRegistry;
import com.intellij.psi.util.ClassUtil;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.spi.SPIFileType;
@@ -109,4 +110,12 @@ public class SPIPackageOrClassReferenceElement extends ASTWrapperPsiElement impl
public PsiReference getReference() {
return this;
}
+
+ @Override
+ public PsiReference @NotNull [] getReferences() {
+ PsiReference[] references = ReferenceProvidersRegistry.getReferencesFromProviders(this);
+ if (references.length > 0) return references;
+
+ return super.getReferences();
+ }
}
diff --git a/java/java-tests/testSrc/com/intellij/java/openapi/vfs/JrtFileSystemTest.java b/java/java-tests/testSrc/com/intellij/java/openapi/vfs/JrtFileSystemTest.java
index 47050a9471d8..026431e856bc 100644
--- a/java/java-tests/testSrc/com/intellij/java/openapi/vfs/JrtFileSystemTest.java
+++ b/java/java-tests/testSrc/com/intellij/java/openapi/vfs/JrtFileSystemTest.java
@@ -6,17 +6,21 @@ import com.intellij.openapi.Disposable;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.util.io.IoTestUtil;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileManager;
import com.intellij.openapi.vfs.impl.jrt.JrtFileSystemImpl;
import com.intellij.openapi.vfs.jrt.JrtFileSystem;
import com.intellij.openapi.vfs.newvfs.events.VFileEvent;
+import com.intellij.openapi.vfs.newvfs.impl.VfsRootAccess;
import com.intellij.openapi.vfs.pointers.VirtualFilePointer;
import com.intellij.openapi.vfs.pointers.VirtualFilePointerManager;
import com.intellij.testFramework.VfsTestUtil;
import com.intellij.testFramework.fixtures.BareTestFixtureTestCase;
import com.intellij.testFramework.rules.TempDirectory;
+import com.intellij.util.UriUtil;
+import com.intellij.util.containers.ContainerUtil;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
@@ -30,8 +34,6 @@ import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.List;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.*;
@@ -42,7 +44,7 @@ public class JrtFileSystemTest extends BareTestFixtureTestCase {
private final Disposable myDisposable = Disposer.newDisposable();
private Path myTestData;
private Path myJrtPath;
- private VirtualFile myRoot;
+ private VirtualFile myRoot; // in jrt:// FS
@Before
public void setUp() throws IOException {
@@ -147,11 +149,27 @@ public class JrtFileSystemTest extends BareTestFixtureTestCase {
}
private static List<String> childNames(VirtualFile dir) {
- return Stream.of(dir.getChildren()).map(VirtualFile::getName).collect(Collectors.toList());
+ return ContainerUtil.map(dir.getChildren(), VirtualFile::getName);
}
private static void assertPointers(VirtualFilePointer[] pointers, boolean valid) {
assertThat(pointers).allMatch(p -> p.isValid() == valid);
assertThat(pointers).allMatch(p -> p.getFile() == null || p.getFile().isValid());
}
+
+ @Test
+ public void testJDKInstalledIntoDiskRootUnderWindowsDoesntCauseHorribleThings() {
+ IoTestUtil.assumeWindows();
+
+ IoTestUtil.performTestOnWindowsSubst(myJrtPath.toString(), substRoot -> {
+ VfsRootAccess.allowRootAccess(myDisposable, substRoot.getPath());
+
+ String substedUrl = "jrt://" + UriUtil.trimTrailingSlashes(FileUtil.toSystemIndependentName(substRoot.getPath())) + "/!/java.base";
+ VirtualFilePointer pointer = VirtualFilePointerManager.getInstance().create(substedUrl, myDisposable, null);
+ assertTrue(pointer.isValid());
+ VirtualFile file = pointer.getFile();
+ assertNotNull(file);
+ assertTrue(file.getFileSystem() instanceof JrtFileSystem);
+ });
+ }
} \ No newline at end of file
diff --git a/java/java-tests/testSrc/com/intellij/util/indexing/IndexDiagnosticTest.kt b/java/java-tests/testSrc/com/intellij/util/indexing/IndexDiagnosticTest.kt
index 8bdfcbcbaceb..cbda9b713438 100644
--- a/java/java-tests/testSrc/com/intellij/util/indexing/IndexDiagnosticTest.kt
+++ b/java/java-tests/testSrc/com/intellij/util/indexing/IndexDiagnosticTest.kt
@@ -10,6 +10,7 @@ import com.intellij.openapi.project.getProjectCachePath
import com.intellij.testFramework.fixtures.JavaCodeInsightFixtureTestCase
import com.intellij.util.SystemProperties
import com.intellij.util.indexing.diagnostic.IndexDiagnosticDumper
+import com.intellij.util.indexing.diagnostic.ScanningType
import com.intellij.util.indexing.diagnostic.dto.*
import com.intellij.util.indexing.diagnostic.dump.paths.PortableFilePath
import org.junit.Assert
@@ -73,7 +74,7 @@ class IndexDiagnosticTest : JavaCodeInsightFixtureTestCase() {
projectName = "projectName",
times = JsonProjectIndexingHistoryTimes(
"reason",
- false,
+ ScanningType.PARTIAL,
JsonDuration(123),
JsonDuration(456),
JsonDuration(789),
diff --git a/native/MacScreenMenu/src/Menu.m b/native/MacScreenMenu/src/Menu.m
index 0e296a732204..f3f6ef3e02b6 100644
--- a/native/MacScreenMenu/src/Menu.m
+++ b/native/MacScreenMenu/src/Menu.m
@@ -410,11 +410,21 @@ Java_com_intellij_ui_mac_screenmenu_Menu_nativeFindItemByTitle(JNIEnv *env, jobj
*/
JNIEXPORT jlong JNICALL
Java_com_intellij_ui_mac_screenmenu_Menu_nativeGetAppMenu(JNIEnv *env, jclass peerClass) {
- NSMenu * mainMenu = [NSApplication sharedApplication].mainMenu;
- id appMenu = [mainMenu numberOfItems] > 0 ? [mainMenu itemAtIndex:0] : nil;
- if (appMenu != nil) {
- appMenu = [appMenu submenu];
- [appMenu retain];
+ JNI_COCOA_ENTER();
+ __block id appMenu = nil;
+ dispatch_block_t block = ^{
+ NSMenu * mainMenu = [NSApplication sharedApplication].mainMenu;
+ appMenu = [mainMenu numberOfItems] > 0 ? [mainMenu itemAtIndex:0] : nil;
+ if (appMenu != nil) {
+ appMenu = [appMenu submenu];
+ [appMenu retain];
+ }
+ };
+ if ([NSThread isMainThread]) {
+ block();
+ } else {
+ dispatch_async_and_wait(dispatch_get_main_queue(), block);
}
return (jlong)appMenu;
+ JNI_COCOA_EXIT();
} \ No newline at end of file
diff --git a/platform/analysis-api/src/com/intellij/lang/refactoring/NamesValidator.java b/platform/analysis-api/src/com/intellij/lang/refactoring/NamesValidator.java
index 5e80ee5a541c..dad3050949da 100644
--- a/platform/analysis-api/src/com/intellij/lang/refactoring/NamesValidator.java
+++ b/platform/analysis-api/src/com/intellij/lang/refactoring/NamesValidator.java
@@ -1,43 +1,32 @@
-/*
- * Copyright 2000-2017 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.
- */
+// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.lang.refactoring;
import com.intellij.openapi.project.Project;
import org.jetbrains.annotations.NotNull;
/**
- * Instances of NamesValidator are obtained from {@link com.intellij.lang.Language} instance.
- * An instance encapsulates knowledge of identifier rules and keyword set of the language.
+ * Encapsulates the knowledge about identifier rules and keyword set of the assigned language.
+ * <p>
+ * Register in {@code com.intellij.lang.namesValidator} extension point.
+ * @see com.intellij.lang.LanguageNamesValidation
+ * @see <a href="https://plugins.jetbrains.com/docs/intellij/rename-refactoring.html">Rename Refactoring (IntelliJ Platform Docs)</a>
*/
public interface NamesValidator {
/**
* Checks if the specified string is a keyword in the custom language.
*
- * @param name the string to check.
- * @param project the project in the context of which the check is done.
- * @return true if the string is a keyword, false otherwise.
+ * @param name the string to check
+ * @param project the project in the context of which the check is done
+ * @return {@code true} if the string is a keyword, {@code false} otherwise
*/
boolean isKeyword(@NotNull String name, Project project);
/**
* Checks if the specified string is a valid identifier in the custom language.
*
- * @param name the string to check.
- * @param project the project in the context of which the check is done.
- * @return true if the string is a valid identifier, false otherwise.
+ * @param name the string to check
+ * @param project the project in the context of which the check is done
+ * @return {@code true} if the string is a valid identifier, {@code false} otherwise
*/
boolean isIdentifier(@NotNull String name, Project project);
-} \ No newline at end of file
+}
diff --git a/platform/core-api/src/com/intellij/openapi/components/AbstractProjectComponent.java b/platform/core-api/src/com/intellij/openapi/components/AbstractProjectComponent.java
index b2a12dc2f448..389d1d5ffbd6 100644
--- a/platform/core-api/src/com/intellij/openapi/components/AbstractProjectComponent.java
+++ b/platform/core-api/src/com/intellij/openapi/components/AbstractProjectComponent.java
@@ -1,10 +1,10 @@
-// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
+// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.openapi.components;
import com.intellij.openapi.project.Project;
/**
- * @deprecated Use {@link ProjectComponent} directly if needed.
+ * @deprecated Components are deprecated, please see <a href="https://plugins.jetbrains.com/docs/intellij/plugin-components.html">SDK Docs</a> for guidelines on migrating to other APIs.
*/
@Deprecated
public abstract class AbstractProjectComponent implements ProjectComponent {
diff --git a/platform/core-api/src/com/intellij/openapi/components/ProjectComponent.java b/platform/core-api/src/com/intellij/openapi/components/ProjectComponent.java
index 0c867e13af7e..4f7d43363a76 100644
--- a/platform/core-api/src/com/intellij/openapi/components/ProjectComponent.java
+++ b/platform/core-api/src/com/intellij/openapi/components/ProjectComponent.java
@@ -1,13 +1,13 @@
-// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
+// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.openapi.components;
/**
- * @deprecated components are deprecated. If you register a class as a project component it will be loaded, its instance will be created and
+ * @see com.intellij.openapi.project.ProjectManager#TOPIC
+ * @deprecated Components are deprecated, please see <a href="https://plugins.jetbrains.com/docs/intellij/plugin-components.html">SDK Docs</a> for guidelines on migrating to other APIs.
+ * <p>
+ * If you register a class as a project component it will be loaded, its instance will be created and
* {@link #initComponent()} and {@link #projectOpened()} methods will be called for each project even if user doesn't use any feature of your
- * plugin. Also plugins which declare project components don't support dynamic loading. Please see
- * <a href="http://www.jetbrains.org/intellij/sdk/docs/basics/plugin_structure/plugin_components.html">guidelines</a> on migrating to other APIs.
- *
- * See {@link com.intellij.openapi.project.ProjectManager#TOPIC}.
+ * plugin. Also, plugins which declare project components don't support dynamic loading.
*/
@Deprecated
public interface ProjectComponent extends BaseComponent {
diff --git a/platform/diff-impl/src/com/intellij/diff/impl/DiffViewerWrapper.java b/platform/diff-impl/src/com/intellij/diff/impl/DiffViewerWrapper.java
index f3e99bdc42e0..74019a35993f 100644
--- a/platform/diff-impl/src/com/intellij/diff/impl/DiffViewerWrapper.java
+++ b/platform/diff-impl/src/com/intellij/diff/impl/DiffViewerWrapper.java
@@ -19,6 +19,7 @@ import com.intellij.diff.DiffContext;
import com.intellij.diff.FrameDiffTool.DiffViewer;
import com.intellij.diff.requests.DiffRequest;
import com.intellij.openapi.util.Key;
+import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
/**
@@ -27,6 +28,7 @@ import org.jetbrains.annotations.NotNull;
* Please, consider using {@link com.intellij.diff.DiffTool}, {@link com.intellij.diff.DiffExtension} or introducing a better extension point into platform,
* rather than adding second usage of this one.
*/
+@ApiStatus.Internal
public interface DiffViewerWrapper {
Key<DiffViewerWrapper> KEY = Key.create("Diff.DiffViewerWrapper");
diff --git a/platform/editor-ui-api/src/com/intellij/ui/breadcrumbs/BreadcrumbsProvider.java b/platform/editor-ui-api/src/com/intellij/ui/breadcrumbs/BreadcrumbsProvider.java
index 92f23b1f0acb..85f4cdd1d365 100644
--- a/platform/editor-ui-api/src/com/intellij/ui/breadcrumbs/BreadcrumbsProvider.java
+++ b/platform/editor-ui-api/src/com/intellij/ui/breadcrumbs/BreadcrumbsProvider.java
@@ -14,33 +14,34 @@ import java.util.List;
import static java.util.Collections.emptyList;
/**
- * Allows to provide a language-specific breadcrumbs,
- * i.e. path to the file root from a selected PSI element.
+ * Allows providing language-specific breadcrumbs, i.e. path to the file root from a selected PSI element.
*/
public interface BreadcrumbsProvider {
ExtensionPointName<BreadcrumbsProvider> EP_NAME = ExtensionPointName.create("com.intellij.breadcrumbsInfoProvider");
/**
- * @return an array of languages supported by this provider
+ * @return array of languages supported by this provider
*/
Language[] getLanguages();
/**
* @param element that represents a single crumb
- * @return {@code true} if the specified element is supported by this provider
+ * @return {@code true} if this provider supports the specified element
*/
boolean acceptElement(@NotNull PsiElement element);
/**
+ * Determines the text for a single crumb from the provided element.
+ *
* @param element that represents a single crumb
- * @return a text for the specified element
+ * @return text for the crumb
*/
@NotNull
@NlsSafe String getElementInfo(@NotNull PsiElement element);
/**
* @param element that represents a single crumb
- * @return an icon for the specified element
+ * @return icon for the crumb
*/
@Nullable
default Icon getElementIcon(@NotNull PsiElement element) {
@@ -49,7 +50,7 @@ public interface BreadcrumbsProvider {
/**
* @param element that represents a single crumb
- * @return a description for the specified element
+ * @return description for the crumb
*/
@Nullable
default @NlsSafe String getElementTooltip(@NotNull PsiElement element) {
@@ -58,7 +59,7 @@ public interface BreadcrumbsProvider {
/**
* @param element that represents a single crumb
- * @return an element that represents a parent crumb, or {@code null}
+ * @return element that represents a parent crumb, or {@code null}
*/
@Nullable
default PsiElement getParent(@NotNull PsiElement element) {
@@ -69,7 +70,7 @@ public interface BreadcrumbsProvider {
* Reserved for future releases. Not supported yet.
*
* @param element that represents a single crumb
- * @return a list of elements to navigate
+ * @return list of elements to navigate
*/
@NotNull
default List<PsiElement> getChildren(@NotNull PsiElement element) {
@@ -78,7 +79,7 @@ public interface BreadcrumbsProvider {
/**
* @param element that represents a single crumb
- * @return a list of actions for context menu
+ * @return list of actions for the context menu
*/
@NotNull
default List<? extends Action> getContextActions(@NotNull PsiElement element) {
diff --git a/platform/extensions/src/com/intellij/openapi/components/BaseComponent.java b/platform/extensions/src/com/intellij/openapi/components/BaseComponent.java
index 372cd609de44..da9fea00876e 100644
--- a/platform/extensions/src/com/intellij/openapi/components/BaseComponent.java
+++ b/platform/extensions/src/com/intellij/openapi/components/BaseComponent.java
@@ -1,10 +1,8 @@
-// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
+// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.openapi.components;
/**
- * The base interface class for all components.
- *
- * @deprecated Components are deprecated; please see <a href="http://www.jetbrains.org/intellij/sdk/docs/basics/plugin_structure/plugin_components.html">SDK Docs</a> for guidelines on migrating to other APIs.
+ * @deprecated Components are deprecated, please see <a href="https://plugins.jetbrains.com/docs/intellij/plugin-components.html">SDK Docs</a> for guidelines on migrating to other APIs.
*/
@Deprecated
public interface BaseComponent extends NamedComponent {
diff --git a/platform/external-system-api/src/com/intellij/openapi/externalSystem/util/ExternalSystemApiUtil.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/util/ExternalSystemApiUtil.java
index eaeeaed79335..a6bc66e4ebcf 100644
--- a/platform/external-system-api/src/com/intellij/openapi/externalSystem/util/ExternalSystemApiUtil.java
+++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/util/ExternalSystemApiUtil.java
@@ -713,6 +713,15 @@ public final class ExternalSystemApiUtil {
return projectInfo.getExternalProjectStructure();
}
+ public static @Nullable DataNode<ProjectData> findProjectNode(
+ @NotNull Project project,
+ @NotNull ProjectSystemId systemId,
+ @NotNull String projectPath
+ ) {
+ ExternalProjectInfo projectInfo = findProjectInfo(project, systemId, projectPath);
+ if (projectInfo == null) return null;
+ return projectInfo.getExternalProjectStructure();
+ }
@ApiStatus.Experimental
public static @Nullable ExternalProjectInfo findProjectInfo(@NotNull Project project,
@NotNull ProjectSystemId systemId,
diff --git a/platform/lang-api/src/com/intellij/codeInsight/completion/PlainTextSymbolCompletionContributor.java b/platform/lang-api/src/com/intellij/codeInsight/completion/PlainTextSymbolCompletionContributor.java
index d8b5196057a0..74a017a0ce9a 100644
--- a/platform/lang-api/src/com/intellij/codeInsight/completion/PlainTextSymbolCompletionContributor.java
+++ b/platform/lang-api/src/com/intellij/codeInsight/completion/PlainTextSymbolCompletionContributor.java
@@ -8,21 +8,24 @@ import org.jetbrains.annotations.NotNull;
import java.util.Collection;
/**
- * A language-specific completion contributor which provides reasonable amount of symbols declared in given file
- * (likely only top-level declarations). Such contributor could be used in plain text editors like VCS commit message field
- * to help users referring to code symbols from the text.
+ * A language-specific completion contributor that should provide a reasonable number of symbols declared in a given file, e.g.,
+ * only top-level declarations.
+ * Such contributors can also help to complete words in plain text editors like VCS commit messages.
+ *
+ * Please see the <a href="https://plugins.jetbrains.com/docs/intellij/code-completion.html#contributor-based-completion">IntelliJ Platform Docs</a>
+ * for a high-level overview of contributor-based completion.
*
* @see PlainTextSymbolCompletionContributorEP
*/
public interface PlainTextSymbolCompletionContributor {
/**
- * Adds lookup elements from given file.
+ * Collects lookup elements from a given file.
*
- * @param file file to add elements from.
+ * @param file file for extracting lookup elements.
* @param invocationCount number of times the completion was invoked (see {@link CompletionParameters#getInvocationCount()}).
- * @param prefix a prefix string. It's not required to return only matches starting with prefix, but this may be used to improve
- * performance.
- * @return a collection of {@link LookupElement}'s to suggest.
+ * @param prefix prefix string that can be used to filter candidates.
+ * It's not required to return only matches starting with prefix, but it can improve performance.
+ * @return collection of suggestions used for completion.
*/
@NotNull
Collection<LookupElement> getLookupElements(@NotNull PsiFile file, int invocationCount, @NotNull String prefix);
diff --git a/platform/lang-api/src/com/intellij/lang/surroundWith/SurroundDescriptor.java b/platform/lang-api/src/com/intellij/lang/surroundWith/SurroundDescriptor.java
index 6ac9411ca140..5339c65d5a0f 100644
--- a/platform/lang-api/src/com/intellij/lang/surroundWith/SurroundDescriptor.java
+++ b/platform/lang-api/src/com/intellij/lang/surroundWith/SurroundDescriptor.java
@@ -1,18 +1,4 @@
-/*
- * Copyright 2000-2015 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.
- */
+// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.lang.surroundWith;
import com.intellij.psi.PsiElement;
@@ -20,14 +6,14 @@ import com.intellij.psi.PsiFile;
import org.jetbrains.annotations.NotNull;
/**
- * Defines a code fragment type on which the Surround With action can be used for files
+ * Defines a code fragment type on which the <em>Code | Surround With</em> action can be used for files
* in a custom language. All surround descriptors registered for a language are queried
* sequentially, and as soon as one is found that returns a non-empty list of elements
* from {@link #getElementsToSurround(PsiFile, int, int)}, the user
* is prompted to choose a specific surrounder for that surround descriptor.
*
- * @author ven
* @see com.intellij.lang.LanguageSurrounders
+ * @see <a href="https://plugins.jetbrains.com/docs/intellij/surround-with.html">Surround With (IntelliJ Platform Docs)</a>
*/
public interface SurroundDescriptor {
/**
@@ -35,7 +21,7 @@ public interface SurroundDescriptor {
* the specified selection in the specified file, or an empty array if no surrounders
* from this surround descriptor are applicable to the specified selection.
*
- * @param file the file where elements are to be surrounded.
+ * @param file the file where elements are to be surrounded
* @param startOffset the selection start offset, with whitespaces skipped
* @param endOffset the selection end offset, with whitespaces skipped
* @return the elements to be surrounded, or an empty array if cannot surround
@@ -43,12 +29,13 @@ public interface SurroundDescriptor {
PsiElement @NotNull [] getElementsToSurround(PsiFile file, int startOffset, int endOffset);
/**
- * Returns the list of surrounders (surround templates) which can be used for this
- * code fragment type.
- *
- * @return the list of surrounders.
+ * @return the list of surrounders (surround templates) which can be used for this code fragment type
*/
Surrounder @NotNull [] getSurrounders();
+ /**
+ * If {@code true} then only surrounders from all applicable exclusive surround descriptors
+ * will be included in the <em>Code | Surround With</em> action.
+ */
boolean isExclusive();
}
diff --git a/platform/lang-api/src/com/intellij/lang/surroundWith/Surrounder.java b/platform/lang-api/src/com/intellij/lang/surroundWith/Surrounder.java
index f75095e3f0cd..dcfa6b5a12b3 100644
--- a/platform/lang-api/src/com/intellij/lang/surroundWith/Surrounder.java
+++ b/platform/lang-api/src/com/intellij/lang/surroundWith/Surrounder.java
@@ -1,18 +1,4 @@
-/*
- * 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.
- */
+// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.lang.surroundWith;
import com.intellij.openapi.editor.Editor;
@@ -26,19 +12,17 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
- * Defines a single template which can be used in Surround With.
+ * Defines a single template which can be used in <em>Code | Surround With</em> action.
*
- * @author ven
* @see SurroundDescriptor
+ * @see <a href="https://plugins.jetbrains.com/docs/intellij/surround-with.html">Surround With (IntelliJ Platform Docs)</a>
*/
public interface Surrounder {
Surrounder[] EMPTY_ARRAY = new Surrounder[0];
ArrayFactory<Surrounder> myArrayFactory = count -> count == 0 ? EMPTY_ARRAY : new Surrounder[count];
/**
- * Returns the user-visible name of the Surround With template.
- *
- * @return the template name
+ * @return the user-visible name of the <em>Surround With</em> template
*/
@NlsActions.ActionText
String getTemplateDescription();
@@ -47,16 +31,14 @@ public interface Surrounder {
* Checks if the template can be used to surround the specified range of elements.
*
* @param elements the elements to be surrounded
- * @return true if the template is applicable to the elements, false otherwise.
+ * @return {@code true} if the template is applicable to the elements, {@code false} otherwise
*/
boolean isApplicable(PsiElement @NotNull [] elements);
/**
- * Performs the Surround With action on the specified range of elements.
+ * Performs the <em>Code | Surround With</em> action on the specified range of elements.
*
- * @param project the project containing the elements.
- * @param editor the editor in which the action is invoked.
- * @param elements the elements to be surrounded.
+ * @param elements the elements to be surrounded
* @return range to select/to position the caret
*/
@Nullable
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/StatusItemMerger.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/StatusItemMerger.java
index 718f5a4f9126..5ab75f2fc0c8 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/StatusItemMerger.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/StatusItemMerger.java
@@ -8,6 +8,7 @@ import org.jetbrains.annotations.Nullable;
import java.util.Objects;
+/** An extension allowing to merge adjacent severity-based icons in the editor's code analysis indicator */
public abstract class StatusItemMerger {
static final ExtensionPointName<StatusItemMerger> EP_NAME = ExtensionPointName.create("com.intellij.daemon.statusItemMerger");
diff --git a/platform/lang-impl/src/com/intellij/find/EditorSearchSession.java b/platform/lang-impl/src/com/intellij/find/EditorSearchSession.java
index 28d7e6a05eb5..7c9dc4133681 100644
--- a/platform/lang-impl/src/com/intellij/find/EditorSearchSession.java
+++ b/platform/lang-impl/src/com/intellij/find/EditorSearchSession.java
@@ -1,4 +1,4 @@
-// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
+// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.find;
@@ -750,7 +750,7 @@ public class EditorSearchSession implements SearchSession,
private class ExcludeAction extends ButtonAction implements LightEditCompatible {
ExcludeAction() {
- super("", 'l');
+ super(FindBundle.message("button.exclude"), 'l');
}
@Override
diff --git a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/ActionSearchEverywhereContributor.java b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/ActionSearchEverywhereContributor.java
index 17b81e1d40d9..dff8210c7a7f 100644
--- a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/ActionSearchEverywhereContributor.java
+++ b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/ActionSearchEverywhereContributor.java
@@ -232,12 +232,12 @@ public class ActionSearchEverywhereContributor implements WeightedSearchEverywhe
private FoundItemDescriptor<GotoActionModel.MatchedValue> getMLWeightedItemDescriptor(@NotNull SearchEverywhereMlService service,
@NotNull GotoActionModel.MatchedValue element) {
- if (element.getType() == GotoActionModel.MatchedValueType.ABBREVIATION) {
- return new FoundItemDescriptor<>(element, element.getMatchingDegree(), 1.0);
- }
-
double mlWeight = service.getMlWeight(this, element, element.getMatchingDegree());
if (mlWeight > 0) {
+ if (element.getType() == GotoActionModel.MatchedValueType.ABBREVIATION) {
+ return new FoundItemDescriptor<>(element, element.getMatchingDegree(), 1.0);
+ }
+
return new FoundItemDescriptor<>(element, element.getMatchingDegree(), mlWeight);
}
return new FoundItemDescriptor<>(element, element.getMatchingDegree());
diff --git a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SEResultsEqualityProvider.kt b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SEResultsEqualityProvider.kt
index 1c2932f9f29b..126803303731 100644
--- a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SEResultsEqualityProvider.kt
+++ b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SEResultsEqualityProvider.kt
@@ -3,14 +3,43 @@ package com.intellij.ide.actions.searcheverywhere
import com.intellij.openapi.extensions.ExtensionPointName
+/**
+ * Equality provider can be used to compare items found by different (or sometimes same) instances of
+ * [SearchEverywhereContributor] and decide that those items are pointing to the same entity.
+ *
+ * For example, following items can be instances of different classes, but the same entities:
+ * - Same file returned by [FileSearchEverywhereContributor] and [RecentFilesSEContributor]
+ * - Java public class and .java file containing this class
+ * - Different links/wrappers to the same [com.intellij.psi.PsiElement]
+ * - etc.
+ */
interface SEResultsEqualityProvider {
+
+ /**
+ * List of possible actions for [compareItems] method.
+ */
sealed class SEEqualElementsActionType {
+
+ /**
+ * Nothing to do.
+ * Should be used when found item is not equal to any already found one.
+ */
object DoNothing : SEEqualElementsActionType() {
override fun combine(another: SEEqualElementsActionType): SEEqualElementsActionType = another
}
+
+ /**
+ * New found item should be skipped.
+ * Should be used when better presentation of found entity already exists in results.
+ */
object Skip : SEEqualElementsActionType() {
override fun combine(another: SEEqualElementsActionType): SEEqualElementsActionType = if (another is Replace) another else this
}
+
+ /**
+ * Already existing item `toBeReplaced` should be replaced with the new found item.
+ * Should be used when equal item already exists in results but new one represents corresponding entity better.
+ */
data class Replace(val toBeReplaced: List<SearchEverywhereFoundElementInfo>) : SEEqualElementsActionType() {
constructor(toBeReplaced: SearchEverywhereFoundElementInfo) : this(listOf(toBeReplaced))
@@ -20,6 +49,14 @@ interface SEResultsEqualityProvider {
abstract fun combine(another: SEEqualElementsActionType): SEEqualElementsActionType
}
+ /**
+ * Compare just found [SearchEverywhereFoundElementInfo] with list of already found items and decide how this new item should be handled.
+ *
+ * See [SEEqualElementsActionType] for possible actions
+ *
+ * @param newItem new found item. This item is suggested to be added to results list.
+ * @param alreadyFoundItems list of already found results. Those items are already shown in results list.
+ */
fun compareItems(newItem: SearchEverywhereFoundElementInfo, alreadyFoundItems: List<SearchEverywhereFoundElementInfo>): SEEqualElementsActionType
companion object {
diff --git a/platform/lang-impl/src/com/intellij/ide/projectView/ProjectViewNodeDecorator.java b/platform/lang-impl/src/com/intellij/ide/projectView/ProjectViewNodeDecorator.java
index 6f94396c0ab5..3080c011b7e3 100644
--- a/platform/lang-impl/src/com/intellij/ide/projectView/ProjectViewNodeDecorator.java
+++ b/platform/lang-impl/src/com/intellij/ide/projectView/ProjectViewNodeDecorator.java
@@ -9,6 +9,9 @@ import com.intellij.ui.ColoredTreeCellRenderer;
/**
* Allows modifying the presentation of project view and package dependencies view nodes.
*
+ * Please see the <a href="https://plugins.jetbrains.com/docs/intellij/project-view.html#decorating-project-view-nodes">IntelliJ Platform Docs</a>
+ * for a high-level overview.
+ *
* @see TreeStructureProvider
*/
public interface ProjectViewNodeDecorator {
diff --git a/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/IndexTodoCacheManagerImpl.java b/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/IndexTodoCacheManagerImpl.java
index dc602d12626f..e28674fc52c1 100644
--- a/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/IndexTodoCacheManagerImpl.java
+++ b/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/IndexTodoCacheManagerImpl.java
@@ -5,6 +5,7 @@ package com.intellij.psi.impl.cache.impl;
import com.intellij.injected.editor.VirtualFileWindow;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.fileEditor.FileDocumentManager;
+import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
@@ -52,14 +53,25 @@ public class IndexTodoCacheManagerImpl implements TodoCacheManager {
@Override
public boolean processFilesWithTodoItems(@NotNull Processor<? super PsiFile> processor) {
if (myProject.isDefault()) return true;
- GlobalSearchScope scope = GlobalSearchScope.allScope(myProject);
+ GlobalSearchScope scope = new GlobalSearchScope(myProject) {
+ @Override
+ public boolean isSearchInModuleContent(@NotNull Module module) { return true; }
+
+ @Override
+ public boolean isSearchInLibraries() { return false; }
+
+ @Override
+ public boolean contains(@NotNull VirtualFile file) {
+ return TodoIndexers.belongsToProject(myProject, file);
+ }
+ };
ConcurrentBitSet idSet = ConcurrentBitSet.create();
ManagingFS fs = ManagingFS.getInstance();
PsiManager psiManager = PsiManager.getInstance(myProject);
IntPredicate consumer = fileId -> {
VirtualFile file = fs.findFileById(fileId);
- if (file == null || !file.isValid() || !scope.contains(file) || !TodoIndexers.belongsToProject(myProject, file)) return true;
+ if (file == null || !file.isValid() || !scope.contains(file)) return true;
PsiFile psiFile = psiManager.findFile(file);
return psiFile == null || processor.process(psiFile);
};
diff --git a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexProjectHandler.java b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexProjectHandler.java
index 51e6618a34c9..b8878cd81cbc 100644
--- a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexProjectHandler.java
+++ b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexProjectHandler.java
@@ -1,4 +1,4 @@
-// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.util.indexing;
import com.intellij.diagnostic.PerformanceWatcher;
@@ -15,6 +15,7 @@ import com.intellij.util.indexing.contentQueue.IndexUpdateRunner;
import com.intellij.util.indexing.diagnostic.IndexDiagnosticDumper;
import com.intellij.util.indexing.diagnostic.ProjectIndexingHistoryImpl;
import com.intellij.util.indexing.diagnostic.ScanningStatistics;
+import com.intellij.util.indexing.diagnostic.ScanningType;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -92,7 +93,7 @@ public final class FileBasedIndexProjectHandler {
@NotNull Project project,
long refreshedFilesCalcDuration) {
ProjectIndexingHistoryImpl projectIndexingHistory =
- new ProjectIndexingHistoryImpl(project, "On refresh of " + files.size() + " files", false);
+ new ProjectIndexingHistoryImpl(project, "On refresh of " + files.size() + " files", ScanningType.REFRESH);
IndexDiagnosticDumper.getInstance().onIndexingStarted(projectIndexingHistory);
((FileBasedIndexImpl)FileBasedIndex.getInstance()).fireUpdateStarted(project);
diff --git a/platform/lang-impl/src/com/intellij/util/indexing/ForceIndexRescanningAction.java b/platform/lang-impl/src/com/intellij/util/indexing/ForceIndexRescanningAction.java
index a59c83922d21..e464c4142cf5 100644
--- a/platform/lang-impl/src/com/intellij/util/indexing/ForceIndexRescanningAction.java
+++ b/platform/lang-impl/src/com/intellij/util/indexing/ForceIndexRescanningAction.java
@@ -1,9 +1,10 @@
-// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
+// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.util.indexing;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.project.DumbAwareAction;
import com.intellij.openapi.project.Project;
+import com.intellij.util.indexing.diagnostic.ScanningType;
import org.jetbrains.annotations.NotNull;
final class ForceIndexRescanningAction extends DumbAwareAction {
@@ -15,7 +16,8 @@ final class ForceIndexRescanningAction extends DumbAwareAction {
false,
false,
null,
- "Force re-scanning");
+ "Force re-scanning",
+ ScanningType.FULL_FORCED);
task.queue(project);
}
}
diff --git a/platform/lang-impl/src/com/intellij/util/indexing/RescanIndexesAction.kt b/platform/lang-impl/src/com/intellij/util/indexing/RescanIndexesAction.kt
index d381ab9056d5..1f659a703777 100644
--- a/platform/lang-impl/src/com/intellij/util/indexing/RescanIndexesAction.kt
+++ b/platform/lang-impl/src/com/intellij/util/indexing/RescanIndexesAction.kt
@@ -1,4 +1,4 @@
-// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
+// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.util.indexing
import com.intellij.ide.actions.cache.*
@@ -7,13 +7,13 @@ import com.intellij.openapi.diagnostic.logger
import com.intellij.openapi.progress.ProgressIndicator
import com.intellij.openapi.progress.util.ProgressIndicatorUtils
import com.intellij.openapi.project.DumbModeTask
-import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.openapi.vfs.VirtualFileWithId
import com.intellij.psi.stubs.StubTreeBuilder
import com.intellij.psi.stubs.StubUpdatingIndex
import com.intellij.util.BooleanFunction
import com.intellij.util.indexing.diagnostic.ProjectIndexingHistoryImpl
+import com.intellij.util.indexing.diagnostic.ScanningType
import com.intellij.util.indexing.roots.IndexableFilesIterator
import com.intellij.util.indexing.roots.ProjectIndexableFilesIteratorImpl
import org.jetbrains.annotations.ApiStatus
@@ -39,7 +39,9 @@ class RescanIndexesAction : RecoveryAction {
if (recoveryScope is FilesRecoveryScope) {
predefinedIndexableFilesIterators = recoveryScope.files.map { ProjectIndexableFilesIteratorImpl(it) }
}
- object : UnindexedFilesUpdater(project, predefinedIndexableFilesIterators, "Rescanning indexes recovery action") {
+ object : UnindexedFilesUpdater(project, false, false,
+ predefinedIndexableFilesIterators, "Rescanning indexes recovery action",
+ if(predefinedIndexableFilesIterators == null) ScanningType.FULL_FORCED else ScanningType.PARTIAL_FORCED) {
private val stubIndex =
runCatching { (FileBasedIndex.getInstance() as FileBasedIndexImpl).getIndex(StubUpdatingIndex.INDEX_ID) }
.onFailure { logger<RescanIndexesAction>().error(it) }.getOrNull()
diff --git a/platform/lang-impl/src/com/intellij/util/indexing/UnindexedFilesUpdater.java b/platform/lang-impl/src/com/intellij/util/indexing/UnindexedFilesUpdater.java
index 87597de332ba..53798fa938ca 100644
--- a/platform/lang-impl/src/com/intellij/util/indexing/UnindexedFilesUpdater.java
+++ b/platform/lang-impl/src/com/intellij/util/indexing/UnindexedFilesUpdater.java
@@ -1,4 +1,4 @@
-// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.util.indexing;
import com.intellij.diagnostic.PerformanceWatcher;
@@ -36,6 +36,7 @@ import com.intellij.util.indexing.contentQueue.IndexUpdateRunner;
import com.intellij.util.indexing.diagnostic.IndexDiagnosticDumper;
import com.intellij.util.indexing.diagnostic.ProjectIndexingHistoryImpl;
import com.intellij.util.indexing.diagnostic.ScanningStatistics;
+import com.intellij.util.indexing.diagnostic.ScanningType;
import com.intellij.util.indexing.diagnostic.dto.JsonScanningStatistics;
import com.intellij.util.indexing.roots.IndexableFileScanner;
import com.intellij.util.indexing.roots.IndexableFilesDeduplicateFilter;
@@ -85,6 +86,7 @@ public class UnindexedFilesUpdater extends DumbModeTask {
private final boolean myStartSuspended;
private final boolean myOnProjectOpen;
private final @NonNls String myIndexingReason;
+ private final @NotNull ScanningType myScanningType;
private final PushedFilePropertiesUpdater myPusher;
private final @Nullable List<IndexableFilesIterator> myPredefinedIndexableFilesIterators;
@@ -92,11 +94,13 @@ public class UnindexedFilesUpdater extends DumbModeTask {
boolean startSuspended,
boolean onProjectOpen,
@Nullable List<IndexableFilesIterator> predefinedIndexableFilesIterators,
- @Nullable @NonNls String indexingReason) {
+ @Nullable @NonNls String indexingReason,
+ @NotNull ScanningType scanningType) {
myProject = project;
myStartSuspended = startSuspended;
myOnProjectOpen = onProjectOpen;
myIndexingReason = indexingReason;
+ myScanningType = scanningType;
myPusher = PushedFilePropertiesUpdater.getInstance(myProject);
myPredefinedIndexableFilesIterators = predefinedIndexableFilesIterators;
@@ -156,7 +160,8 @@ public class UnindexedFilesUpdater extends DumbModeTask {
myStartSuspended,
false,
mergeIterators(myPredefinedIndexableFilesIterators, ((UnindexedFilesUpdater)taskFromQueue).myPredefinedIndexableFilesIterators),
- reason
+ reason,
+ ScanningType.Companion.merge(oldTask.myScanningType, oldTask.myScanningType)
);
}
@@ -177,17 +182,18 @@ public class UnindexedFilesUpdater extends DumbModeTask {
// If we haven't succeeded to fully scan the project content yet, then we must keep trying to run
// file based index extensions for all project files until at least one of UnindexedFilesUpdater-s finishes without cancellation.
// This is important, for example, for shared indexes: all files must be associated with their locally available shared index chunks.
- this(project, false, false, null, null);
+ this(project, false, false, null, null, ScanningType.FULL);
}
public UnindexedFilesUpdater(@NotNull Project project, @Nullable @NonNls String indexingReason) {
- this(project, false, false, null, indexingReason);
+ this(project, false, false, null, indexingReason, ScanningType.FULL);
}
public UnindexedFilesUpdater(@NotNull Project project,
@Nullable List<IndexableFilesIterator> predefinedIndexableFilesIterators,
@Nullable @NonNls String indexingReason) {
- this(project, false, false, predefinedIndexableFilesIterators, indexingReason);
+ this(project, false, false, predefinedIndexableFilesIterators, indexingReason,
+ predefinedIndexableFilesIterators == null ? ScanningType.FULL : ScanningType.PARTIAL);
}
private void updateUnindexedFiles(@NotNull ProjectIndexingHistoryImpl projectIndexingHistory, @NotNull ProgressIndicator indicator) {
@@ -573,7 +579,8 @@ public class UnindexedFilesUpdater extends DumbModeTask {
}
protected @NotNull ProjectIndexingHistoryImpl performScanningAndIndexing(@NotNull ProgressIndicator indicator) {
- ProjectIndexingHistoryImpl projectIndexingHistory = new ProjectIndexingHistoryImpl(myProject, myIndexingReason, isFullIndexUpdate());
+ ProjectIndexingHistoryImpl projectIndexingHistory =
+ new ProjectIndexingHistoryImpl(myProject, myIndexingReason, myScanningType);
myIndex.loadIndexes();
myIndex.filesUpdateStarted(myProject, isFullIndexUpdate());
IndexDiagnosticDumper.getInstance().onIndexingStarted(projectIndexingHistory);
@@ -643,17 +650,21 @@ public class UnindexedFilesUpdater extends DumbModeTask {
return SystemProperties.getBooleanProperty("ij.indexes.skip.initial.refresh", false);
}
- public static void scanAndIndexProjectAfterOpen(@NotNull Project project, boolean startSuspended, @Nullable @NonNls String indexingReason) {
+ public static void scanAndIndexProjectAfterOpen(@NotNull Project project,
+ boolean startSuspended,
+ @Nullable @NonNls String indexingReason) {
if (TestModeFlags.is(INDEX_PROJECT_WITH_MANY_UPDATERS_TEST_KEY)) {
LOG.assertTrue(ApplicationManager.getApplication().isUnitTestMode());
List<IndexableFilesIterator> iterators = collectProviders(project, (FileBasedIndexImpl)FileBasedIndex.getInstance());
for (IndexableFilesIterator iterator : iterators) {
- new UnindexedFilesUpdater(project, startSuspended, true, Collections.singletonList(iterator), indexingReason).queue(project);
+ new UnindexedFilesUpdater(project, startSuspended, true, Collections.singletonList(iterator), indexingReason,
+ ScanningType.FULL_ON_PROJECT_OPEN).queue(project);
}
project.putUserData(CONTENT_SCANNED, true);
}
else {
- new UnindexedFilesUpdater(project, startSuspended, true, null, indexingReason).queue(project);
+ new UnindexedFilesUpdater(project, startSuspended, true, null, indexingReason, ScanningType.FULL_ON_PROJECT_OPEN).
+ queue(project);
}
}
}
diff --git a/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/ProjectIndexingHistory.kt b/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/ProjectIndexingHistory.kt
index f7fa953ce974..495348b196db 100644
--- a/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/ProjectIndexingHistory.kt
+++ b/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/ProjectIndexingHistory.kt
@@ -33,6 +33,56 @@ interface ProjectIndexingHistory {
val visibleTimeToAllThreadsTimeRatio: Double
}
+/**
+ * isFull - if the whole project was rescanned (instead of a part of it)
+ */
+enum class ScanningType(val isFull: Boolean) {
+ /**
+ * Full project rescan forced by user via Repair IDE action
+ */
+ FULL_FORCED(true),
+
+ /**
+ * It's mandatory full project rescan on project open
+ */
+ FULL_ON_PROJECT_OPEN(true),
+
+ /**
+ * Full project rescan requested by some code
+ */
+ FULL(true),
+
+
+ /**
+ * Partial rescan forced by user via Repair IDE action on a limited scope (not full project)
+ */
+ PARTIAL_FORCED(false),
+
+ /**
+ * Partial project rescan requested by some code
+ */
+ PARTIAL(false),
+
+ /**
+ * Some files were considered changed and therefore rescanned
+ */
+ REFRESH(false);
+
+ companion object {
+ fun merge(first: ScanningType, second: ScanningType): ScanningType = returnFirstFound(first, second,
+ FULL_FORCED, FULL_ON_PROJECT_OPEN, FULL,
+ PARTIAL_FORCED, PARTIAL,
+ REFRESH)
+
+ private fun returnFirstFound(first: ScanningType, second: ScanningType, vararg types: ScanningType): ScanningType {
+ for (type in types) {
+ if (first == type || second == type) return type
+ }
+ throw IllegalStateException("Unexpected ScanningType $first $second")
+ }
+ }
+}
+
interface StatsPerFileType {
val totalNumberOfFiles: Int
val totalBytes: BytesNumber
@@ -58,7 +108,7 @@ interface StatsPerIndexer {
interface IndexingTimes {
val indexingReason: String?
- val wasFullIndexing: Boolean
+ val scanningType: ScanningType
val updatingStart: ZonedDateTime
val totalUpdatingTime: TimeNano
val updatingEnd: ZonedDateTime
diff --git a/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/ProjectIndexingHistoryFusReporterListener.kt b/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/ProjectIndexingHistoryFusReporterListener.kt
index b3643550c5ce..b845875b42a6 100644
--- a/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/ProjectIndexingHistoryFusReporterListener.kt
+++ b/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/ProjectIndexingHistoryFusReporterListener.kt
@@ -11,7 +11,9 @@ import com.intellij.openapi.fileTypes.FileType
import com.intellij.openapi.fileTypes.FileTypeManager
import com.intellij.openapi.project.Project
import com.intellij.util.indexing.diagnostic.dto.toMillis
+import java.util.*
import java.util.concurrent.TimeUnit
+import kotlin.collections.HashMap
import kotlin.math.roundToLong
class ProjectIndexingHistoryFusReporterListener : ProjectIndexingHistoryListener {
@@ -48,7 +50,7 @@ class ProjectIndexingHistoryFusReporterListener : ProjectIndexingHistoryListener
ProjectIndexingHistoryFusReporter.reportIndexingFinished(
projectIndexingHistory.project,
projectIndexingHistory.indexingSessionId,
- projectIndexingHistory.times.wasFullIndexing,
+ projectIndexingHistory.times.scanningType,
projectIndexingHistory.times.totalUpdatingTime.toMillis(),
projectIndexingHistory.times.indexingDuration.toMillis(),
scanningTime,
@@ -78,13 +80,14 @@ class ProjectIndexingHistoryFusReporterListener : ProjectIndexingHistoryListener
}
object ProjectIndexingHistoryFusReporter : CounterUsagesCollector() {
- private val GROUP = EventLogGroup("indexing.statistics", 5)
+ private val GROUP = EventLogGroup("indexing.statistics", 6)
override fun getGroup() = GROUP
private val indexingSessionId = EventFields.Long("indexing_session_id")
private val isFullIndexing = EventFields.Boolean("is_full")
+ private val scanningType = EventFields.Enum<ScanningType>("type") { type -> type.name.lowercase(Locale.ENGLISH) }
private val totalTime = EventFields.Long("total_time")
private val indexingTime = EventFields.Long("indexing_time")
private val scanningTime = EventFields.Long("scanning_time")
@@ -112,6 +115,7 @@ object ProjectIndexingHistoryFusReporter : CounterUsagesCollector() {
"finished",
indexingSessionId,
isFullIndexing,
+ scanningType,
totalTime,
indexingTime,
scanningTime,
@@ -134,7 +138,7 @@ object ProjectIndexingHistoryFusReporter : CounterUsagesCollector() {
fun reportIndexingFinished(
project: Project,
indexingSessionId: Long,
- wasFullIndexing: Boolean,
+ scanningType: ScanningType,
totalTime: Long,
indexingTime: Long,
scanningTime: Long,
@@ -150,7 +154,8 @@ object ProjectIndexingHistoryFusReporter : CounterUsagesCollector() {
indexingFinished.log(
project,
this.indexingSessionId.with(indexingSessionId),
- this.isFullIndexing.with(wasFullIndexing),
+ this.isFullIndexing.with(scanningType.isFull),
+ this.scanningType.with(scanningType),
this.totalTime.with(totalTime),
this.indexingTime.with(indexingTime),
this.scanningTime.with(scanningTime),
diff --git a/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/ProjectIndexingHistoryImpl.kt b/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/ProjectIndexingHistoryImpl.kt
index 198a2c2a3ce4..fa47fb1b29ec 100644
--- a/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/ProjectIndexingHistoryImpl.kt
+++ b/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/ProjectIndexingHistoryImpl.kt
@@ -19,7 +19,7 @@ import kotlin.reflect.KMutableProperty1
@ApiStatus.Internal
data class ProjectIndexingHistoryImpl(override val project: Project,
override val indexingReason: String?,
- private val wasFullIndexing: Boolean) : ProjectIndexingHistory {
+ private val scanningType: ScanningType) : ProjectIndexingHistory {
private companion object {
val indexingSessionIdSequencer = AtomicLong()
val log = thisLogger()
@@ -31,7 +31,7 @@ data class ProjectIndexingHistoryImpl(override val project: Project,
override val times: IndexingTimes by ::timesImpl
- private val timesImpl = IndexingTimesImpl(indexingReason = indexingReason, wasFullIndexing = wasFullIndexing,
+ private val timesImpl = IndexingTimesImpl(indexingReason = indexingReason, scanningType = scanningType,
updatingStart = ZonedDateTime.now(ZoneOffset.UTC), totalUpdatingTime = System.nanoTime())
override val scanningStatistics = arrayListOf<JsonScanningStatistics>()
@@ -324,7 +324,7 @@ data class ProjectIndexingHistoryImpl(override val project: Project,
data class IndexingTimesImpl(
override val indexingReason: String?,
- override val wasFullIndexing: Boolean,
+ override val scanningType: ScanningType,
override val updatingStart: ZonedDateTime,
override var totalUpdatingTime: TimeNano,
override var updatingEnd: ZonedDateTime = updatingStart,
diff --git a/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/dto/JsonConverter.kt b/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/dto/JsonConverter.kt
index 4b8fa5a6874f..f3d2684389ff 100644
--- a/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/dto/JsonConverter.kt
+++ b/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/dto/JsonConverter.kt
@@ -85,7 +85,7 @@ fun IndexingFileSetStatistics.IndexedFile.toJson() = JsonFileProviderIndexStatis
fun IndexingTimes.toJson() =
JsonProjectIndexingHistoryTimes(
indexingReason = indexingReason,
- wasFullIndexing = wasFullIndexing,
+ scanningType = scanningType,
totalUpdatingTime = JsonDuration(totalUpdatingTime),
indexingTime = JsonDuration(indexingDuration.toNanos()),
contentLoadingVisibleTime = JsonDuration(contentLoadingVisibleDuration.toNanos()),
diff --git a/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/dto/JsonProjectIndexingHistoryTimes.kt b/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/dto/JsonProjectIndexingHistoryTimes.kt
index b9e498f53150..d90b8ff2fc27 100644
--- a/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/dto/JsonProjectIndexingHistoryTimes.kt
+++ b/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/dto/JsonProjectIndexingHistoryTimes.kt
@@ -3,12 +3,13 @@ package com.intellij.util.indexing.diagnostic.dto
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
import com.fasterxml.jackson.annotation.JsonInclude
+import com.intellij.util.indexing.diagnostic.ScanningType
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
data class JsonProjectIndexingHistoryTimes(
val indexingReason: String? = null,
- val wasFullIndexing: Boolean = false,
+ val scanningType: ScanningType = ScanningType.FULL,
val totalUpdatingTime: JsonDuration = JsonDuration(),
val indexingTime: JsonDuration = JsonDuration(),
val contentLoadingVisibleTime: JsonDuration = JsonDuration(),
diff --git a/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/presentation/jsonToHtmlConverter.kt b/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/presentation/jsonToHtmlConverter.kt
index 9a23f69063e2..ceaec19987d4 100644
--- a/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/presentation/jsonToHtmlConverter.kt
+++ b/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/presentation/jsonToHtmlConverter.kt
@@ -14,6 +14,7 @@ import com.intellij.util.indexing.diagnostic.JsonSharedIndexDiagnosticEvent
import com.intellij.util.indexing.diagnostic.dto.*
import org.intellij.lang.annotations.Language
import org.jetbrains.annotations.Nls
+import java.util.*
fun createAggregateHtml(
projectName: String,
@@ -95,7 +96,7 @@ fun createAggregateHtml(
td(diagnostic.appInfo.productCode + "-" + diagnostic.appInfo.build)
//Indexing type section
- td(if (diagnostic.indexingTimes.wasFullIndexing) "Full" else "Partial")
+ td(diagnostic.indexingTimes.scanningType.name.lowercase(Locale.ENGLISH).replace('_', ' '))
}
}
}
@@ -378,7 +379,7 @@ fun JsonIndexDiagnostic.generateHtml(): String {
if (times.indexingReason != null) {
tr { td("Reason"); td(times.indexingReason) }
}
- tr { td("Full or partial"); td(if (times.wasFullIndexing) "full" else "partial") }
+ tr { td("Type"); td(times.scanningType.name.lowercase(Locale.ENGLISH).replace('_', ' ')) }
tr { td("Finished at"); td(times.updatingEnd.presentableLocalDateTime()) }
tr { td("Cancelled?"); td(times.wasInterrupted.toString()) }
tr { td("Suspended time"); td(times.totalSuspendedTime.presentableDuration()) }
diff --git a/platform/lang-impl/testSources/com/intellij/util/indexing/diagnostic/ProjectIndexingHistoryImplTest.kt b/platform/lang-impl/testSources/com/intellij/util/indexing/diagnostic/ProjectIndexingHistoryImplTest.kt
index 12327dea2ad7..0e9e7a373ee0 100644
--- a/platform/lang-impl/testSources/com/intellij/util/indexing/diagnostic/ProjectIndexingHistoryImplTest.kt
+++ b/platform/lang-impl/testSources/com/intellij/util/indexing/diagnostic/ProjectIndexingHistoryImplTest.kt
@@ -1,4 +1,4 @@
-// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
+// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.util.indexing.diagnostic
import com.intellij.openapi.command.impl.DummyProject
@@ -12,7 +12,7 @@ class ProjectIndexingHistoryImplTest {
@Test
fun `test observation missed the start of suspension (IDEA-281514)`() {
- val history = ProjectIndexingHistoryImpl(DummyProject.getInstance(), "test", true)
+ val history = ProjectIndexingHistoryImpl(DummyProject.getInstance(), "test", ScanningType.FULL)
val time = Instant.now()
history.stopSuspendingStages(time)
history.startStage(ProjectIndexingHistoryImpl.Stage.Indexing, time.plusNanos(1))
@@ -27,7 +27,7 @@ class ProjectIndexingHistoryImplTest {
@Test
fun `test there may be actions after suspension`() {
- val history = ProjectIndexingHistoryImpl(DummyProject.getInstance(), "test", true)
+ val history = ProjectIndexingHistoryImpl(DummyProject.getInstance(), "test", ScanningType.FULL)
val time = Instant.now()
history.startStage(ProjectIndexingHistoryImpl.Stage.Indexing, time)
history.suspendStages(time.plusNanos(1))
@@ -42,7 +42,7 @@ class ProjectIndexingHistoryImplTest {
@Test
fun `test there may be actions after suspension 2`() {
- val history = ProjectIndexingHistoryImpl(DummyProject.getInstance(), "test", true)
+ val history = ProjectIndexingHistoryImpl(DummyProject.getInstance(), "test", ScanningType.FULL)
val time = Instant.now()
history.startStage(ProjectIndexingHistoryImpl.Stage.Indexing, time)
history.suspendStages(time.plusNanos(1))
@@ -58,7 +58,7 @@ class ProjectIndexingHistoryImplTest {
@Test
fun `test there may be actions after suspension 3`() {
- val history = ProjectIndexingHistoryImpl(DummyProject.getInstance(), "test", true)
+ val history = ProjectIndexingHistoryImpl(DummyProject.getInstance(), "test", ScanningType.FULL)
val time = Instant.now()
history.suspendStages(time)
history.startStage(ProjectIndexingHistoryImpl.Stage.Indexing, time.plusNanos(1))
@@ -74,7 +74,7 @@ class ProjectIndexingHistoryImplTest {
@Test
fun `test there may be actions after suspension 4`() {
- val history = ProjectIndexingHistoryImpl(DummyProject.getInstance(), "test", true)
+ val history = ProjectIndexingHistoryImpl(DummyProject.getInstance(), "test", ScanningType.FULL)
val time = Instant.now()
history.startStage(ProjectIndexingHistoryImpl.Stage.Indexing, time)
history.stopSuspendingStages(time.plusNanos(1))
@@ -89,7 +89,7 @@ class ProjectIndexingHistoryImplTest {
@Test
fun `test there may be actions after suspension 5`() {
- val history = ProjectIndexingHistoryImpl(DummyProject.getInstance(), "test", true)
+ val history = ProjectIndexingHistoryImpl(DummyProject.getInstance(), "test", ScanningType.FULL)
val time = Instant.now()
history.startStage(ProjectIndexingHistoryImpl.Stage.Indexing, time.plusNanos(1))
history.stopSuspendingStages(time.plusNanos(2))
@@ -106,7 +106,7 @@ class ProjectIndexingHistoryImplTest {
@Test
fun `test basic workflow`() {
- val history = ProjectIndexingHistoryImpl(DummyProject.getInstance(), "test", true)
+ val history = ProjectIndexingHistoryImpl(DummyProject.getInstance(), "test", ScanningType.FULL)
val instant = Instant.now()
history.startStage(ProjectIndexingHistoryImpl.Stage.PushProperties, instant)
history.stopStage(ProjectIndexingHistoryImpl.Stage.PushProperties, instant.plusNanos(1))
@@ -122,7 +122,7 @@ class ProjectIndexingHistoryImplTest {
@Test
fun `test stage with suspension inside`() {
- val history = ProjectIndexingHistoryImpl(DummyProject.getInstance(), "test", true)
+ val history = ProjectIndexingHistoryImpl(DummyProject.getInstance(), "test", ScanningType.FULL)
val instant = Instant.now()
history.startStage(ProjectIndexingHistoryImpl.Stage.PushProperties, instant)
history.suspendStages(instant.plusNanos(1))
diff --git a/platform/lvcs-impl/src/com/intellij/history/core/Paths.java b/platform/lvcs-impl/src/com/intellij/history/core/Paths.java
index 61586d8a3614..310c65326a71 100644
--- a/platform/lvcs-impl/src/com/intellij/history/core/Paths.java
+++ b/platform/lvcs-impl/src/com/intellij/history/core/Paths.java
@@ -58,7 +58,7 @@ public final class Paths {
public static Iterable<String> split(String path) {
String root = FileUtil.extractRootPath(path);
if (root == null) return splitInner(path);
- if (root.length() + 1 == path.length() && path.endsWith(":///")) {
+ if (root.length() + 1 == path.length() && path.endsWith("/")) {
return Collections.singleton(root);
}
diff --git a/platform/platform-api/resources/messages/IdeBundle.properties b/platform/platform-api/resources/messages/IdeBundle.properties
index ada86e389600..ad1db6aa1710 100644
--- a/platform/platform-api/resources/messages/IdeBundle.properties
+++ b/platform/platform-api/resources/messages/IdeBundle.properties
@@ -83,7 +83,7 @@ group.settings.process.tab.close=When closing a tool window with a running proce
radio.process.close.terminate=Terminate process
radio.process.close.disconnect=Disconnect
radio.process.close.ask=Ask
-treenode.loading= loading…
+treenode.loading= loading\u2026
action.descriptor.action=Action: {0}
action.descriptor.typing=Typing: "{0}"
action.descriptor.keystroke=Keystroke: "{0}"
@@ -150,8 +150,8 @@ prompt.input.favorites.list.new.name=Rename Favorites list ''{0}'' to:
command.create.file.from.template=Create File From Template
error.parsing.file.template=Error parsing file template: {0}
title.velocity.error=Velocity Error
-action.from.file.template=From File Template …
-action.edit.file.templates=Edit File Templates…
+action.from.file.template=From File Template \u2026
+action.edit.file.templates=Edit File Templates\u2026
error.unable.to.parse.template.message=Unable to parse template "{0}"\nError message: {1}
error.invalid.template.file.name.or.extension=Invalid template file name or extension
title.cannot.create.class=Cannot Create Class
@@ -334,7 +334,7 @@ prompt.enter.new.file.name=Specify a new file name:
title.new.file=New File
progress.creating.file=Creating file {0}{1}{2}
command.create.file=Create file
-action.delete.ellipsis=_Delete…
+action.delete.ellipsis=_Delete\u2026
action.delete=_Delete
title.file.already.exists=File Already Exists
title.error.writing.file=Error Writing File
@@ -412,7 +412,7 @@ progress.downloading.list.of.plugins=Downloading list of plugins from {0}
progress.downloading.plugins.meta=Downloading data for plugin {0}
progress.downloading.available.plugins=Downloading list of available plugins
progress.download.plugins=Downloading Plugins
-button.http.proxy.settings=&HTTP Proxy Settings…
+button.http.proxy.settings=&HTTP Proxy Settings\u2026
group.vendor=Vendor
plugin.status.installed=Installed
plugin.status.not.allowed=Blocked
@@ -431,8 +431,8 @@ action.move.module.outside.any.group=Outside Any Group
message.move.modules.to.group=Move {0} to the Group {1}
message.module=module ''{0}''
message.modules=modules
-action.move.module.new.top.level.group=New Top Level Group…
-action.move.module.to.new.sub.group=To New Subgroup…
+action.move.module.new.top.level.group=New Top Level Group\u2026
+action.move.module.to.new.sub.group=To New Subgroup\u2026
action.description.create.new.module.group=Create New Module Group
prompt.specify.name.of.module.subgroup=Specify name of {0} subgroup the {1} will be shown under.\n\n
title.module.sub.group=Module Subgroup
@@ -558,15 +558,15 @@ title.choose.action.icon=Choose Action Icon
action.choose.actions.to.add=Choose Actions To Add
button.set.icon=&Set icon
label.icon.path=&Icon:
-button.edit.action.icon=Edit &Icon…
-button.add.action=Add &Action…
+button.edit.action.icon=Edit &Icon\u2026
+button.add.action=Add &Action\u2026
button.add.separator=Add &Separator
title.customizations=Menus and Toolbars
-group.customizations.add.action.group=Add Actions…
-group.customizations.restore.action.group=Restore Actions…
+group.customizations.add.action.group=Add Actions\u2026
+group.customizations.restore.action.group=Restore Actions\u2026
action.customizations.customize.action=Customize Toolbar...
label.choosebyname.no.matches.found=No matches found
-label.choosebyname.searching=Searching…
+label.choosebyname.searching=Searching\u2026
prompt.gotoclass.enter.class.name=Enter {0} name:
label.no.matches.found=No matches found
prompt.gotofile.enter.file.name=Enter file name:
@@ -613,9 +613,9 @@ scope.selected.files=Selected {0,choice,1#file|2#files}
scope.selected.directories=Selected {0,choice,1#directory|2#directories}
scope.selected.files.and.directories=Selected {0,choice,1#file|2#files} \\& {1,choice,1#directory|2#directories}
scope.class.hierarchy=Class Hierarchy
-progress.searching= searching…
+progress.searching= searching\u2026
title.tip.of.the.day=Tip of the Day
-action.open.tip=&Open…
+action.open.tip=&Open\u2026
action.previous.tip=&Previous Tip
action.next.tip=&Next Tip
error.unable.to.read.tip.of.the.day=<html><body>Unable to read Tip Of The Day ({0}). Make sure {1} is installed properly.</body></html>
@@ -644,7 +644,7 @@ checkbox.narrow.down.on.typing=&Narrow &&down on typing
node.default.package=<Default Package>
prompt.enter.a.new.package.name=Enter a new package name:
command.create.new.package=Create new package
-action.new.package=New Package…
+action.new.package=New Package\u2026
action.description.create.new.package=Create new package
tab.chooser.project=Project
tab.chooser.search.by.name=Search by Name
@@ -690,7 +690,7 @@ updates.paid.upgrade=You can evaluate the new version for {0} days, or buy it on
updates.fallback.build=You have a perpetual fallback license for the new version.
updates.interim.build=You can use the new version until your subscription expires on {0}.
updates.new.build.notification.title={0} {1} available
-updates.notification.update.action=Update…
+updates.notification.update.action=Update\u2026
updates.ready.message={0} is ready to <a href=\"update\">update</a>.
update.installed.notification.title=Plugin updates installed
updates.external.progress=Fetching available updates for external components
@@ -700,7 +700,7 @@ updates.plugin.ready.tooltip={0} {1,choice,1#plugin|2#plugins} {1,choice,1#updat
updates.plugin.ready.title={0} plugin update available
updates.plugins.ready.title=Plugin updates available
updates.all.plugins.action={0,choice,1#Update|2#Update all}
-updates.plugins.dialog.action=Details…
+updates.plugins.dialog.action=Details\u2026
updates.no.updates.notification=No IDE or plugin updates available
updates.no.updates.message=You already have the latest version of {0} and plugins installed.
updates.no.updates.toolbox.message=<html>All plugins are up to date.<br> \
@@ -714,7 +714,7 @@ updates.no.updates.unknown.message=<html>All plugins are up to date.<br> \
updates.plugins.ready.header=<html><b>Plugins from configured hosts are ready to update.</b><br> \
Check plugins you want to update.</html>
updates.configure.label=<b><a href=\"updates\">Configure</a></b> automatic updates.
-updates.configure.updates.label=Configure updates…
+updates.configure.updates.label=Configure updates\u2026
updates.incompatible.plugins.found={0,choice,1#Plugin|2#Plugins} incompatible with the new build found:{0,choice,1#' '|2#'<br/>'} {1}
updates.download.and.restart.button=Up&date and Restart
updates.apply.manually.button=Up&date Manually
@@ -729,7 +729,7 @@ updates.from.to.size=Updating {0} to {1} ({2}). Patch size is {3} MB.
updates.write.protected={0} does not have write access to {1}. Please run it by a privileged user to update.
updates.settings.title=Updates
updates.last.check.never=Never
-updates.settings.check.now.button=&Check for Updates…
+updates.settings.check.now.button=&Check for Updates\u2026
updates.settings.checkbox=Check for IDE updates
updates.settings.checkbox.for=Check IDE updates for:
updates.plugins.settings.checkbox=Check for plugin updates
@@ -739,7 +739,7 @@ updates.settings.channel.locked=EAP builds can only be updated from the EAP chan
updates.settings.last.check=Last checked: {0}
updates.settings.current.version=Current version:
updates.settings.build.number=Build number:
-updates.settings.ignored=Manage ignored updates…
+updates.settings.ignored=Manage ignored updates\u2026
updates.settings.ignored.title=Ignored Updates
updates.settings.recommend.toolbox=We recommend the <a href=''{0}''>{1}</a>
updates.settings.recommend.toolbox.multiline.description=Get updates automatically, open your projects with one click,\n\
@@ -794,14 +794,14 @@ plugin.manager.optional.dependencies.detected.title=Install Suggested Plugins
plugin.manager.optional.dependencies.detected.message=It is suggested to install {1} with the ''{0}'' plugin.
plugin.manager.obsolete.plugins.detected.title=Disable Conflicting Plugin
plugin.manager.replace.plugin.0.by.plugin.1=<html>The ''{1}'' plugin is designed as a replacement for the installed ''{0}'' plugin.<br>\
- Disable the “{0}” plugin to avoid conflicts?</html>
+ Disable the \u201C{0}\u201D plugin to avoid conflicts?</html>
error.message.unable.to.create.file=Unable to create file ''{0}''
button.facet.quickfix.text=&Fix
-button.fix=Fix…
+button.fix=Fix\u2026
file.chooser.show.path=Show path
file.chooser.hide.path=Hide path
file.chooser.hide.path.tooltip.text=Show/Hide path text field
@@ -872,7 +872,7 @@ implicit.log.directory.path=It seems you''re using ''idea.system.path'' property
bundled.jre.version.message=Please consider switching to the bundled Java runtime \
that is better suited for the IDE (your current Java runtime is {0} by {1} at ''{2}'').
bundled.jre.m1.arch.message=Download {0} for Apple Silicon for better performance and stability.
-bundled.jre.m1.arch.message.download=Download…
+bundled.jre.m1.arch.message.download=Download\u2026
action.SwitchToJBR.text=Switch to bundled runtime
cannot.delete.jre.config=Cannot delete JRE configuration file ''{0}'': {1}
@@ -886,7 +886,7 @@ sys.health.acknowledge.action=Don't show again
low.disk.space.message=Low disk space on a {0} system directory partition
prompt.goto.inspection.enter.name=Enter inspection name:
-goto.inspection.action.text=&Run Inspection by Name…
+goto.inspection.action.text=&Run Inspection by Name\u2026
goto.inspection.action.choose.inherit.settings.from=Inspection Options
goto.inspection.action.dialog.title=Run ''{0}''
goto.inspection.action.fix.all=Fix All
@@ -901,12 +901,12 @@ whats.new.timeout.title=Couldn't load page
whats.new.timeout.message=The content for this page cannot be loaded. Please check your internet connection.
whats.new.timeout.action=You can <a href="{0}" class="link" target="_blank">open this page in browser</a> or try again later.
# 0 - IDE name (e.g. "IntelliJ IDEA"), 1 - IDE version (e.g. "2020.3")
-whats.new.notification.text={0} {1} est arrivée!
+whats.new.notification.text={0} {1} est arriv\u00E9e!
whats.new.notification.action=See what's new
diff.dialog.title=Diff Between ''{0}'' and ''{1}''
-goto.custom.region.menu.item=Custom Folding…
+goto.custom.region.menu.item=Custom Folding\u2026
goto.custom.region.command=Go to Custom Folding
goto.custom.region.message.dumb.mode=Custom folding navigation is not available until indexes are built.
goto.custom.region.message.unavailable=There are no custom foldings in the current file.
@@ -1013,7 +1013,7 @@ run.anything.action.tooltip.text=Execute commands: open projects, launch run con
double.ctrl.or.shift.shortcut=Double {0}
run.anything.hint.initial.text=Press {0} or {1} to navigate through the suggestion list
run.anything.indexing.mode.not.supported=Run anything is not available while indexes are updating
-run.anything.context.browse.directory=Browse Directory…
+run.anything.context.browse.directory=Browse Directory\u2026
run.anything.context.project=Project
run.anything.context.project.undefined=undefined
run.anything.context.title.working.directory=Execution Context
@@ -1117,7 +1117,7 @@ dnd.with.alt.pressed.only=Drag-and-drop with Alt pressed only
checkbox.full.paths.in.window.header=Always show full path in window header
overridden.by.jvm.property=Overridden by JVM property ''{0}''
option.is.overridden.by.jvm.property=The option is overridden by the JVM property: "{0}"
-background.image.button=Background Image…
+background.image.button=Background Image\u2026
display.balloon.notifications=Display balloon notifications
small.labels.in.editor.tabs=Small labels in editor tabs
show.hidden.tabs=Show Hidden Tabs
@@ -1174,11 +1174,11 @@ file.encoding.option.warning.windows.only=<html> {0} will add <a>UTF-8 BOM</a> t
plugin.manager.tab.marketplace=Marketplace
plugin.manager.tab.installed=Installed
plugin.manager.options.command=Type / to see options
-plugin.manager.repositories=Manage Plugin Repositories…
+plugin.manager.repositories=Manage Plugin Repositories\u2026
plugin.manager.custom.certificates=Manage Plugin Certificates
plugin.manager.update.all=Update all
plugin.manager.tooltip=Manage Repositories, Configure Proxy or Install Plugin from Disk
-plugin.settings.link.title=Plugin Settings…
+plugin.settings.link.title=Plugin Settings\u2026
settings.required.plugins.title=Specify a list of plugins required for your project. {0} will notify you if a required plugin is missing or needs an update.
settings.certificate.accept.non.trusted.certificates.automatically=Accept non-trusted certificates &automatically
settings.certificate.no.certificate.selected=No certificate selected
@@ -1221,7 +1221,7 @@ settings.file.colors.dialog.warning.replace=<html>Do you want to update \
settings.file.colors.enable.file.colors=Enable &file colors
settings.file.colors.use.in.editor.tabs=Use in editor &tabs
settings.file.colors.use.in.project.view=Use in &project view
-settings.file.colors.manage.scopes=&Manage scopes…
+settings.file.colors.manage.scopes=&Manage scopes\u2026
settings.file.colors.description=<html>\
Files can belong to several scopes. If there are two colors for one scope, the color of the first scope in the list is used.
@@ -1251,11 +1251,11 @@ action.Anonymous.text.reset.shortcuts=Reset Shortcuts
action.Anonymous.text.delete.hook=Delete Hook
action.Anonymous.text.live.templates=Live Templates
action.Anonymous.text.live.template=Live Template
-action.Anonymous.text.template.group=Template Group…
+action.Anonymous.text.template.group=Template Group\u2026
action.Anonymous.text.rename=Rename
-action.Anonymous.text.new.group=New group…
-action.Anonymous.text.change.context=Change context…
-action.Anonymous.text.edit.scopes.order=Edit Scopes Order…
+action.Anonymous.text.new.group=New group\u2026
+action.Anonymous.text.change.context=Change context\u2026
+action.Anonymous.text.edit.scopes.order=Edit Scopes Order\u2026
action.Anonymous.text.done=Done
action.Anonymous.text.remove.leading.directory=Remove Leading Directory
action.Anonymous.text.restore.leading.directory=Restore Leading Directory
@@ -1335,9 +1335,9 @@ action.AnAction.description.run.on.frame.activation=Run On Frame Activation
action.AnAction.text.search.history=Search History
action.AnAction.description.search.history=Search History
action.add.to.new.favorites.list.description=Add To New Favorites List
-action.DataSharingOptionsAction.text=Data Sharing Options…
+action.DataSharingOptionsAction.text=Data Sharing Options\u2026
action.DataSharingOptionsAction.description=Data Sharing Options
-action.InstallFromDiskAction.text=Install Plugin from Disk…
+action.InstallFromDiskAction.text=Install Plugin from Disk\u2026
action.InstallFromDiskAction.not.allowed.description=Installing plugins from disk is not allowed for your organization
failed.to.unload.modified.plugins=Failed to unload modified plugins: {0}
plugins.reloaded.successfully={0} reloaded successfully
@@ -1438,18 +1438,18 @@ label.category.unknown=UNKNOWN
chooser.description.jar.and.zip.archives.are.accepted=JAR and ZIP archives are accepted
chooser.title.plugin.file=Choose Plugin File
dialog.title.install.plugin=Install Plugin
-progress.title.installing.plugin=Installing plugin "{0}"…
+progress.title.installing.plugin=Installing plugin "{0}"\u2026
message.link.refresh=refresh
message.check.the.internet.connection.and=Check the internet connection and
-progress.text.downloading=Downloading…
-progress.text.loading=Loading…
+progress.text.downloading=Downloading\u2026
+progress.text.loading=Loading\u2026
label.install.a.limited.functionality.for.free=Install a version with limited functionality for free or
label.use.the.trial.for.up.to.30.days.or=Use the 30-day trial or
label.category.n.a=n/a
dialog.title.dependent.plugins.found=Dependent Plugins Found
button.enable.updated.plugins=Enable Updated {0,Choice,1#Plugin|2#Plugins}
button.enable.all=Enable All
-progress.title.checking.plugins.repository=Checking Plugins Repository…
+progress.title.checking.plugins.repository=Checking Plugins Repository\u2026
title.search.results=Search Results
empty.text.nothing.found=Nothing found
label.plugin.change.notes=Change Notes
@@ -1496,7 +1496,7 @@ plugins.configurable.buy.the.plugin=buy the plugin
action.presentation.AbstractSchemesPanel.text=Show Scheme Actions
action.presentation.EditorTabbedContainer.text=Close. Alt-Click to Close Others.
action.presentation.EncodingPanel.text=File Encoding
-action.presentation.ExtractIncludeAction.text=Include File…
+action.presentation.ExtractIncludeAction.text=Include File\u2026
action.presentation.LightEditTabs.text=Close. Alt-Click to Close Others.
action.presentation.OpenSelectedProjectsAction.text.open.all.projects.in.group=Open All Projects in Group
action.presentation.OpenSelectedProjectsAction.text.open.selected=Open Selected
@@ -1558,7 +1558,7 @@ action.text.hide.file.name=Hide File Name
rename.0=Rename {0}
dialog.title.select.0=Select {0}
quickfix.text.insert.0=Insert {0}
-progress.text.reopening.files=Reopening files…
+progress.text.reopening.files=Reopening files\u2026
button.reject=Reject
tooltip.text.update.is.in.progress.click.to.cancel=Update is in progress. Click to cancel
@@ -1627,7 +1627,7 @@ terminal.cursor.shape.vertical.name=Vertical
notification.title.desktop.entry.creation.failed=Desktop entry creation failed
notification.title.desktop.entry.created=Desktop entry created
-label.text.desktop.entry.can.be.created.later.in.tools.create.desktop.entry=Desktop entry can be created later in Tools | Create Desktop Entry…
+label.text.desktop.entry.can.be.created.later.in.tools.create.desktop.entry=Desktop entry can be created later in Tools | Create Desktop Entry\u2026
step.title.desktop.entry=Desktop Entry
button.installed=Installed
label.new.plugins.can.also.be.downloaded.in.0.plugins=New plugins can also be downloaded in {0} | Plugins
@@ -1689,7 +1689,7 @@ dialog.title.invalid.input=Invalid Input
popup.title.import.scheme=Import Scheme
dialog.title.import=Import
message.there.are.no.available.schemes.to.import=There are no available schemes to import
-label.macro.recording.started=Macro recording started…
+label.macro.recording.started=Macro recording started\u2026
tooltip.macro.is.being.recorded.now=Macro is being recorded now
dialog.title.required.plugin=Required Plugin
@@ -1698,7 +1698,7 @@ label.minimum.version=Minimum version:
label.plugin=Plugin:
label.version.any=<any>
-link.more=More…
+link.more=More\u2026
message.the.path.0.does.not.exist.maybe.on.remote=The path {0} does not exist.\n\
If it is on a removable or network drive, please make sure that the drive is connected.
@@ -1728,7 +1728,7 @@ message.this.functionality.is.not.available.during.indexing=This functionality i
progress.title.constructing.tooltip=Constructing tooltip
wrong.number.of.arguments.usage.ide.executable.save=Wrong number of arguments. Usage: <ide executable> save
wrong.number.of.arguments.usage.ide.executable.exit=Wrong number of arguments. Usage: <ide executable> exit [--restart]
-menu.item.loading=loading…
+menu.item.loading=loading\u2026
command.finish=finish
dialog.title.add.actions.to.quick.list=Add Actions to Quick List
this.file.does.not.belong.to.the.project={0, choice, 1#This file does|2#These files do} not belong to the project:
@@ -1757,7 +1757,7 @@ large.file.editor.name=Large File Editor
large.file.preview.notification=The file is too large ({0}). Showing a read-only preview of the first {1}.
dialog.message.could.not.erase.files.or.folders.0.1=Could not erase files or folders:\n{0}{1}
command.deleting.files=Deleting Files
-progress.title.deleting.files=Deleting Files…
+progress.title.deleting.files=Deleting Files\u2026
dialog.title.choose.plugins.to.install.or.enable=Choose Plugins to Install or Enable
action.text.merge.tabs.to.group=Merge Tabs to ''{0}'' Group
action.text.split.group=Split ''{0}'' Group
@@ -1773,15 +1773,15 @@ notification.group.project.settings=Could not save project
action.text.copy=&Copy
dialog.title.collect.troubleshooting.information=Collect Troubleshooting Information
link.reset.icon=Reset
-link.change.icon=Change…
+link.change.icon=Change\u2026
dialog.title.can.t.create.0.sdk=Cannot Create {0} SDK
label.continue.editing=Continue editing
button.continue.editing=Continue Editing
button.save.anyway=Save Anyway
change.encoding.command.name=Change Encoding for ''{0}''
-progress.text.reloading.file=Reloading file…
+progress.text.reloading.file=Reloading file\u2026
progress.title.reload.files=Reload files
-progress.text.reloading.files=Reloading files…
+progress.text.reloading.files=Reloading files\u2026
action.text.more=More
dialog.title.change.group.name=Change Group Name
label.enter.group.name=Enter group name:
@@ -1847,7 +1847,7 @@ notification.group.password.safe=Password storage not available
action.text.install.keymap=Install {0} Keymap
action.text.search.for.keymap=Search for {0} Keymap plugin
action.separator.file.templates=File templates
-startup.indicator.text.running.startup.activities=Running startup activities…
+startup.indicator.text.running.startup.activities=Running startup activities\u2026
notification.configurable.display.name.notifications=Notifications
dumb.balloon.this.action=This action
dumb.balloon.none.of.the.following.actions=None of the following actions
@@ -1859,7 +1859,7 @@ checkbox.use.custom.user.data.directory.for.chrome=&Use custom user data directo
label.ssl.certificate.details=Certificate details
dialog.title.http.proxy.exceptions=Proxy exceptions
border.title.problem.files=Problem files
-link.change.project.icon=Choose SVG file…
+link.change.project.icon=Choose SVG file\u2026
link.change.project.icon.description=The SVG file will be saved to the .idea folder.<br/>To share the project icon, add it to the repository.
label.project.icon.for.darcula.theme=Dark theme:
label.project.icon.for.default.theme=Light theme:
@@ -1972,7 +1972,7 @@ welcome.screen.learnIde.help.and.resources.text=Help and Resources
welcome.screen.color.theme.header=Color theme
welcome.screen.ide.font.size.label=IDE font:
welcome.screen.editor.font.size.label=Editor font:
-welcome.screen.all.settings.link=All settings…
+welcome.screen.all.settings.link=All settings\u2026
# End of the sentence that is started by link.check hyperlink
welcome.screen.check.for.updates.comment=\ for updates now.
welcome.screen.logo.version.label=Version {0}
@@ -1992,8 +1992,8 @@ dialog.title.proxy.authentication=Proxy Authentication: {0}
dialog.message.please.enter.credentials.for=Please enter credentials for: {0}
dialog.title.untrusted.server.s.certificate=Untrusted Server's Certificate
text.server.s.certificate.trusted=Server's certificate is not trusted
-action.DescriptionAwareSchemeActions.add.description.text=Add Description…
-action.DescriptionAwareSchemeActions.edit.description.text=Edit Description…
+action.DescriptionAwareSchemeActions.add.description.text=Add Description\u2026
+action.DescriptionAwareSchemeActions.edit.description.text=Edit Description\u2026
button.fix.it=Fix it
popup.title.recent.projects=Recent Projects
dialog.title.reopen.project=Reopen Project
@@ -2314,7 +2314,7 @@ notification.action.unknown.macros.error.fix=Fix it
dialog.title.configuration.changed=Configuration Changed
dialog.message.component.could.not.be.reloaded=The component cannot be reloaded. Reload project?
dialog.title.migrating.plugins=Migrating Plugins
-progress.text.migrating.plugins=Migrating plugins…
+progress.text.migrating.plugins=Migrating plugins\u2026
dialog.message.unknown.error=Unknown error
http.velocity={0}<hr> <font face="verdana" size="-1">\
<a href=''http://velocity.apache.org/engine/devel/user-guide.html#Velocity_Template_Language_VTL:_An_Introduction''>\nApache Velocity</a> \
@@ -2347,9 +2347,9 @@ required.plugin.between.versions=, version between ''{0}'' and ''{1}''
required.plugin.at.least.versions=, version at least ''{0}''
required.plugin.at.most.versions=, version at most ''{0}''
window.title.switcher=Switcher
-progress.title.cds.optimize.startup=Optimizing startup performance…
-progress.text.collecting.classes=Collecting classes list…
-progress.text.generate.classes.archive=Generating classes archive…
+progress.title.cds.optimize.startup=Optimizing startup performance\u2026
+progress.text.collecting.classes=Collecting classes list\u2026
+progress.text.generate.classes.archive=Generating classes archive\u2026
only.at.line.start=\\&Only at line start
dialog.message.internal.error=Internal error
label.recommended.only.if.you.are.br.familiar.with.vim=Recommended only if you are<br> familiar with Vim.
@@ -2357,7 +2357,7 @@ label.from.your.jetbrains.account=From your JetBrains account
label.text.plugin.dependencies=With {0, choice, 1#dependency|2#dependencies}: {1}
label.no.description.available=No description available
label.plugin.descriptor.category.unknown=Unknown
-link.label.wizard.step.plugin.customize=Customize…
+link.label.wizard.step.plugin.customize=Customize\u2026
link.label.choice.disable.enable.choice.all={0, choice, 0#Disable|1#Enable}{1, choice, 0# All|1#}
colorpicker.label.red=R:
@@ -2380,7 +2380,7 @@ colorpanel.label.alpha.percent=A%
colorpanel.label.red=R
colorpanel.label.green=G
colorpanel.label.blue=B
-colorpanel.label.hue=H°
+colorpanel.label.hue=H\u00B0
colorpanel.label.saturation=S%
colorpanel.label.brightness=B%
@@ -2392,7 +2392,7 @@ no.charset.set.reason.charset.auto.detected.from.content=charset is auto-detecte
no.charset.set.reason.disabled.for.file.type=disabled for {0}
checkbox.widescreen.tool.window.layout.description=Maximize the height of vertical tool windows by limiting the width of horizontal tool windows
error.tree.view.cell.error=Error: {0}
-error.tree.view.fixing=fixing…
+error.tree.view.fixing=fixing\u2026
error.tree.view.fix.description=Fix: {0}
gdpr.exit.button=Exit
gdpr.continue.button=Continue
@@ -2456,25 +2456,25 @@ wsl.target.introspection.step.completed.successfully=Introspection completed suc
wsl.target.introspection.step.completed.with.errors=Introspection completed with errors.
wsl.target.language.step.description={0} runtime configuration for {1}
wsl.target.tool.step.description=WSL configuration
-wsl.opening_wsl=Opening WSL…
+wsl.opening_wsl=Opening WSL\u2026
wsl.no_path=Cannot find the Windows-specific part of this distribution, cannot browse it
wsl.executing.process=Executing WSL Process
name.variable=File name entered in the dialog
-action.plugins.text=Plugins…
+action.plugins.text=Plugins\u2026
settings.entry.point.tooltip=IDE and Project Settings
settings.entry.point.with.updates.tooltip=Updates available. IDE and Project Settings
settings.entry.point.widget.name=IDE and Project Settings
settings.entry.point.update.ide.action=Download {0} {1}
-settings.entry.point.update.plugin.action=Update {0} Plugin…
-settings.entry.point.update.plugins.action=Update {0} Plugins…
+settings.entry.point.update.plugin.action=Update {0} Plugin\u2026
+settings.entry.point.update.plugins.action=Update {0} Plugins\u2026
template.file.name=Template to generate file name and path
template.file.name.optional=Template to generate file name and path (optional)
updates.settings.show.editor=Show What's New in the editor after an IDE update
plugin.version.bundled=bundled
-laf.action.install.theme=Install Theme…
-keymap.action.configure.keymap=Configure Keymap…
-keymap.action.install.keymap=Install Keymap…
+laf.action.install.theme=Install Theme\u2026
+keymap.action.configure.keymap=Configure Keymap\u2026
+keymap.action.install.keymap=Install Keymap\u2026
settings.entry.point.got.it.popup=Quickly access the main IDE and project settings, and execute commands.
dialog.title.custom.debug.log.configuration=Custom Debug Log Configuration
web.preview.file.editor.name=Preview for {0}
@@ -2488,7 +2488,7 @@ command.name.choice.exclude.include={0, choice, 0#Exclude|1#Include} {1}
detach.directory.dialog.message.detach.0=Detach {0}?\nNo files will be removed on disk.
detach.directory.dialog.title.detach=Detach Directories from Project
detach.directory.dialog.button.detach=Detach
-detach.directory.action.text.detach.0=Detach {0,choice,1#Directory|2#Directories} from Project…
+detach.directory.action.text.detach.0=Detach {0,choice,1#Directory|2#Directories} from Project\u2026
attachable.project.pane.name=Files
label.empty.text.attach.directories.with.right.click=Attach directories with right click
label.text.html.center.drop.here.to.attach.br.as.a.root.directory.center.html=<html><center>Drop here to attach<br/>as a root directory</center></html>
@@ -2526,11 +2526,11 @@ untrusted.project.open.dialog.title=Trust and Open Project ''{0}''?
# {0} stands for the IDE name, e.g. "IntelliJ IDEA"
untrusted.project.open.dialog.text=\
{0} provides features that may execute potentially malicious code from this folder.\n\n\
- If you don’t trust the source, preview the project in the safe mode to only browse its code.
+ If you don\u2019t trust the source, preview the project in the safe mode to only browse its code.
# Editor notification banner when the project is opened in the safe mode
untrusted.project.notification.description=Safe mode, limited functionality. Trust the project to access full IDE functionality.
-untrusted.project.notification.trust.link=Trust project…
+untrusted.project.notification.trust.link=Trust project\u2026
untrusted.project.notification.read.more.link=Read more
# Trust Project modal confirmation when opening an existing project, or when clicking to "Trust Project" link in the editor banner
@@ -2538,7 +2538,7 @@ untrusted.project.dialog.distrust.button=Stay in Safe Mode
untrusted.project.dialog.title=Trust {0} {1,choice,1#Project|1<Projects}?
untrusted.project.general.dialog.title=Trust Project?
untrusted.project.dialog.text=\
- If you don’t trust the source, stay in the safe mode.\n\n\
+ If you don\u2019t trust the source, stay in the safe mode.\n\n\
Loading, running, or building a {0} {1,choice,1#project|1<projects} may execute potentially malicious code from its build scripts.
# {0} stands for something like github.com/JetBrains
@@ -2557,9 +2557,9 @@ trusted.hosts.settings.new.trusted.folder.file.chooser.title=Select Trusted Loca
# 'Actions on Save' page in Settings (Preferences)
actions.on.save.page.title=Actions on Save
-actions.on.save.link.configure.autosave.options=Configure autosave options…
-actions.on.save.link.configure=Configure…
-actions.on.save.link.all.actions.on.save=All actions on save…
+actions.on.save.link.configure.autosave.options=Configure autosave options\u2026
+actions.on.save.link.configure=Configure\u2026
+actions.on.save.link.all.actions.on.save=All actions on save\u2026
actions.on.save.table.column.name.action=Action
actions.on.save.table.column.name.activated.on=Activated On
# This is a label in the 'Activated On' column. Should be short.
@@ -2582,7 +2582,7 @@ toolbox.updates.download.update.action.text=Download {2} {1} ({0})
toolbox.updates.download.update.action.description=Toolbox App will download {2} {1} ({0}) and let you \
know when the update is ready to switch
-toolbox.updates.download.ready.action.text=Switch to {2} {1} ({0})…
+toolbox.updates.download.ready.action.text=Switch to {2} {1} ({0})\u2026
toolbox.updates.download.ready.action.description=Toolbox App has installed {2} {1} ({0}). Restart to the new version?
popup.title.open.project=Open Project
@@ -2591,7 +2591,7 @@ notification.title.input.method.disabler=Input methods disabler
notification.content.input.method.disabler=The IDE is running with enabled input methods that can cause freezes. \
Please consider to disable input methods if you don't really use them.
action.text.disable.input.methods=Disable input methods
-log.in.link.text=Log in…
+log.in.link.text=Log in\u2026
login.dialog.jb.login=Log in to JetBrains Account
login.dialog.separator.text=or log in with
@@ -2601,14 +2601,14 @@ login.dialog.simple.login=Log in to JetBrains Account
login.dialog.you.are.logged=You are logged in
login.dialog.subscribe.to.survey=Subscribe to {0} survey
login.dialog.start.using=Get Started
-login.dialog.waiting.for.login=Waiting for login in browser…
-login.dialog.waiting.for.login.short=Waiting for login…
+login.dialog.waiting.for.login=Waiting for login in browser\u2026
+login.dialog.waiting.for.login.short=Waiting for login\u2026
login.dialog.new.user.label=New user?
login.dialog.register.link=Create an account
login.dialog.troubles.link=Troubles?
login.dialog.eap.info.link=About EAP
login.dialog.title={0}
-login.dialog.log.out=Log Out…
+login.dialog.log.out=Log Out\u2026
login.dialog.empty.username=Logged in
login.dialog.trouble.default.message=Unable to complete authorization process.
login.dialog.trouble.no.link={0}<br> \
@@ -2617,16 +2617,16 @@ login.dialog.trouble.no.link={0}<br> \
login.dialog.trouble.with.redirect=Sign in to your account and copy IDE authorization token.<br/>If the browser does not open, <a href="{0}">copy the link</a> and open it manually.
login.dialog.trouble.unknown=<a href="{0}">Copy the link</a> and open it in browser to get IDE authorization token.
login.dialog.authorization.token.field=IDE authorization token
-login.dialog.back.link=← Back
+login.dialog.back.link=\u2190 Back
login.dialog.check.token=Check Token
login.dialog.wrong.token=Wrong authorization token
login.dialog.link.copied=Link copied
login.dialog.session.expired=Authorization session has expired. Please start it again
# {0} is a product name (e.g. "IntelliJ IDEA")
-old.dirs.action.progress=Looking for leftover IDE storage directories…
+old.dirs.action.progress=Looking for leftover IDE storage directories\u2026
old.dirs.notification.text=Leftover IDE storage directories found.
-old.dirs.notification.action=View and delete…
+old.dirs.notification.action=View and delete\u2026
old.dirs.not.found.notification.text=No leftover IDE storage directories were found.
old.dirs.dialog.title=Delete Leftover IDE Storage Directories
old.dirs.dialog.text=<html>\
@@ -2638,7 +2638,7 @@ old.dirs.column.name=Directory
old.dirs.column.updated=Last Used
old.dirs.column.size=Size
old.dirs.dialog.delete.button=Delete {0} {0,choice,0#Directories|1#Directory|2#Directories}
-old.dirs.delete.progress=Deleting directories…
+old.dirs.delete.progress=Deleting directories\u2026
old.dirs.delete.error=Cannot delete directories
plugin.group.editor=Editor
@@ -2679,8 +2679,8 @@ notifications.toolwindow.suggestions=Suggestions
notifications.toolwindow.timeline=Timeline
notifications.toolwindow.timeline.clear.all=Clear all
notifications.toolwindow.remind.tomorrow=Remind me tomorrow
-notifications.toolwindow.dont.show.again.for.this.project=Don’t show again for this project
-notifications.toolwindow.dont.show.again=Don’t show again
+notifications.toolwindow.dont.show.again.for.this.project=Don\u2019t show again for this project
+notifications.toolwindow.dont.show.again=Don\u2019t show again
notifications.toolwindow.suggestion.gotit.title=Use suggestions below to optimize user\nexperience and improve performance
notifications.toolwindow.suggestion.gotit.link=Got it
notifications.collapse.balloon.title={0} more {1}
@@ -2728,3 +2728,8 @@ external.link.confirmation.title=Open Link
external.link.confirmation.message.0=Are you sure you want to open the link in a browser or in an associated application?<br><br>{0}
external.link.confirmation.yes.label=Open
external.link.confirmation.trust.label=Trust Project and Open
+
+jcef.local.cache.invalidate.action.description=Delete embedded browser engine cache and cookies. This action may affect components that use an embedded browser to render HTML-based content and web pages.
+jcef.local.cache.invalidate.checkbox.description=Delete embedded browser engine cache and cookies
+jcef.local.cache.invalidate.failed.title=Failed to clean up browser engine cache
+jcef.local.cache.invalidate.failed.message=The Invalidate Caches operation requested embedded browser engine cache cleanup. The operation failed due to I/O error: {0}
diff --git a/platform/platform-api/src/com/intellij/openapi/GitSilentFileAdder.java b/platform/platform-api/src/com/intellij/openapi/GitSilentFileAdder.java
index 3a01ec4979fe..3904e1e56282 100644
--- a/platform/platform-api/src/com/intellij/openapi/GitSilentFileAdder.java
+++ b/platform/platform-api/src/com/intellij/openapi/GitSilentFileAdder.java
@@ -9,14 +9,6 @@ import org.jetbrains.annotations.SystemIndependent;
import java.io.File;
import java.nio.file.Path;
-/**
- * To be used in async Project initialization tasks to add files silently,
- * preventing triggering of 'add new files to vcs' notifications/dialogs
- * by {@link com.intellij.openapi.vcs.VcsVFSListener}.
- *
- * @see GitRepositoryInitializer
- * @see com.intellij.openapi.vcs.VcsFileListenerContextHelper
- */
@ApiStatus.Internal
public interface GitSilentFileAdder {
/**
@@ -34,9 +26,9 @@ public interface GitSilentFileAdder {
void markFileForAdding(@NotNull Path path, boolean isDirectory);
/**
- * Notify that marked files can be added on pooled thread.
+ * Notify that marked files can be scheduled for addition to VCS.
* <p>
- * Should be called after explicit VFS refresh if files are added externally (ex: using NIO).
+ * Method should be called after an explicit synchronous VFS refresh if files are added externally (ex: using NIO, by an external command, etc).
*/
void finish();
diff --git a/platform/platform-api/src/com/intellij/openapi/GitSilentFileAdderProvider.java b/platform/platform-api/src/com/intellij/openapi/GitSilentFileAdderProvider.java
index 85fe0d3a4093..273cf59b7179 100644
--- a/platform/platform-api/src/com/intellij/openapi/GitSilentFileAdderProvider.java
+++ b/platform/platform-api/src/com/intellij/openapi/GitSilentFileAdderProvider.java
@@ -3,8 +3,18 @@ package com.intellij.openapi;
import com.intellij.openapi.extensions.ProjectExtensionPointName;
import com.intellij.openapi.project.Project;
+import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
+/**
+ * To be used in async Project initialization tasks to add files silently,
+ * preventing triggering of 'add new files to vcs' notifications/dialogs
+ * by {@link com.intellij.openapi.vcs.VcsVFSListener}.
+ *
+ * @see GitRepositoryInitializer
+ * @see com.intellij.openapi.vcs.VcsFileListenerContextHelper
+ */
+@ApiStatus.Internal
public interface GitSilentFileAdderProvider {
ProjectExtensionPointName<GitSilentFileAdderProvider> EP_NAME = new ProjectExtensionPointName<>("com.intellij.gitSilentFileAdder");
diff --git a/platform/platform-api/src/com/intellij/ui/jcef/JBCefApp.java b/platform/platform-api/src/com/intellij/ui/jcef/JBCefApp.java
index 71c1a27a2a27..3504b016bde5 100644
--- a/platform/platform-api/src/com/intellij/ui/jcef/JBCefApp.java
+++ b/platform/platform-api/src/com/intellij/ui/jcef/JBCefApp.java
@@ -13,6 +13,7 @@ import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.NotNullLazyValue;
@@ -30,6 +31,7 @@ import org.cef.CefSettings.LogSeverity;
import org.cef.callback.CefSchemeHandlerFactory;
import org.cef.callback.CefSchemeRegistrar;
import org.cef.handler.CefAppHandlerAdapter;
+import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -68,6 +70,8 @@ public final class JBCefApp {
@NotNull private final CefApp myCefApp;
+ @NotNull private final CefSettings myCefSettings;
+
@NotNull private final Disposable myDisposable = new Disposable() {
@Override
public void dispose() {
@@ -147,6 +151,8 @@ public final class JBCefApp {
settings.remote_debugging_port = port;
}
+ settings.cache_path = ApplicationManager.getApplication().getService(JBCefAppCache.class).getPath().toString();
+
String[] argsFromProviders = JBCefAppRequiredArgumentsProvider
.getProviders()
.stream()
@@ -194,6 +200,7 @@ public final class JBCefApp {
}
CefApp.addAppHandler(new MyCefAppHandler(args, trackGPUCrashes));
+ myCefSettings = settings;
myCefApp = CefApp.getInstance(settings);
Disposer.register(ApplicationManager.getApplication(), myDisposable);
}
@@ -356,6 +363,11 @@ public final class JBCefApp {
return getInstance() != null;
}
+ @Contract(pure = true)
+ @NotNull String getCachePath() {
+ return myCefSettings.cache_path;
+ }
+
@NotNull
public JBCefClient createClient() {
return createClient(false);
@@ -426,7 +438,7 @@ public final class JBCefApp {
private int myGPUCrashCounter = 0;
private boolean myNotificationShown = false;
- MyCefAppHandler(String @Nullable[] args, boolean trackGPUCrashes) {
+ MyCefAppHandler(String @Nullable [] args, boolean trackGPUCrashes) {
super(args);
myGPUCrashLimit = trackGPUCrashes ? Integer.getInteger("ide.browser.jcef.gpu.infinitecrash.internallimit", 10) : -1;
}
diff --git a/platform/platform-api/src/com/intellij/ui/jcef/JBCefAppCache.kt b/platform/platform-api/src/com/intellij/ui/jcef/JBCefAppCache.kt
new file mode 100644
index 000000000000..c9bddbb01f76
--- /dev/null
+++ b/platform/platform-api/src/com/intellij/ui/jcef/JBCefAppCache.kt
@@ -0,0 +1,61 @@
+// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+package com.intellij.ui.jcef
+
+import com.intellij.execution.Platform
+import com.intellij.ide.IdeBundle
+import com.intellij.notification.Notification
+import com.intellij.notification.NotificationType
+import com.intellij.notification.Notifications
+import com.intellij.openapi.application.PathManager
+import com.intellij.openapi.components.Service
+import com.intellij.openapi.diagnostic.thisLogger
+import com.intellij.openapi.util.io.FileUtil
+import org.jetbrains.annotations.NotNull
+import java.io.IOException
+import java.nio.file.Path
+import java.nio.file.Paths
+
+private const val invalidationMarkerFileName = "invalidation.marker"
+
+@Service
+class JBCefAppCache {
+ @get:NotNull
+ val path by lazy(LazyThreadSafetyMode.SYNCHRONIZED) {
+ prepareCachePath()
+ }
+
+ fun markInvalidated() {
+ FileUtil.createIfDoesntExist(path.resolve(invalidationMarkerFileName).toFile())
+ }
+
+ private fun prepareCachePath(): Path {
+ val fileSeparator = Platform.current().fileSeparator
+ val defaultCachePath = "${PathManager.getSystemPath()}${fileSeparator}jcef_cache${fileSeparator}"
+ val suggestedPath: Path = Paths.get(System.getProperty("ide.browser.jcef.cache.path", defaultCachePath))
+
+ val invalidationMarkerFilePath = suggestedPath.resolve(invalidationMarkerFileName)
+ val logger = thisLogger()
+
+ if (FileUtil.exists(invalidationMarkerFilePath.toString())) {
+ try {
+ FileUtil.delete(suggestedPath)
+ logger.info("Successfully deleted JCEF browser engine cache at \"$suggestedPath\"")
+ }
+ catch (exception: IOException) {
+ Notifications.Bus.notify(
+ Notification(
+ "IDE Caches",
+ IdeBundle.message("jcef.local.cache.invalidate.failed.title"),
+ IdeBundle.message("jcef.local.cache.invalidate.failed.message", exception.message),
+ NotificationType.ERROR
+ )
+ )
+
+ logger.error("Failed to cleanup JCEF browser engine cache due to I/O error", exception)
+ }
+ }
+
+ logger.debug("JCEF cache path: \"$suggestedPath\"")
+ return suggestedPath
+ }
+}
diff --git a/platform/platform-api/src/com/intellij/ui/jcef/JBCefAppCacheInvalidator.kt b/platform/platform-api/src/com/intellij/ui/jcef/JBCefAppCacheInvalidator.kt
new file mode 100644
index 000000000000..2e062e2c9d06
--- /dev/null
+++ b/platform/platform-api/src/com/intellij/ui/jcef/JBCefAppCacheInvalidator.kt
@@ -0,0 +1,19 @@
+// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+package com.intellij.ui.jcef
+
+import com.intellij.ide.IdeBundle
+import com.intellij.ide.caches.CachesInvalidator
+import com.intellij.openapi.application.ApplicationManager
+
+class JBCefAppCacheInvalidator : CachesInvalidator() {
+
+ override fun getComment(): String = IdeBundle.message("jcef.local.cache.invalidate.action.description")
+
+ override fun getDescription(): String = IdeBundle.message("jcef.local.cache.invalidate.checkbox.description")
+
+ override fun optionalCheckboxDefaultValue(): Boolean = false
+
+ override fun invalidateCaches() {
+ ApplicationManager.getApplication().getService(JBCefAppCache::class.java).markInvalidated()
+ }
+}
diff --git a/platform/platform-impl/src/com/intellij/application/options/editor/EditorTabsConfigurableEP.java b/platform/platform-impl/src/com/intellij/application/options/editor/EditorTabsConfigurableEP.java
index 629fa82e7788..9748b456bd59 100644
--- a/platform/platform-impl/src/com/intellij/application/options/editor/EditorTabsConfigurableEP.java
+++ b/platform/platform-impl/src/com/intellij/application/options/editor/EditorTabsConfigurableEP.java
@@ -7,17 +7,19 @@ import com.intellij.openapi.options.SearchableConfigurable;
import com.intellij.openapi.options.UnnamedConfigurable;
/**
- * To provide additional options in Editor | Editor Tabs section register implementation of
- * {@link UnnamedConfigurable} in the plugin.xml:
- * <p/>
- * &lt;extensions defaultExtensionNs="com.intellij"&gt;<br>
- * &nbsp;&nbsp;&lt;editorTabsConfigurable instance="class-name"/&gt;<br>
+ * Provides additional options in <em>Editor | General | Editor Tabs</em> settings.
+ * <p>
+ * Register implementation of {@link UnnamedConfigurable} in {@code plugin.xml}:
+ * <pre>
+ * &lt;extensions defaultExtensionNs="com.intellij"&gt;
+ * &lt;editorTabsConfigurable instance="class-name"/&gt;
* &lt;/extensions&gt;
+ * </pre>
+ * <p>
+ * A new instance of the specified class will be created each time when the Settings dialog is opened.
* <p>
- * A new instance of the specified class will be created each time then the Settings dialog is opened
- *
- * If you need to add a section of editor tabs options, your UnnamedConfigurable should implement
- * {@link EditorTabsOptionsCustomSection}
+ * If you need to add a section of editor tabs options, your {@code UnnamedConfigurable} should implement
+ * {@link EditorTabsOptionsCustomSection}.
*/
public final class EditorTabsConfigurableEP extends ConfigurableEP<SearchableConfigurable> {
static final ExtensionPointName<EditorTabsConfigurableEP> EP_NAME = new ExtensionPointName<>("com.intellij.editorTabsConfigurable");
diff --git a/platform/platform-impl/src/com/intellij/application/options/editor/EditorTabsOptionsCustomSection.java b/platform/platform-impl/src/com/intellij/application/options/editor/EditorTabsOptionsCustomSection.java
index 752800cb827d..1ae050d928e6 100644
--- a/platform/platform-impl/src/com/intellij/application/options/editor/EditorTabsOptionsCustomSection.java
+++ b/platform/platform-impl/src/com/intellij/application/options/editor/EditorTabsOptionsCustomSection.java
@@ -4,7 +4,9 @@ package com.intellij.application.options.editor;
import com.intellij.openapi.options.UnnamedConfigurable;
/**
- * A marker interface for custom editor tabs option sections
+ * A marker interface for custom editor tabs option sections.
+ *
+ * @see EditorTabsConfigurableEP
*/
public interface EditorTabsOptionsCustomSection extends UnnamedConfigurable {
}
diff --git a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionToolbarImpl.java b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionToolbarImpl.java
index 82f80162117e..d265bd404bb2 100644
--- a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionToolbarImpl.java
+++ b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionToolbarImpl.java
@@ -1344,6 +1344,7 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar, QuickAct
Dimension pSize = p.getSize();
if (myOrientation == SwingConstants.HORIZONTAL && pSize.height - availSize.height > 8 ||
myOrientation == SwingConstants.VERTICAL && pSize.width - availSize.width > 8) {
+ if (availSize.width == 0 && availSize.height == 0) result = p;
break;
}
result = p;
diff --git a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/PopupMenuPreloader.java b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/PopupMenuPreloader.java
index af3676b4ba6e..18c21d50307b 100644
--- a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/PopupMenuPreloader.java
+++ b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/PopupMenuPreloader.java
@@ -7,6 +7,7 @@ import com.intellij.openapi.actionSystem.ActionGroup;
import com.intellij.openapi.actionSystem.ActionPlaces;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.DataContext;
+import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.ex.util.EditorUtil;
import com.intellij.openapi.editor.impl.EditorComponentImpl;
@@ -49,6 +50,7 @@ public final class PopupMenuPreloader implements Runnable, HierarchyListener {
@NotNull String actionPlace,
@Nullable PopupHandler popupHandler,
@NotNull Supplier<? extends ActionGroup> groupSupplier) {
+ if (ApplicationManager.getApplication().isUnitTestMode()) return;
if (component instanceof EditorComponentImpl && ourEditorContextMenuPreloadCount > 4 ||
component instanceof IdeMenuBar && SwingUtilities.getWindowAncestor(component) instanceof IdeFrame.Child) {
return;
diff --git a/platform/platform-impl/src/com/intellij/openapi/command/impl/DefaultUndoReportHandler.java b/platform/platform-impl/src/com/intellij/openapi/command/impl/DefaultUndoReportHandler.java
index 235471be7ba2..ef24baa838b6 100644
--- a/platform/platform-impl/src/com/intellij/openapi/command/impl/DefaultUndoReportHandler.java
+++ b/platform/platform-impl/src/com/intellij/openapi/command/impl/DefaultUndoReportHandler.java
@@ -15,7 +15,7 @@ import org.jetbrains.annotations.Nullable;
import java.util.Collection;
-public class DefaultUndoReportHandler implements UndoReportHandler {
+class DefaultUndoReportHandler implements UndoReportHandler {
private static final Logger LOG = Logger.getInstance(DefaultUndoReportHandler.class);
@Override
diff --git a/platform/platform-impl/src/com/intellij/openapi/command/impl/UndoReportHandler.java b/platform/platform-impl/src/com/intellij/openapi/command/impl/UndoReportHandler.java
index d83808b4285c..f7bda96542be 100644
--- a/platform/platform-impl/src/com/intellij/openapi/command/impl/UndoReportHandler.java
+++ b/platform/platform-impl/src/com/intellij/openapi/command/impl/UndoReportHandler.java
@@ -6,11 +6,13 @@ import com.intellij.openapi.command.undo.UnexpectedUndoException;
import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.NlsContexts;
+import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
+@ApiStatus.Internal
public interface UndoReportHandler {
ExtensionPointName<UndoReportHandler> EP_NAME = ExtensionPointName.create("com.intellij.undoReportHandler");
diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/headertoolbar/MainToolbarAppWidgetFactory.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/headertoolbar/MainToolbarAppWidgetFactory.kt
index 64852ca5957b..ed0c07b742cd 100644
--- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/headertoolbar/MainToolbarAppWidgetFactory.kt
+++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/headertoolbar/MainToolbarAppWidgetFactory.kt
@@ -2,12 +2,23 @@
package com.intellij.openapi.wm.impl.headertoolbar
import com.intellij.openapi.extensions.ExtensionPointName
+import org.jetbrains.annotations.ApiStatus
import javax.swing.JComponent
+/**
+ * Factory for Application-level widgets placed in main toolbar.
+ *
+ * @see [MainToolbarWidgetFactory]
+ */
+@ApiStatus.Experimental
+@ApiStatus.Internal
interface MainToolbarAppWidgetFactory : MainToolbarWidgetFactory {
companion object {
val EP_NAME = ExtensionPointName<MainToolbarAppWidgetFactory>("com.intellij.appToolbarWidget")
}
+ /**
+ * Factory method to create widget
+ */
fun createWidget(): JComponent
} \ No newline at end of file
diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/headertoolbar/MainToolbarProjectWidgetFactory.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/headertoolbar/MainToolbarProjectWidgetFactory.kt
index 81533aeb2a2d..8b7ebe52561d 100644
--- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/headertoolbar/MainToolbarProjectWidgetFactory.kt
+++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/headertoolbar/MainToolbarProjectWidgetFactory.kt
@@ -2,11 +2,24 @@
package com.intellij.openapi.wm.impl.headertoolbar
import com.intellij.openapi.project.Project
+import org.jetbrains.annotations.ApiStatus
import javax.swing.JComponent
/**
- * Extension point: com.intellij.projectToolbarWidget
+ * Factory for Project-level widgets placed in main toolbar.
+ *
+ * Extension point: `com.intellij.projectToolbarWidget`
+ *
+ * @see [MainToolbarWidgetFactory]
*/
+@ApiStatus.Experimental
+@ApiStatus.Internal
interface MainToolbarProjectWidgetFactory : MainToolbarWidgetFactory {
+
+ /**
+ * Factory method to create widget
+ *
+ * @param project current project
+ */
fun createWidget(project: Project): JComponent
} \ No newline at end of file
diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/headertoolbar/MainToolbarWidgetFactory.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/headertoolbar/MainToolbarWidgetFactory.kt
index 70fada1da44b..0fb770a2412a 100644
--- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/headertoolbar/MainToolbarWidgetFactory.kt
+++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/headertoolbar/MainToolbarWidgetFactory.kt
@@ -1,10 +1,25 @@
// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.openapi.wm.impl.headertoolbar
+import org.jetbrains.annotations.ApiStatus
+
+/**
+ * Factory for widgets placed in main toolbar.
+ * This is root interface which is not supposed to be implemented. Please implement [MainToolbarProjectWidgetFactory] for
+ * Application level widgets or [MainToolbarProjectWidgetFactory] for Project level widgets
+ */
+@ApiStatus.Experimental
+@ApiStatus.Internal
interface MainToolbarWidgetFactory {
+ /**
+ * Defines part of toolbar (described in [Position]) when widget should be shown.
+ */
fun getPosition(): Position
+ /**
+ * List of allowed positions for toolbar widgets
+ */
enum class Position {
Left, Right, Center
}
diff --git a/platform/platform-impl/src/com/intellij/ui/GotItTooltip.kt b/platform/platform-impl/src/com/intellij/ui/GotItTooltip.kt
index ac62470efa38..267ca5743ac0 100644
--- a/platform/platform-impl/src/com/intellij/ui/GotItTooltip.kt
+++ b/platform/platform-impl/src/com/intellij/ui/GotItTooltip.kt
@@ -70,11 +70,13 @@ class GotItTooltipService {
}
/**
- * id is a unique id for the tooltip that will be used to store the tooltip state in <code>PropertiesComponent</code>
- * id has the following format: place.where.used - lowercase words separated with dots.
- * GotIt tooltip usage statistics can be properly gathered if its id prefix is registered in plugin.xml (PlatformExtensions.xml)
- * with gotItTooltipAllowlist extension point. Prefix can cover a whole class of different gotit tooltips.
- * If prefix is shorter than the whole ID then all different tooltip usages will be reported in one category described by the prefix.
+ * The `id` is a unique identifier for the tooltip that will be used to store the tooltip state in [PropertiesComponent].
+ * Identifier has the following format: `place.where.used` (lowercase words separated with dots).
+ *
+ * Got It tooltip usage statistics can be properly gathered if its identifier prefix is registered in
+ * `plugin.xml` (`PlatformExtensions.xml`) with `com.intellij.statistics.gotItTooltipAllowlist` extension point.
+ * Prefix can cover a whole class of different Got It tooltips. If the prefix is shorter than the whole ID, then all different
+ * tooltip usages will be reported in one category described by the prefix.
*/
class GotItTooltip(@NonNls val id: String,
@Nls val text: String,
@@ -127,7 +129,7 @@ class GotItTooltip(@NonNls val id: String,
}
/**
- * Add optional header to the tooltip.
+ * Add an optional header to the tooltip.
*/
fun withHeader(@Nls header: String): GotItTooltip {
this.header = header
@@ -135,7 +137,7 @@ class GotItTooltip(@NonNls val id: String,
}
/**
- * Set preferred tooltip position relatively to the owner component
+ * Set preferred tooltip position relatively to the owner component.
*/
fun withPosition(position: Balloon.Position): GotItTooltip {
this.position = position
@@ -167,7 +169,7 @@ class GotItTooltip(@NonNls val id: String,
}
/**
- * Set close timeout. If set then tooltip appears without "Got It" button.
+ * Set the close timeout. If set, then the tooltip appears without the "Got It" button.
*/
@JvmOverloads
fun withTimeout(timeout: Int = DEFAULT_TIMEOUT): GotItTooltip {
@@ -178,7 +180,7 @@ class GotItTooltip(@NonNls val id: String,
}
/**
- * Limit tooltip body width to the given value. By default it's limited to <code>MAX_WIDTH</code> pixels.
+ * Limit tooltip body width to the given value. By default, it's limited to `MAX_WIDTH` pixels.
*/
fun withMaxWidth(width: Int): GotItTooltip {
maxWidth = width
@@ -186,7 +188,7 @@ class GotItTooltip(@NonNls val id: String,
}
/**
- * Add optional link to the tooltip.
+ * Add an optional link to the tooltip.
*/
fun withLink(@Nls linkLabel: String, action: () -> Unit): GotItTooltip {
link = object : LinkLabel<Unit>(linkLabel, null) {
@@ -197,14 +199,14 @@ class GotItTooltip(@NonNls val id: String,
}
/**
- * Add optional link to the tooltip. Java version.
+ * Add an optional link to the tooltip. Java version.
*/
fun withLink(@Nls linkLabel: String, action: Runnable): GotItTooltip {
return withLink(linkLabel) { action.run() }
}
/**
- * Add optional browser link to the tooltip. Link is rendered with arrow icon.
+ * Add an optional browser link to the tooltip. Link is rendered with arrow icon.
*/
fun withBrowserLink(@Nls linkLabel: String, url: URL): GotItTooltip {
link = object : LinkLabel<Unit>(linkLabel, AllIcons.Ide.External_link_arrow) {
@@ -231,7 +233,7 @@ class GotItTooltip(@NonNls val id: String,
}
/**
- * Optionally show close shortcut next to Got It button
+ * Show close shortcut next to the "Got It" button.
*/
fun andShowCloseShortcut(): GotItTooltip {
showCloseShortcut = true
@@ -239,7 +241,7 @@ class GotItTooltip(@NonNls val id: String,
}
/**
- * Set notification method that's called when actual <code>Balloon</code> is created.
+ * Set the notification method that's called when actual [Balloon] is created.
*/
fun setOnBalloonCreated(callback: (Balloon) -> Unit): GotItTooltip {
onBalloonCreated = callback
@@ -247,20 +249,21 @@ class GotItTooltip(@NonNls val id: String,
}
/**
- * Returns <code>true</code> if this tooltip can be shown at the given properties settings.
+ * Returns `true` if this tooltip can be shown at the given properties settings.
*/
override fun canShow(): Boolean = showCondition("$PROPERTY_PREFIX.$id")
/**
* Show tooltip for the given component and point to the component.
- * If the component is showing (see <code>Component.isShowing</code>) and has not empty bounds then
- * the tooltip is shown right away.
- * If the component is showing but has empty bounds (technically not visible) then tooltip is shown asynchronously
- * when component gets resized to not empty bounds.
- * If the component is not showing then tooltip is shown asynchronously when component is added to the hierarchy and
- * gets not empty bounds.
*
- * not for actionButton
+ * If the component is showing (see [Component.isShowing]) and has not empty bounds,
+ * then the tooltip is shown right away.
+ *
+ * If the component is showing but has empty bounds (technically not visible),
+ * then tooltip is shown asynchronously when the component gets resized to not empty bounds.
+ *
+ * If the component is not showing, then tooltip is shown asynchronously when component is added to the hierarchy
+ * and gets not empty bounds.
*/
override fun show(component: JComponent, pointProvider: (Component, Balloon) -> Point) {
if (canShow()) {
diff --git a/platform/platform-impl/src/com/intellij/ui/Splash.java b/platform/platform-impl/src/com/intellij/ui/Splash.java
index 7f075826fb33..6d213b10e173 100644
--- a/platform/platform-impl/src/com/intellij/ui/Splash.java
+++ b/platform/platform-impl/src/com/intellij/ui/Splash.java
@@ -53,7 +53,7 @@ public final class Splash extends Dialog {
private final Image image;
public Splash(@NotNull ApplicationInfoEx info) {
- super((Frame)null);
+ super((Frame)null, "splash");
setUndecorated(true);
progressSlidePainter = info.getProgressSlides().isEmpty() ? null : new ProgressSlidePainter(info);
diff --git a/platform/platform-impl/src/com/intellij/ui/popup/list/ListPopupImpl.java b/platform/platform-impl/src/com/intellij/ui/popup/list/ListPopupImpl.java
index 2b6f6e2a7214..82d2b04ed355 100644
--- a/platform/platform-impl/src/com/intellij/ui/popup/list/ListPopupImpl.java
+++ b/platform/platform-impl/src/com/intellij/ui/popup/list/ListPopupImpl.java
@@ -611,7 +611,7 @@ public class ListPopupImpl extends WizardPopup implements ListPopup, NextStepHan
@Override
public void mouseReleased(MouseEvent e) {
- if (e.isConsumed() || !isActionClick(e) || isMultiSelectionEnabled() && UIUtil.isSelectionButtonDown(e)) return;
+ if (!isActionClick(e) || isMultiSelectionEnabled() && UIUtil.isSelectionButtonDown(e)) return;
IdeEventQueue.getInstance().blockNextEvents(e); // sometimes, after popup close, MOUSE_RELEASE event delivers to other components
Object selectedValue = myList.getSelectedValue();
ListPopupStep<Object> listStep = getListStep();
diff --git a/platform/platform-resources/src/META-INF/PlatformExtensions.xml b/platform/platform-resources/src/META-INF/PlatformExtensions.xml
index de8c36d4da28..0fbb8bf0b8f6 100644
--- a/platform/platform-resources/src/META-INF/PlatformExtensions.xml
+++ b/platform/platform-resources/src/META-INF/PlatformExtensions.xml
@@ -147,6 +147,7 @@
<applicationService serviceImplementation="com.intellij.ide.GeneralSettings" preload="notHeadless"/>
<applicationService serviceImplementation="com.intellij.ui.jcef.JBCefStartup" preload="true" os="mac"/>
+ <cachesInvalidator implementation="com.intellij.ui.jcef.JBCefAppCacheInvalidator" order="last" />
<applicationService serviceInterface="com.intellij.ide.ui.IdeUiService"
serviceImplementation="com.intellij.openapi.fileEditor.impl.IdeUiServiceImpl"/>
diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/project/DumbServiceImplTest.groovy b/platform/platform-tests/testSrc/com/intellij/openapi/project/DumbServiceImplTest.groovy
index f7a672bd966f..29304c37706f 100644
--- a/platform/platform-tests/testSrc/com/intellij/openapi/project/DumbServiceImplTest.groovy
+++ b/platform/platform-tests/testSrc/com/intellij/openapi/project/DumbServiceImplTest.groovy
@@ -1,4 +1,4 @@
-// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
+// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.openapi.project
import com.intellij.openapi.application.ApplicationManager
@@ -21,6 +21,7 @@ import com.intellij.util.indexing.FileBasedIndex
import com.intellij.util.indexing.FileBasedIndexImpl
import com.intellij.util.indexing.contentQueue.IndexUpdateRunner
import com.intellij.util.indexing.diagnostic.ProjectIndexingHistoryImpl
+import com.intellij.util.indexing.diagnostic.ScanningType
import com.intellij.util.ui.UIUtil
import org.jetbrains.annotations.NotNull
import org.junit.Assert
@@ -171,7 +172,7 @@ class DumbServiceImplTest extends BasePlatformTestCase {
def index = FileBasedIndex.getInstance() as FileBasedIndexImpl
new IndexUpdateRunner(index, ConcurrencyUtil.newSameThreadExecutorService(), 1)
.indexFiles(project, Collections.singletonList(new IndexUpdateRunner.FileSet(project, "child", [child])),
- indicator, new ProjectIndexingHistoryImpl(getProject(), "Testing", false))
+ indicator, new ProjectIndexingHistoryImpl(getProject(), "Testing", ScanningType.PARTIAL))
}
}
catch (ProcessCanceledException e) {
diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/vfs/impl/VirtualFilePointerTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/vfs/impl/VirtualFilePointerTest.java
index eed27521d73d..34f6d27e30d8 100644
--- a/platform/platform-tests/testSrc/com/intellij/openapi/vfs/impl/VirtualFilePointerTest.java
+++ b/platform/platform-tests/testSrc/com/intellij/openapi/vfs/impl/VirtualFilePointerTest.java
@@ -11,11 +11,13 @@ import com.intellij.openapi.application.WriteAction;
import com.intellij.openapi.application.ex.PathManagerEx;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Disposer;
+import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.io.FileAttributes;
import com.intellij.openapi.util.io.FileSystemUtil;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.io.IoTestUtil;
+import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.*;
import com.intellij.openapi.vfs.ex.temp.TempFileSystem;
import com.intellij.openapi.vfs.impl.jar.JarFileSystemImpl;
@@ -29,16 +31,14 @@ import com.intellij.openapi.vfs.pointers.VirtualFilePointerManager;
import com.intellij.testFramework.*;
import com.intellij.testFramework.fixtures.BareTestFixtureTestCase;
import com.intellij.testFramework.rules.TempDirectory;
-import com.intellij.util.ExceptionUtil;
-import com.intellij.util.IncorrectOperationException;
-import com.intellij.util.TestTimeOut;
-import com.intellij.util.TimeoutUtil;
+import com.intellij.util.*;
import com.intellij.util.concurrency.Semaphore;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.io.SuperUserStatus;
import com.intellij.util.messages.MessageBusConnection;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
@@ -50,6 +50,7 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.FileTime;
+import java.security.SecureRandom;
import java.time.Instant;
import java.util.*;
import java.util.concurrent.CountDownLatch;
@@ -213,11 +214,6 @@ public class VirtualFilePointerTest extends BareTestFixtureTestCase {
}
@Test
- public void testCreateVFPFromStrangeJarUrlMustCrash() throws IOException {
- UsefulTestCase.assertThrows(IllegalArgumentException.class, ()->myVirtualFilePointerManager.create("jar://C:/!/java.base", disposable, null));
- }
-
- @Test
public void testPointerForFileSystemRoot1() {
File rootDir = new File("/");
assertTrue(rootDir.exists());
@@ -1281,4 +1277,46 @@ public class VirtualFilePointerTest extends BareTestFixtureTestCase {
assertTrue(pointer.getUrl(), pointer.getUrl().endsWith(path));
assertEquals("allopen-compiler-plugin.jar", pointer.getFileName());
}
+ @Test
+ public void testJarUrlContainingInvalidExclamationInTheMiddleMustNotCrashAnything() {
+ File root = tempDir.getRoot();
+ while (root.getParentFile() != null) root = root.getParentFile();
+ String diskRoot = UriUtil.trimTrailingSlashes(FileUtil.toSystemIndependentName(root.getPath()));
+
+ assertJarSeparatorParsedCorrectlyForFileInsideJar("/", "!/", null, "_");
+ assertJarSeparatorParsedCorrectlyForFileInsideJar("!/", "!/", null, "_");
+ assertJarSeparatorParsedCorrectlyForFileInsideJar("!/xxx", "!/xxx", "xxx", "xxx");
+ assertJarSeparatorParsedCorrectlyForFileInsideJar("!/xxx/!/yyy", "!/xxx/!/yyy", "yyy", "xxx/!/yyy");
+ if (SystemInfo.isWindows) {
+ assertJarSeparatorParsedCorrectly("jar://" + diskRoot + "/!/abc", "jar://" + diskRoot + "!/abc", "abc");
+ assertJarSeparatorParsedCorrectly("jar://" + diskRoot + "!/abc", "jar://" + diskRoot + "!/abc", "abc");
+ }
+ }
+
+ private void assertJarSeparatorParsedCorrectlyForFileInsideJar(@NotNull String relativePathInsideJar, @NotNull String expectedPointerRelativeUrl, @Nullable String expectedPointerFileName, @NotNull String expectedPathInsideJar) {
+ String abc = "abc" + new SecureRandom().nextLong()+".jar";
+ String tempRoot = UriUtil.trimTrailingSlashes(FileUtil.toSystemIndependentName(tempDir.getRoot().getPath()));
+ VirtualFilePointer pointer = VirtualFilePointerManager.getInstance().create("jar://" + tempRoot + "/" + abc + relativePathInsideJar, disposable, null);
+ assertEquals(expectedPointerRelativeUrl, StringUtil.trimStart(pointer.getUrl(), "jar://" + tempRoot + "/" + abc));
+ String expectedPointerFileNameToCheck = expectedPointerFileName == null ? abc : expectedPointerFileName;
+ assertEquals(expectedPointerFileNameToCheck, pointer.getFileName());
+ assertEquals(JarFileSystem.getInstance(), ((VirtualFilePointerImpl)pointer).myNode.myFS);
+ assertFalse(pointer.isValid());
+
+ File jar = IoTestUtil.createTestJar(new File(tempRoot+"/"+abc), List.of(Pair.create(expectedPathInsideJar, new byte[]{' ', ' '})));
+ assertNotNull(LocalFileSystem.getInstance().refreshAndFindFileByIoFile(jar));
+
+ assertTrue(pointer.isValid());
+ VirtualFile virtualFile = pointer.getFile();
+ assertNotNull(virtualFile);
+ assertEquals(expectedPointerFileNameToCheck, virtualFile.getName());
+ }
+
+ private void assertJarSeparatorParsedCorrectly(@NotNull String sourceUrl, @NotNull String expectedPointerUrl, @NotNull String expectedPointerFileName) {
+ VirtualFilePointer pointer = VirtualFilePointerManager.getInstance().create(sourceUrl, disposable, null);
+ assertEquals(expectedPointerUrl, pointer.getUrl());
+ assertEquals(expectedPointerFileName, pointer.getFileName());
+ assertEquals(JarFileSystem.getInstance(), ((VirtualFilePointerImpl)pointer).myNode.myFS);
+ assertFalse(pointer.isValid());
+ }
} \ No newline at end of file
diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/vfs/local/FileWatcherTest.kt b/platform/platform-tests/testSrc/com/intellij/openapi/vfs/local/FileWatcherTest.kt
index 075026c81749..d8e5561a56b0 100644
--- a/platform/platform-tests/testSrc/com/intellij/openapi/vfs/local/FileWatcherTest.kt
+++ b/platform/platform-tests/testSrc/com/intellij/openapi/vfs/local/FileWatcherTest.kt
@@ -459,30 +459,30 @@ class FileWatcherTest : BareTestFixtureTestCase() {
val target = tempDir.newDirectory("top")
val file = tempDir.newFile("top/sub/test.txt")
- val substRoot = IoTestUtil.createSubst(target.path)
- VfsRootAccess.allowRootAccess(testRootDisposable, substRoot.path)
- val vfsRoot = fs.findFileByIoFile(substRoot)!!
- watchedPaths += substRoot.path
+ IoTestUtil.performTestOnWindowsSubst(target.path) { substRoot ->
+ VfsRootAccess.allowRootAccess(testRootDisposable, substRoot.path)
+ val vfsRoot = fs.findFileByIoFile(substRoot)!!
+ watchedPaths += substRoot.path
- val substFile = File(substRoot, "sub/test.txt")
- refresh(target)
- refresh(substRoot)
+ val substFile = File(substRoot, "sub/test.txt")
+ refresh(target)
+ refresh(substRoot)
- try {
- watch(substRoot)
- assertEvents({ file.writeText("new content") }, mapOf(substFile to 'U'))
+ try {
+ watch(substRoot)
+ assertEvents({ file.writeText("new content") }, mapOf(substFile to 'U'))
- val request = watch(target)
- assertEvents({ file.writeText("updated content") }, mapOf(file to 'U', substFile to 'U'))
- assertEvents({ assertTrue(file.delete()) }, mapOf(file to 'D', substFile to 'D'))
- unwatch(request)
+ val request = watch(target)
+ assertEvents({ file.writeText("updated content") }, mapOf(file to 'U', substFile to 'U'))
+ assertEvents({ assertTrue(file.delete()) }, mapOf(file to 'D', substFile to 'D'))
+ unwatch(request)
- assertEvents({ file.writeText("re-creation") }, mapOf(substFile to 'C'))
- }
- finally {
- IoTestUtil.deleteSubst(substRoot.path)
- (vfsRoot as NewVirtualFile).markDirty()
- fs.refresh(false)
+ assertEvents({ file.writeText("re-creation") }, mapOf(substFile to 'C'))
+ }
+ finally {
+ (vfsRoot as NewVirtualFile).markDirty()
+ fs.refresh(false)
+ }
}
}
diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/vfs/local/WslFileWatcherTest.kt b/platform/platform-tests/testSrc/com/intellij/openapi/vfs/local/WslFileWatcherTest.kt
index 43333ea3cffa..83738beb9836 100644
--- a/platform/platform-tests/testSrc/com/intellij/openapi/vfs/local/WslFileWatcherTest.kt
+++ b/platform/platform-tests/testSrc/com/intellij/openapi/vfs/local/WslFileWatcherTest.kt
@@ -7,7 +7,6 @@ import com.intellij.openapi.application.runWriteAction
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.util.SystemInfo
import com.intellij.openapi.util.io.FileUtil
-import com.intellij.openapi.util.io.IoTestUtil
import com.intellij.openapi.util.io.IoTestUtil.*
import com.intellij.openapi.vfs.LocalFileSystem
import com.intellij.openapi.vfs.VfsUtilCore
@@ -455,30 +454,30 @@ class WslFileWatcherTest : BareTestFixtureTestCase() {
val target = tempDir.newDirectory("top")
val file = tempDir.newFile("top/sub/test.txt")
- val substRoot = createSubst(target.path)
- VfsRootAccess.allowRootAccess(testRootDisposable, substRoot.path)
- val vfsRoot = fs.findFileByIoFile(substRoot)!!
- watchedPaths += substRoot.path
+ performTestOnWindowsSubst(target.path) { substRoot ->
+ VfsRootAccess.allowRootAccess(testRootDisposable, substRoot.path)
+ val vfsRoot = fs.findFileByIoFile(substRoot)!!
+ watchedPaths += substRoot.path
- val substFile = File(substRoot, "sub/test.txt")
- refresh(target)
- refresh(substRoot)
+ val substFile = File(substRoot, "sub/test.txt")
+ refresh(target)
+ refresh(substRoot)
- try {
- watch(substRoot)
- assertEvents({ file.writeText("new content") }, mapOf(substFile to 'U'))
+ try {
+ watch(substRoot)
+ assertEvents({ file.writeText("new content") }, mapOf(substFile to 'U'))
- val request = watch(target)
- assertEvents({ file.writeText("updated content") }, mapOf(file to 'U', substFile to 'U'))
- assertEvents({ assertTrue(file.delete()) }, mapOf(file to 'D', substFile to 'D'))
- unwatch(request)
+ val request = watch(target)
+ assertEvents({ file.writeText("updated content") }, mapOf(file to 'U', substFile to 'U'))
+ assertEvents({ assertTrue(file.delete()) }, mapOf(file to 'D', substFile to 'D'))
+ unwatch(request)
- assertEvents({ file.writeText("re-creation") }, mapOf(substFile to 'C'))
- }
- finally {
- deleteSubst(substRoot.path)
- (vfsRoot as NewVirtualFile).markDirty()
- fs.refresh(false)
+ assertEvents({ file.writeText("re-creation") }, mapOf(substFile to 'C'))
+ }
+ finally {
+ (vfsRoot as NewVirtualFile).markDirty()
+ fs.refresh(false)
+ }
}
}
diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/vfs/newvfs/persistent/PersistentFsTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/vfs/newvfs/persistent/PersistentFsTest.java
index 986584903066..02cca13d4052 100644
--- a/platform/platform-tests/testSrc/com/intellij/openapi/vfs/newvfs/persistent/PersistentFsTest.java
+++ b/platform/platform-tests/testSrc/com/intellij/openapi/vfs/newvfs/persistent/PersistentFsTest.java
@@ -15,6 +15,7 @@ import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.roots.ContentEntry;
import com.intellij.openapi.roots.ModuleRootModificationUtil;
import com.intellij.openapi.util.Disposer;
+import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.io.FileAttributes;
import com.intellij.openapi.util.io.FileUtil;
@@ -158,21 +159,19 @@ public class PersistentFsTest extends BareTestFixtureTestCase {
@Test
public void testDeleteSubstRoots() {
IoTestUtil.assumeWindows();
+ Ref<VirtualFile> subst = new Ref<>();
+ Ref<String> substPath = new Ref<>();
- File substRoot = IoTestUtil.createSubst(tempDirectory.getRoot().getPath());
- VirtualFile subst;
- try {
- subst = refreshAndFind(substRoot);
+ IoTestUtil.performTestOnWindowsSubst(tempDirectory.getRoot().getPath(), substRoot -> {
+ substPath.set(substRoot.getPath());
+ subst.set(refreshAndFind(substRoot));
assertNotNull(substRoot.listFiles());
- }
- finally {
- IoTestUtil.deleteSubst(substRoot.getPath());
- }
- subst.refresh(false, true);
+ });
+ subst.get().refresh(false, true);
VirtualFile[] roots = PersistentFS.getInstance().getRoots(LocalFileSystem.getInstance());
for (VirtualFile root : roots) {
- String prefix = StringUtil.commonPrefix(root.getPath(), substRoot.getPath());
+ String prefix = StringUtil.commonPrefix(root.getPath(), substPath.get());
assertTrue(prefix, prefix.isEmpty());
}
}
diff --git a/platform/platform-tests/testSrc/com/intellij/util/io/PersistencePerformanceTest.java b/platform/platform-tests/testSrc/com/intellij/util/io/PersistencePerformanceTest.java
index f78a77c29cdf..7af410828c16 100644
--- a/platform/platform-tests/testSrc/com/intellij/util/io/PersistencePerformanceTest.java
+++ b/platform/platform-tests/testSrc/com/intellij/util/io/PersistencePerformanceTest.java
@@ -1,4 +1,4 @@
-// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
+// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.util.io;
import com.intellij.openapi.application.ApplicationManager;
@@ -15,6 +15,7 @@ import com.intellij.util.indexing.FileBasedIndexImpl;
import com.intellij.util.indexing.UnindexedFilesUpdater;
import com.intellij.util.indexing.contentQueue.IndexUpdateRunner;
import com.intellij.util.indexing.diagnostic.ProjectIndexingHistoryImpl;
+import com.intellij.util.indexing.diagnostic.ScanningType;
import org.jetbrains.annotations.NotNull;
import java.io.DataInput;
@@ -108,7 +109,7 @@ public class PersistencePerformanceTest extends BasePlatformTestCase {
Thread.sleep(100);
new IndexUpdateRunner(index, UnindexedFilesUpdater.GLOBAL_INDEXING_EXECUTOR, UnindexedFilesUpdater.getNumberOfIndexingThreads())
.indexFiles(getProject(), Collections.singletonList(new IndexUpdateRunner.FileSet(getProject(), "test files", files)),
- new EmptyProgressIndicator(), new ProjectIndexingHistoryImpl(getProject(), "Testing", false));
+ new EmptyProgressIndicator(), new ProjectIndexingHistoryImpl(getProject(), "Testing", ScanningType.PARTIAL));
}
for (Future<Boolean> future : futures) {
assertTrue(future.get());
diff --git a/platform/projectModel-api/src/com/intellij/openapi/module/ModuleComponent.java b/platform/projectModel-api/src/com/intellij/openapi/module/ModuleComponent.java
index 9a5ab1a3edf8..bb1ba90f42e5 100644
--- a/platform/projectModel-api/src/com/intellij/openapi/module/ModuleComponent.java
+++ b/platform/projectModel-api/src/com/intellij/openapi/module/ModuleComponent.java
@@ -1,15 +1,15 @@
-// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
+// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.openapi.module;
import com.intellij.openapi.components.BaseComponent;
import com.intellij.openapi.project.Project;
/**
- * @deprecated Components are deprecated. If you register a class as a module component it will be loaded, its instance will be created and
+ * @deprecated Components are deprecated, please see <a href="https://plugins.jetbrains.com/docs/intellij/plugin-components.html">SDK Docs</a> for guidelines on migrating to other APIs.
+ * <p>
+ * If you register a class as a module component it will be loaded, its instance will be created and
* {@link #initComponent()}, {@link #moduleAdded()} methods will be called for each module even if user doesn't use
* any feature of your plugin. Also, plugins declaring module components do not support dynamic loading.
- * <p/>
- * Please see <a href="http://www.jetbrains.org/intellij/sdk/docs/basics/plugin_structure/plugin_components.html">SDK Docs</a> for guidelines on migrating to other APIs.
*/
@Deprecated
public interface ModuleComponent extends BaseComponent {
@@ -38,7 +38,7 @@ public interface ModuleComponent extends BaseComponent {
/**
* Invoked when the module corresponding to this component instance has been completely
* loaded and added to the project.
- * <p>
+ *
* @deprecated Consider to use {@link com.intellij.ProjectTopics#MODULES} ({@link com.intellij.openapi.project.ModuleListener#moduleAdded(Project, Module)})
*/
@Deprecated
diff --git a/platform/refactoring/src/com/intellij/refactoring/extractMethod/ExtractMethodHelper.java b/platform/refactoring/src/com/intellij/refactoring/extractMethod/ExtractMethodHelper.java
index 320a13398a32..c6f3bcf3ec12 100644
--- a/platform/refactoring/src/com/intellij/refactoring/extractMethod/ExtractMethodHelper.java
+++ b/platform/refactoring/src/com/intellij/refactoring/extractMethod/ExtractMethodHelper.java
@@ -108,9 +108,8 @@ public final class ExtractMethodHelper {
boolean isPerformanceScript = System.getProperty("testscript.filename") != null;
final Project project = callElement.getProject();
final boolean exitCode = isUnittest || isPerformanceScript ||
- MessageDialogBuilder.yesNo(message,
- RefactoringBundle.message(
- "refactoring.extract.method.dialog.title"),
+ MessageDialogBuilder.yesNo(RefactoringBundle.message("refactoring.extract.method.dialog.title"),
+ message,
UIUtil.getInformationIcon()).ask(project);
if (exitCode) {
boolean replaceAll = false;
diff --git a/platform/refactoring/src/com/intellij/refactoring/rename/RenameInputValidator.java b/platform/refactoring/src/com/intellij/refactoring/rename/RenameInputValidator.java
index a094d6404265..ee381ce1bdc2 100644
--- a/platform/refactoring/src/com/intellij/refactoring/rename/RenameInputValidator.java
+++ b/platform/refactoring/src/com/intellij/refactoring/rename/RenameInputValidator.java
@@ -9,10 +9,11 @@ import org.jetbrains.annotations.NotNull;
/**
* Validates input for new chosen name of the element to be renamed.
+ * Extend {@link RenameInputValidatorEx} to provide custom error messages.
* <p>
- * Extend {@link RenameInputValidatorEx} to provide custom error message.
- *
- * @author Gregory.Shrago
+ * Register in {@code com.intellij.renameInputValidator} extension point.
+ * @see RenameInputValidatorRegistry
+ * @see <a href="https://plugins.jetbrains.com/docs/intellij/rename-refactoring.html">Rename Refactoring (IntelliJ Platform Docs)</a>
*/
public interface RenameInputValidator {
ExtensionPointName<RenameInputValidator> EP_NAME = ExtensionPointName.create("com.intellij.renameInputValidator");
@@ -21,10 +22,10 @@ public interface RenameInputValidator {
ElementPattern<? extends PsiElement> getPattern();
/**
- * Invoked for elements accepted by pattern {@link #getPattern()}.
+ * Invoked for elements accepted by pattern returned from {@link #getPattern()}.
* <p>
- * Return {@code true} if {@link RenameInputValidatorEx} should return custom error message,
+ * Return {@code true} if {@link RenameInputValidatorEx} should return a custom error message,
* otherwise default message "'[newName]' is not a valid identifier" will be shown.
*/
boolean isInputValid(@NotNull final String newName, @NotNull final PsiElement element, @NotNull final ProcessingContext context);
-} \ No newline at end of file
+}
diff --git a/platform/refactoring/src/com/intellij/refactoring/rename/RenameInputValidatorEx.java b/platform/refactoring/src/com/intellij/refactoring/rename/RenameInputValidatorEx.java
index 013c485d6153..5bf9f98edde3 100644
--- a/platform/refactoring/src/com/intellij/refactoring/rename/RenameInputValidatorEx.java
+++ b/platform/refactoring/src/com/intellij/refactoring/rename/RenameInputValidatorEx.java
@@ -9,17 +9,17 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
- * Adds ability to provide custom error message.
+ * Rename input validator with the ability to provide custom error messages.
*/
public interface RenameInputValidatorEx extends RenameInputValidator {
/**
- * Called only if all input validators ({@link RenameInputValidator}) accept
+ * Called only if all {@link RenameInputValidator}s accept
* the new name in {@link #isInputValid(String, PsiElement, ProcessingContext)}
* and name is a valid identifier for the language of the element.
*
- * @return {@code null} if newName is a valid name, custom error message otherwise
+ * @return {@code null} if {@code newName} is a valid name, custom error message otherwise
*/
@Nullable
@DialogMessage String getErrorMessage(@NotNull String newName, @NotNull Project project);
-} \ No newline at end of file
+}
diff --git a/platform/remoteDev-util/src/com/intellij/remoteDev/downloader/CodeWithMeClientDownloader.kt b/platform/remoteDev-util/src/com/intellij/remoteDev/downloader/CodeWithMeClientDownloader.kt
index edc1f8622f18..873aa12c9a08 100644
--- a/platform/remoteDev-util/src/com/intellij/remoteDev/downloader/CodeWithMeClientDownloader.kt
+++ b/platform/remoteDev-util/src/com/intellij/remoteDev/downloader/CodeWithMeClientDownloader.kt
@@ -8,6 +8,7 @@ import com.intellij.internal.statistic.StructuredIdeActivity
import com.intellij.openapi.application.ModalityState
import com.intellij.openapi.components.service
import com.intellij.openapi.diagnostic.ControlFlowException
+import com.intellij.openapi.diagnostic.debug
import com.intellij.openapi.diagnostic.logger
import com.intellij.openapi.progress.EmptyProgressIndicator
import com.intellij.openapi.progress.ProcessCanceledException
@@ -515,7 +516,7 @@ object CodeWithMeClientDownloader {
val (executable, fullLauncherCmd) = findLauncherUnderCwmGuestRoot(guestRoot)
val guestHome = findCwmGuestHome(guestRoot)
- val linkTarget = if (SystemInfo.isMac) jdkRoot / "jbr" else detectTrueJdkRoot(jdkRoot)
+ val linkTarget = if (SystemInfo.isMac) detectMacOsJbrDirectory(jdkRoot) else detectTrueJdkRoot(jdkRoot)
createSymlink(guestHome / "jbr", linkTarget)
// Update mtime on JRE & CWM Guest roots. The cleanup process will use it later.
@@ -630,8 +631,15 @@ object CodeWithMeClientDownloader {
return processLifetimeDef.lifetime
}
+ private fun detectMacOsJbrDirectory(root: Path): Path {
+ val jbrDirectory = root.listDirectoryEntries().find { it.nameWithoutExtension.startsWith("jbr") }
+
+ LOG.debug { "JBR directory: $jbrDirectory" }
+ return jbrDirectory ?: error("Unable to find target content directory starts with 'jbr' inside MacOS package: '$root'")
+ }
+
fun createSymlinkToJdkFromGuest(guestRoot: Path, jdkRoot: Path) {
- val linkTarget = if (SystemInfo.isMac) jdkRoot / "jbr" else detectTrueJdkRoot(jdkRoot)
+ val linkTarget = if (SystemInfo.isMac) detectMacOsJbrDirectory(jdkRoot) else detectTrueJdkRoot(jdkRoot)
val guestHome = findCwmGuestHome(guestRoot)
createSymlink(guestHome / "jbr", linkTarget)
}
diff --git a/platform/remoteDev-util/src/com/intellij/remoteDev/downloader/CodeWithMeGuestLauncher.kt b/platform/remoteDev-util/src/com/intellij/remoteDev/downloader/CodeWithMeGuestLauncher.kt
index 66ccb80e16c1..b2d2ca3298c9 100644
--- a/platform/remoteDev-util/src/com/intellij/remoteDev/downloader/CodeWithMeGuestLauncher.kt
+++ b/platform/remoteDev-util/src/com/intellij/remoteDev/downloader/CodeWithMeGuestLauncher.kt
@@ -65,7 +65,14 @@ object CodeWithMeGuestLauncher {
val pair = CodeWithMeClientDownloader.downloadClientAndJdk(sessionInfo, progressIndicator)
if (pair == null) return
- clientLifetime = runDownloadedClient(project?.createLifetime() ?: Lifetime.Eternal, pair.first, pair.second, url, product, progressIndicator)
+ clientLifetime = runDownloadedClient(
+ lifetime = project?.createLifetime() ?: Lifetime.Eternal,
+ pathToClient = pair.first,
+ pathToJre = pair.second,
+ urlForThinClient = url,
+ product = product,
+ progressIndicator = progressIndicator
+ )
}
catch (t: Throwable) {
LOG.warn(t)
diff --git a/platform/testFramework/src/com/intellij/openapi/util/io/IoTestUtil.java b/platform/testFramework/src/com/intellij/openapi/util/io/IoTestUtil.java
index a6df3c241f72..0ead19a709a7 100644
--- a/platform/testFramework/src/com/intellij/openapi/util/io/IoTestUtil.java
+++ b/platform/testFramework/src/com/intellij/openapi/util/io/IoTestUtil.java
@@ -26,6 +26,7 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
+import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.jar.JarFile;
import java.util.stream.Collectors;
@@ -57,7 +58,7 @@ public final class IoTestUtil {
return filterParts(Charset.forName(forEncoding).newEncoder()::canEncode);
}
- private static String filterParts(Predicate<String> predicate) {
+ private static String filterParts(@NotNull Predicate<? super String> predicate) {
return StringUtil.nullize(Stream.of(UNICODE_PARTS).filter(predicate).collect(Collectors.joining("_")));
}
@@ -174,7 +175,11 @@ public final class IoTestUtil {
assertTrue(new File(junction).delete());
}
- public static @NotNull File createSubst(@NotNull String target) {
+ /**
+ * (Windows-only)
+ * creates "subst" drive for target, perform some tests on it and deletes it
+ */
+ public static void performTestOnWindowsSubst(@NotNull String target, @NotNull Consumer<? super @NotNull File> createdSubstTester) {
assertTrue(SystemInfo.isWindows);
File targetFile = new File(target);
assertTrue(targetFile.getPath(), targetFile.isDirectory());
@@ -182,11 +187,13 @@ public final class IoTestUtil {
runCommand("subst", substRoot, targetFile.getPath());
File rootFile = new File(substRoot + "\\");
assertTrue("target=" + targetFile + ", subst=" + rootFile, rootFile.isDirectory());
- return rootFile;
- }
- public static void deleteSubst(@NotNull String substRoot) {
- runCommand("subst", StringUtil.trimEnd(substRoot, '\\'), "/d");
+ try {
+ createdSubstTester.accept(rootFile);
+ }
+ finally {
+ runCommand("subst", StringUtil.trimEnd(substRoot, '\\'), "/d");
+ }
}
public static void createFifo(@NotNull String path) {
@@ -266,7 +273,7 @@ public final class IoTestUtil {
}
}
- public static @NotNull File createTestJar(@NotNull File jarFile, @NotNull Collection<Pair<String, byte[]>> namesAndContents) {
+ public static @NotNull File createTestJar(@NotNull File jarFile, @NotNull Collection<? extends Pair<String, byte[]>> namesAndContents) {
try (ZipOutputStream stream = new ZipOutputStream(new FileOutputStream(jarFile))) {
for (Pair<String, byte[]> p : namesAndContents) {
String name = p.first;
diff --git a/platform/util/src/com/intellij/openapi/util/io/OSAgnosticPathUtil.java b/platform/util/src/com/intellij/openapi/util/io/OSAgnosticPathUtil.java
index 189dc7a8bbd4..5b204af5829b 100644
--- a/platform/util/src/com/intellij/openapi/util/io/OSAgnosticPathUtil.java
+++ b/platform/util/src/com/intellij/openapi/util/io/OSAgnosticPathUtil.java
@@ -65,7 +65,14 @@ public final class OSAgnosticPathUtil {
}
public static boolean isAbsoluteDosPath(@NotNull String path) {
- return path.length() > 2 && path.charAt(1) == ':' && isSlash(path.charAt(2)) && isDriveLetter(path.charAt(0));
+ return path.length() > 2 && startsWithWindowsDrive(path) && isSlash(path.charAt(2));
+ }
+
+ /**
+ * @return true when the path starts with a drive letter followed by colon, e.g., "C:"
+ */
+ public static boolean startsWithWindowsDrive(@NotNull String path) {
+ return path.length() >= 2 && path.charAt(1) == ':' && isDriveLetter(path.charAt(0));
}
public static boolean isUncPath(@NotNull String path) {
diff --git a/platform/util/testSrc/com/intellij/openapi/util/io/FileAttributesReadingTest.java b/platform/util/testSrc/com/intellij/openapi/util/io/FileAttributesReadingTest.java
index 5d478baaaccf..f790be64de75 100644
--- a/platform/util/testSrc/com/intellij/openapi/util/io/FileAttributesReadingTest.java
+++ b/platform/util/testSrc/com/intellij/openapi/util/io/FileAttributesReadingTest.java
@@ -432,8 +432,7 @@ public abstract class FileAttributesReadingTest {
assumeWindows();
tempDir.newFile("file.txt"); // just to populate a directory
- File substRoot = createSubst(tempDir.getRoot().getPath());
- try {
+ performTestOnWindowsSubst(tempDir.getRoot().getPath(), substRoot ->{
FileAttributes attributes = getAttributes(substRoot);
assertEquals(substRoot + " " + attributes, FileAttributes.Type.DIRECTORY, attributes.getType());
assertFalse(substRoot + " " + attributes, attributes.isSymLink());
@@ -445,10 +444,7 @@ public abstract class FileAttributesReadingTest {
File file = children[0];
String target = resolveSymLink(file);
assertEquals(file.getPath(), target);
- }
- finally {
- deleteSubst(substRoot.getPath());
- }
+ });
}
@Test
diff --git a/platform/vcs-impl/src/com/intellij/codeInsight/hints/VcsCodeVisionProvider.kt b/platform/vcs-impl/src/com/intellij/codeInsight/hints/VcsCodeVisionProvider.kt
index ecb2e77cad74..e332218bed7c 100644
--- a/platform/vcs-impl/src/com/intellij/codeInsight/hints/VcsCodeVisionProvider.kt
+++ b/platform/vcs-impl/src/com/intellij/codeInsight/hints/VcsCodeVisionProvider.kt
@@ -74,29 +74,23 @@ class VcsCodeVisionProvider : CodeVisionProvider<Unit> {
val lenses = ArrayList<Pair<TextRange, CodeVisionEntry>>()
- try {
- val visionLanguageContext = VcsCodeVisionLanguageContext.providersExtensionPoint.forLanguage(language)
- ?: return@runReadAction READY_EMPTY
- val traverser = SyntaxTraverser.psiTraverser(file)
- for (element in traverser.preOrderDfsTraversal()) {
- if (visionLanguageContext.isAccepted(element)) {
- val textRange = InlayHintsUtils.getTextRangeWithoutLeadingCommentsAndWhitespaces(element)
- val length = editor.document.textLength
- val adjustedRange = TextRange(min(textRange.startOffset, length), min(textRange.endOffset, length))
- val codeAuthorInfo = PREVIEW_INFO_KEY.get(editor) ?: getCodeAuthorInfo(element.project, adjustedRange, editor, aspect)
- val text = codeAuthorInfo.getText()
- val icon = if (codeAuthorInfo.mainAuthor != null) AllIcons.Vcs.Author else null
- val clickHandler = CodeAuthorClickHandler(element, language)
- val entry = ClickableTextCodeVisionEntry(text, id, onClick = clickHandler, icon, text, text, emptyList())
- entry.showInMorePopup = false
- lenses.add(adjustedRange to entry)
- }
+ val visionLanguageContext = VcsCodeVisionLanguageContext.providersExtensionPoint.forLanguage(language)
+ ?: return@runReadAction READY_EMPTY
+ val traverser = SyntaxTraverser.psiTraverser(file)
+ for (element in traverser.preOrderDfsTraversal()) {
+ if (visionLanguageContext.isAccepted(element)) {
+ val textRange = InlayHintsUtils.getTextRangeWithoutLeadingCommentsAndWhitespaces(element)
+ val length = editor.document.textLength
+ val adjustedRange = TextRange(min(textRange.startOffset, length), min(textRange.endOffset, length))
+ val codeAuthorInfo = PREVIEW_INFO_KEY.get(editor) ?: getCodeAuthorInfo(element.project, adjustedRange, editor, aspect)
+ val text = codeAuthorInfo.getText()
+ val icon = if (codeAuthorInfo.mainAuthor != null) AllIcons.Vcs.Author else null
+ val clickHandler = CodeAuthorClickHandler(element, language)
+ val entry = ClickableTextCodeVisionEntry(text, id, onClick = clickHandler, icon, text, text, emptyList())
+ entry.showInMorePopup = false
+ lenses.add(adjustedRange to entry)
}
}
- catch (e: Exception) {
- e.printStackTrace()
- throw e
- }
return@runReadAction CodeVisionState.Ready(lenses)
}
}
@@ -135,7 +129,7 @@ class VcsCodeVisionProvider : CodeVisionProvider<Unit> {
val visionLanguageContext = VcsCodeVisionLanguageContext.providersExtensionPoint.forLanguage(language) ?: return null
val vcs = ProjectLevelVcsManager.getInstance(project).getVcsFor(psiFile.virtualFile) ?: return null
if ("Git" != vcs.name) {
- return null
+ return null
}
if (vcs.annotationProvider !is CacheableAnnotationProvider) return null
return object: BypassBasedPlaceholderCollector {
diff --git a/platform/vfs-impl/src/com/intellij/openapi/vfs/impl/FilePartNodeRoot.java b/platform/vfs-impl/src/com/intellij/openapi/vfs/impl/FilePartNodeRoot.java
index 059768d0492f..9dd4671ed360 100644
--- a/platform/vfs-impl/src/com/intellij/openapi/vfs/impl/FilePartNodeRoot.java
+++ b/platform/vfs-impl/src/com/intellij/openapi/vfs/impl/FilePartNodeRoot.java
@@ -2,6 +2,7 @@
package com.intellij.openapi.vfs.impl;
import com.intellij.openapi.util.Pair;
+import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.util.text.StringUtilRt;
import com.intellij.openapi.vfs.*;
@@ -138,27 +139,27 @@ final class FilePartNodeRoot extends FilePartNode {
@NotNull
NodeToUpdate findOrCreateByPath(@NotNull String path, @NotNull NewVirtualFileSystem fs) {
NewVirtualFileSystem currentFS;
- boolean jarSuffix;
+ String relativePathInsideJar;
if (fs instanceof ArchiveFileSystem) {
currentFS = LocalFileSystem.getInstance();
- // strip trailing "!/" because LocalVirtualFileSystem.normalize() are afraid of them and strip them out
- if (path.endsWith(JarFileSystem.JAR_SEPARATOR)) {
- path = path.substring(0, path.length() - JarFileSystem.JAR_SEPARATOR.length());
- jarSuffix = true;
+ int i = path.lastIndexOf(JarFileSystem.JAR_SEPARATOR);
+ // strip everything after "!/" and after extractRootFromPath() append it back,
+ // because LocalVirtualFileSystem.normalize() is afraid of these jar separators and tries to absolutize them incorrectly (e.g. "C:!/foo" -> "C:idea/bin/!/foo")
+ if (i == -1) {
+ relativePathInsideJar = JarFileSystem.JAR_SEPARATOR;
}
else {
- jarSuffix = false;
+ relativePathInsideJar = path.substring(i);
+ path = path.substring(0, i);
}
}
else {
currentFS = fs;
- jarSuffix = false;
+ relativePathInsideJar = "";
}
Pair<NewVirtualFile, String> pair = VfsImplUtil.extractRootFromPath(currentFS, path);
String pathFromRoot = pair == null ? path : pair.second;
- if (jarSuffix) {
- pathFromRoot += JarFileSystem.JAR_SEPARATOR;
- }
+ pathFromRoot += relativePathInsideJar;
List<String> names = splitNames(pathFromRoot);
NewVirtualFile fsRoot = pair == null ? null : pair.first;
@@ -283,16 +284,16 @@ final class FilePartNodeRoot extends FilePartNode {
if (end == 0) return Collections.emptyList();
List<String> names = new ArrayList<>(Math.max(20, end/4)); // path length -> path height approximation
while (true) {
- boolean isJarSeparator = StringUtil.endsWith(path, 0, end, JarFileSystem.JAR_SEPARATOR) && end > 2 && path.charAt(end - 3) != '/';
+ boolean isJarSeparator = StringUtil.endsWith(path, 0, end, JarFileSystem.JAR_SEPARATOR)
+ && (end == 2 && SystemInfo.isWindows || end > 2 && path.charAt(end - 3) != '/');
if (isJarSeparator) {
names.add(JarFileSystem.JAR_SEPARATOR);
end -= 2;
- continue;
}
- if (path.charAt(end-1) == '/') {
+ if (end != 0 && path.charAt(end-1) == '/') {
end--;
}
- if (end == 0 && path.charAt(0) == '/') {
+ if (end == 0) {
break; // here's separator between non-empty root (e.g. on Windows) and path's tail
}
int startIndex = extractName(path, end);
@@ -321,8 +322,8 @@ final class FilePartNodeRoot extends FilePartNode {
}
// returns start index of the name (i.e. path[return..length) is considered a name)
- private static int extractName(@NotNull CharSequence path, int length) {
- int i = StringUtil.lastIndexOf(path, '/', 0, length);
+ private static int extractName(@NotNull CharSequence path, int endOffset) {
+ int i = StringUtil.lastIndexOf(path, '/', 0, endOffset);
if (i != -1 && PathUtilRt.isWindowsUNCRoot(path, i)) {
// UNC
return 0;
diff --git a/platform/vfs-impl/src/com/intellij/openapi/vfs/impl/VirtualFilePointerManagerImpl.java b/platform/vfs-impl/src/com/intellij/openapi/vfs/impl/VirtualFilePointerManagerImpl.java
index 70efb62acc40..0149cbfb7a03 100644
--- a/platform/vfs-impl/src/com/intellij/openapi/vfs/impl/VirtualFilePointerManagerImpl.java
+++ b/platform/vfs-impl/src/com/intellij/openapi/vfs/impl/VirtualFilePointerManagerImpl.java
@@ -223,8 +223,7 @@ public final class VirtualFilePointerManagerImpl extends VirtualFilePointerManag
// if newly created path is the same as the one extracted from url then the url did not change, we can reuse it
//noinspection StringEquality
if (cleanPath != path) {
- String fsSpecificPath = cleanPath + (fileSystem instanceof ArchiveFileSystem && !cleanPath.contains(JarFileSystem.JAR_SEPARATOR) ? JarFileSystem.JAR_SEPARATOR : "");
- url = VirtualFileManager.constructUrl(protocol, fsSpecificPath);
+ url = VirtualFileManager.constructUrl(protocol, cleanPath);
path = cleanPath;
}
if (url.contains("..")) {
@@ -237,7 +236,7 @@ public final class VirtualFilePointerManagerImpl extends VirtualFilePointerManag
else {
// when someone is crazy enough to create VFP for not-yet existing file from the path with "..", ignore all symlinks
path = FileUtil.toCanonicalPath(path);
- url = VirtualFileManager.constructUrl(protocol, path + (fileSystem instanceof ArchiveFileSystem ? JarFileSystem.JAR_SEPARATOR : ""));
+ url = VirtualFileManager.constructUrl(protocol, path);
}
}
if (file == null && StringUtil.isEmptyOrSpaces(path)) {
@@ -283,7 +282,7 @@ public final class VirtualFilePointerManagerImpl extends VirtualFilePointerManag
if (next == '/' && i != 0 ||
next == '/' && !SystemInfo.isWindows ||// additional condition for Windows UNC
- next == '/' && slash == 2 && path.charAt(1) == ':' && OSAgnosticPathUtil.isDriveLetter(path.charAt(0)) ||// Z://foo -> Z:/foo
+ next == '/' && slash == 2 && OSAgnosticPathUtil.startsWithWindowsDrive(path) || // Z://foo -> Z:/foo
next == '.' && (slash == path.length()-2 || path.charAt(slash+2) == '/')) {
return cleanupTail(path, slash);
}
@@ -342,19 +341,34 @@ public final class VirtualFilePointerManagerImpl extends VirtualFilePointerManag
FilePartNodeRoot root = getRoot(fs);
NodeToUpdate toUpdate;
if (file == null) {
- String normPath = fs instanceof ArchiveFileSystem && !path.contains(JarFileSystem.JAR_SEPARATOR) ? path + JarFileSystem.JAR_SEPARATOR : path;
+ String normPath = path;
+ if (fs instanceof ArchiveFileSystem) {
+ // check that "!/" separator is placed correctly in the url:
+ // "xx!/yyy" has jar separator; but "xx/!/yyy" doesn't: directory separator only
+ int index = -1;
+ do {
+ index = path.indexOf(JarFileSystem.JAR_SEPARATOR, index + 1);
+ }
+ while (index > 0 && path.charAt(index-1) == '/');
+ if (index == -1 && !isArchiveInTheWindowsDiskRoot(path)) {
+ // treat url "jar://xx/x.jar" as "jar://xx/x.jar!/"
+ normPath = path + JarFileSystem.JAR_SEPARATOR;
+ }
+ }
toUpdate = root.findOrCreateByPath(normPath, fs);
}
else {
toUpdate = root.findOrCreateByFile(file);
}
FilePartNode node = toUpdate.node;
- if (fs != node.myFS && url != null && (IS_UNDER_UNIT_TEST || IS_INTERNAL)) {
- throw new IllegalArgumentException("Invalid url: '" + url + "'. " +
- "Its protocol '" + VirtualFileManager.extractProtocol(url) + "' is from " + fsFromFile +
- " but the path part points to " + node.myFS);
+ if (fs != node.myFS) {
+ if (url != null && (IS_UNDER_UNIT_TEST || IS_INTERNAL)) {
+ throw new IllegalArgumentException("Invalid url: '" + url + "'. " +
+ "Its protocol '" + VirtualFileManager.extractProtocol(url) + "' is from " + fsFromFile +
+ " but the path part points to " + node.myFS);
+ }
+ LOG.error("fs=" + fs + "; node.myFS=" + node.myFS+"; url="+url+"; file="+file+"; node="+node);
}
- assert fs == node.myFS : "fs=" + fs + "; node.myFS=" + node.myFS+"; url="+url+"; file="+file;
VirtualFilePointerImpl pointer = node.getPointer(listener);
if (pointer == null) {
@@ -372,6 +386,21 @@ public final class VirtualFilePointerManagerImpl extends VirtualFilePointerManag
return pointer;
}
+ private static boolean isArchiveInTheWindowsDiskRoot(@NotNull String path) {
+ // special case: "C:!/foo" means the archive is in the disk root - we shouldn't treat it as relative path starting with "!"
+ // other special case: "C:/!/foo" means the archive is in the disk root - we shouldn't treat it as under the (local) directory "!" in the disk root
+ return OSAgnosticPathUtil.startsWithWindowsDrive(path)
+ && path.length() >= 4
+ && (path.charAt(2) == '!'
+ && path.charAt(3) == '/'
+ ||
+ path.length() >= 5
+ && path.charAt(2) == '/'
+ && path.charAt(3) == '!'
+ && path.charAt(4) == '/'
+ );
+ }
+
@Override
public @NotNull VirtualFilePointer duplicate(@NotNull VirtualFilePointer pointer,
@NotNull Disposable parent,
@@ -530,7 +559,7 @@ public final class VirtualFilePointerManagerImpl extends VirtualFilePointerManag
if (VirtualFile.PROP_NAME.equals(change.getPropertyName()) && !Comparing.equal(change.getOldValue(), change.getNewValue())) {
VirtualFileSystemEntry eventFile = (VirtualFileSystemEntry)change.getFile();
VirtualFileSystemEntry parent = (VirtualFileSystemEntry)FilePartNode.getParentThroughJar(eventFile, eventFile.getFileSystem());
- // e.g. for LightVirtualFiles
+ // e.g., for LightVirtualFiles
if (parent != null) {
int newNameId = toNameId(change.getNewValue().toString());
addRelevantPointers(eventFile, parent, newNameId, toFirePointers, toUpdateNodes, true, fs, event);
diff --git a/platform/vfs-impl/src/com/intellij/openapi/vfs/newvfs/VfsImplUtil.java b/platform/vfs-impl/src/com/intellij/openapi/vfs/newvfs/VfsImplUtil.java
index 80bf679e13ac..b3be0fabdf91 100644
--- a/platform/vfs-impl/src/com/intellij/openapi/vfs/newvfs/VfsImplUtil.java
+++ b/platform/vfs-impl/src/com/intellij/openapi/vfs/newvfs/VfsImplUtil.java
@@ -152,7 +152,12 @@ public final class VfsImplUtil {
return null;
}
- return pair(root, normalizedPath.substring(rootPath.length()));
+ int i = rootPath.length();
+ if (i < normalizedPath.length() && normalizedPath.charAt(i) == '/') {
+ i++;
+ }
+ String relativePath = normalizedPath.substring(i);
+ return pair(root, relativePath);
}
public static void refresh(@NotNull NewVirtualFileSystem vfs, boolean asynchronous) {
diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/actions/XNewWatchAction.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/actions/XNewWatchAction.java
index 7f4e9fdd9cc3..43dfe1a1808d 100644
--- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/actions/XNewWatchAction.java
+++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/actions/XNewWatchAction.java
@@ -1,34 +1,36 @@
-/*
- * 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.
- */
+// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.xdebugger.impl.frame.actions;
import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.project.DumbAwareAction;
+import com.intellij.xdebugger.XDebugSession;
+import com.intellij.xdebugger.impl.XDebugSessionImpl;
+import com.intellij.xdebugger.impl.frame.XVariablesViewBase;
import com.intellij.xdebugger.impl.frame.XWatchesView;
-import com.intellij.xdebugger.impl.ui.tree.XDebuggerTree;
+import com.intellij.xdebugger.impl.ui.DebuggerUIUtil;
+import com.intellij.xdebugger.impl.ui.XDebugSessionTab;
import com.intellij.xdebugger.impl.ui.tree.nodes.WatchesRootNode;
import com.intellij.xdebugger.impl.ui.tree.nodes.XDebuggerTreeNode;
import org.jetbrains.annotations.NotNull;
-public class XNewWatchAction extends XWatchesTreeActionBase {
+public class XNewWatchAction extends DumbAwareAction {
@Override
- protected void perform(@NotNull AnActionEvent e, @NotNull XDebuggerTree tree, @NotNull XWatchesView watchesView) {
- XDebuggerTreeNode root = tree.getRoot();
- if (root instanceof WatchesRootNode) {
- final WatchesRootNode watchesRoot = (WatchesRootNode)root;
- watchesRoot.addNewWatch();
+ public void actionPerformed(@NotNull AnActionEvent e) {
+ XWatchesView view = DebuggerUIUtil.getWatchesView(e);
+ if (view instanceof XVariablesViewBase) {
+ XDebuggerTreeNode root = ((XVariablesViewBase)view).getTree().getRoot();
+ if (root instanceof WatchesRootNode) {
+ XDebugSession session = DebuggerUIUtil.getSession(e);
+ if (session instanceof XDebugSessionImpl) {
+ XDebugSessionTab.showWatchesView((XDebugSessionImpl)session);
+ }
+ ((WatchesRootNode)root).addNewWatch();
+ }
}
}
+
+ @Override
+ public void update(@NotNull AnActionEvent e) {
+ e.getPresentation().setEnabled(DebuggerUIUtil.getSession(e) != null && DebuggerUIUtil.getWatchesView(e) != null);
+ }
}
diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/DebuggerUIUtil.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/DebuggerUIUtil.java
index e20b55765dc7..163deca2ead9 100644
--- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/DebuggerUIUtil.java
+++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/DebuggerUIUtil.java
@@ -4,7 +4,9 @@ package com.intellij.xdebugger.impl.ui;
import com.intellij.codeInsight.hint.HintUtil;
import com.intellij.ide.nls.NlsMessages;
import com.intellij.openapi.Disposable;
-import com.intellij.openapi.actionSystem.*;
+import com.intellij.openapi.actionSystem.ActionManager;
+import com.intellij.openapi.actionSystem.AnAction;
+import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.LogicalPosition;
@@ -21,15 +23,14 @@ import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.wm.IdeFocusManager;
import com.intellij.openapi.wm.WindowManager;
-import com.intellij.ui.*;
+import com.intellij.ui.AppUIUtil;
+import com.intellij.ui.ComponentUtil;
+import com.intellij.ui.EditorTextField;
+import com.intellij.ui.ScreenUtil;
import com.intellij.ui.awt.RelativePoint;
-import com.intellij.ui.components.AnActionLink;
-import com.intellij.ui.components.JBLabel;
import com.intellij.ui.popup.list.ListPopupImpl;
import com.intellij.util.Consumer;
-import com.intellij.util.ui.GridBag;
import com.intellij.util.ui.JBUI;
-import com.intellij.util.ui.UIUtil;
import com.intellij.xdebugger.*;
import com.intellij.xdebugger.breakpoints.XBreakpoint;
import com.intellij.xdebugger.breakpoints.XBreakpointListener;
@@ -464,6 +465,22 @@ public final class DebuggerUIUtil {
});
}
+ @Nullable
+ public static XWatchesView getWatchesView(@NotNull AnActionEvent e) {
+ XWatchesView view = e.getData(XWatchesView.DATA_KEY);
+ Project project = e.getProject();
+ if (view == null && project != null) {
+ XDebugSession session = getSession(e);
+ if (session != null) {
+ XDebugSessionTab tab = ((XDebugSessionImpl)session).getSessionTab();
+ if (tab != null) {
+ return tab.getWatchesView();
+ }
+ }
+ }
+ return view;
+ }
+
public static void registerActionOnComponent(String name, JComponent component, Disposable parentDisposable) {
AnAction action = ActionManager.getInstance().getAction(name);
action.registerCustomShortcutSet(action.getShortcutSet(), component, parentDisposable);
diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/actions/XAddToWatchesTreeAction.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/actions/XAddToWatchesTreeAction.java
index 2cfce6f629e2..acc6e0b322c0 100644
--- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/actions/XAddToWatchesTreeAction.java
+++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/actions/XAddToWatchesTreeAction.java
@@ -1,13 +1,9 @@
-// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
+// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.xdebugger.impl.ui.tree.actions;
import com.intellij.openapi.actionSystem.AnActionEvent;
-import com.intellij.openapi.project.Project;
-import com.intellij.xdebugger.XDebugSession;
-import com.intellij.xdebugger.impl.XDebugSessionImpl;
import com.intellij.xdebugger.impl.frame.XWatchesView;
import com.intellij.xdebugger.impl.ui.DebuggerUIUtil;
-import com.intellij.xdebugger.impl.ui.XDebugSessionTab;
import com.intellij.xdebugger.impl.ui.tree.nodes.XValueNodeImpl;
import org.jetbrains.annotations.NotNull;
@@ -18,7 +14,7 @@ import org.jetbrains.annotations.NotNull;
public class XAddToWatchesTreeAction extends XDebuggerTreeActionBase {
@Override
protected boolean isEnabled(@NotNull final XValueNodeImpl node, @NotNull AnActionEvent e) {
- return super.isEnabled(node, e) && getWatchesView(e) != null;
+ return super.isEnabled(node, e) && DebuggerUIUtil.getWatchesView(e) != null;
}
@Override
@@ -35,24 +31,9 @@ public class XAddToWatchesTreeAction extends XDebuggerTreeActionBase {
@Override
protected void perform(final XValueNodeImpl node, @NotNull final String nodeName, final AnActionEvent e) {
- final XWatchesView watchesView = getWatchesView(e);
+ final XWatchesView watchesView = DebuggerUIUtil.getWatchesView(e);
if (watchesView != null) {
DebuggerUIUtil.addToWatches(watchesView, node);
}
}
-
- private static XWatchesView getWatchesView(@NotNull AnActionEvent e) {
- XWatchesView view = e.getData(XWatchesView.DATA_KEY);
- Project project = e.getProject();
- if (view == null && project != null) {
- XDebugSession session = DebuggerUIUtil.getSession(e);
- if (session != null) {
- XDebugSessionTab tab = ((XDebugSessionImpl)session).getSessionTab();
- if (tab != null) {
- return tab.getWatchesView();
- }
- }
- }
- return view;
- }
} \ No newline at end of file
diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/resources/AutoCloseableResourceInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/resources/AutoCloseableResourceInspection.java
index 31a9cd9414a5..2b733fc191c3 100644
--- a/plugins/InspectionGadgets/src/com/siyeh/ig/resources/AutoCloseableResourceInspection.java
+++ b/plugins/InspectionGadgets/src/com/siyeh/ig/resources/AutoCloseableResourceInspection.java
@@ -62,7 +62,9 @@ public class AutoCloseableResourceInspection extends ResourceInspection {
"java.io.StringReader",
"java.util.Formatter",
"java.util.Scanner",
- "org.springframework.context.ConfigurableApplicationContext");
+ "org.springframework.context.ConfigurableApplicationContext",
+ "io.micronaut.context.ApplicationContext");
+
protected final MethodMatcher myMethodMatcher;
final List<String> ignoredTypes = new ArrayList<>(DEFAULT_IGNORED_TYPES);
@SuppressWarnings("PublicField")
diff --git a/plugins/coverage/src/com/intellij/coverage/JavaCoverageEngine.java b/plugins/coverage/src/com/intellij/coverage/JavaCoverageEngine.java
index 2aebf9b181db..a7bf3c8a006f 100644
--- a/plugins/coverage/src/com/intellij/coverage/JavaCoverageEngine.java
+++ b/plugins/coverage/src/com/intellij/coverage/JavaCoverageEngine.java
@@ -53,11 +53,13 @@ import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.rt.coverage.data.JumpData;
import com.intellij.rt.coverage.data.LineData;
import com.intellij.rt.coverage.data.SwitchData;
+import com.intellij.task.ProjectTaskManager;
import com.intellij.testIntegration.TestFramework;
import jetbrains.coverage.report.ReportGenerationFailedException;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import org.jetbrains.concurrency.Promise;
import org.jetbrains.jps.model.java.JavaSourceRootType;
import java.io.DataInputStream;
@@ -326,8 +328,13 @@ public class JavaCoverageEngine extends CoverageEngine {
@Override
public boolean recompileProjectAndRerunAction(@NotNull final Module module, @NotNull final CoverageSuitesBundle suite,
@NotNull final Runnable chooseSuiteAction) {
- final VirtualFile outputpath = CompilerModuleExtension.getInstance(module).getCompilerOutputPath();
- final VirtualFile testOutputpath = CompilerModuleExtension.getInstance(module).getCompilerOutputPathForTests();
+ CompilerModuleExtension compilerModuleExtension = CompilerModuleExtension.getInstance(module);
+ if (compilerModuleExtension == null) {
+ return false;
+ }
+
+ final VirtualFile outputpath = compilerModuleExtension.getCompilerOutputPath();
+ final VirtualFile testOutputpath = compilerModuleExtension.getCompilerOutputPathForTests();
if (outputpath == null && isModuleOutputNeeded(module, JavaSourceRootType.SOURCE)
|| suite.isTrackTestFolders() && testOutputpath == null && isModuleOutputNeeded(module, JavaSourceRootType.TEST_SOURCE)) {
@@ -342,14 +349,12 @@ public class JavaCoverageEngine extends CoverageEngine {
JavaCoverageBundle.message("coverage.hide.report"),
Messages.getWarningIcon());
if (choice == Messages.OK) {
- final CompilerManager compilerManager = CompilerManager.getInstance(project);
- compilerManager.make(compilerManager.createProjectCompileScope(project), (aborted, errors, warnings, compileContext) -> {
- if (aborted || errors != 0) return;
- ApplicationManager.getApplication().invokeLater(() -> {
- if (project.isDisposed()) return;
- CoverageDataManager.getInstance(project).chooseSuitesBundle(suite);
- });
- });
+ ProjectTaskManager taskManager = ProjectTaskManager.getInstance(project);
+ Promise<ProjectTaskManager.Result> promise = taskManager.buildAllModules();
+ promise.onSuccess(result -> ApplicationManager.getApplication().invokeLater(() -> {
+ CoverageDataManager.getInstance(project).chooseSuitesBundle(suite);
+ }, o -> project.isDisposed())
+ );
} else if (!project.isDisposed()) {
CoverageDataManager.getInstance(project).chooseSuitesBundle(null);
}
diff --git a/plugins/editorconfig/src/org/editorconfig/configmanagement/EditorConfigEncodingCache.java b/plugins/editorconfig/src/org/editorconfig/configmanagement/EditorConfigEncodingCache.java
index 82b3bb84e6e7..161b7fa6aee8 100644
--- a/plugins/editorconfig/src/org/editorconfig/configmanagement/EditorConfigEncodingCache.java
+++ b/plugins/editorconfig/src/org/editorconfig/configmanagement/EditorConfigEncodingCache.java
@@ -138,7 +138,8 @@ public class EditorConfigEncodingCache implements PersistentStateComponent<Eleme
@Nullable
public Charset getCachedEncoding(@NotNull VirtualFile virtualFile) {
- return ObjectUtils.doIfNotNull(getCachedCharsetData(virtualFile), CharsetData::getCharset);
+ CharsetData charsetData = getCachedCharsetData(virtualFile);
+ return charsetData != null && !charsetData.isIgnored ? charsetData.getCharset() : null;
}
@Nullable
diff --git a/plugins/gradle/java/resources/META-INF/plugin.xml b/plugins/gradle/java/resources/META-INF/plugin.xml
index 7e8c36e8761c..2eea7553b1c3 100644
--- a/plugins/gradle/java/resources/META-INF/plugin.xml
+++ b/plugins/gradle/java/resources/META-INF/plugin.xml
@@ -40,6 +40,7 @@
<frameworkSupport implementation="org.jetbrains.plugins.gradle.frameworkSupport.GradleJavaFrameworkSupportProvider"/>
<kotlinDslFrameworkSupport implementation="org.jetbrains.plugins.gradle.frameworkSupport.KotlinDslGradleJavaFrameworkSupportProvider" />
<targetEnvironmentAware implementation="org.jetbrains.plugins.gradle.execution.target.GradleServerDebugAware" />
+ <taskResultListener implementation="org.jetbrains.plugins.gradle.service.GradleProjectOutputsUpdater"/>
</extensions>
<extensions defaultExtensionNs="com.intellij">
@@ -95,5 +96,7 @@
<statistics.counterUsagesCollector implementationClass="com.intellij.openapi.externalSystem.statistics.ExternalSystemSyncActionsCollector"/>
<registryKey key="gradle.execution.target.server.debug.port" defaultValue="-1"
description="Specifies port at which Gradle target server process will wait for debugger connections. -1 means disabled feature."/>
+ <registryKey key="gradle.refresh.project.outputs" defaultValue="true"
+ description="After a Gradle task, do a shallow refresh of modules outputs in VFS"/>
</extensions>
</idea-plugin> \ No newline at end of file
diff --git a/plugins/gradle/java/src/config/GradlePositionManager.java b/plugins/gradle/java/src/config/GradlePositionManager.java
index a1182a8b7307..efbee8117583 100644
--- a/plugins/gradle/java/src/config/GradlePositionManager.java
+++ b/plugins/gradle/java/src/config/GradlePositionManager.java
@@ -4,6 +4,7 @@ package org.jetbrains.plugins.gradle.config;
import com.intellij.execution.wsl.WSLDistribution;
import com.intellij.execution.wsl.WslDistributionManager;
import com.intellij.execution.wsl.WslPath;
+import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleUtilCore;
import com.intellij.openapi.project.Project;
@@ -38,6 +39,8 @@ import org.jetbrains.plugins.groovy.runner.GroovyScriptUtil;
import java.io.File;
import java.net.URI;
import java.net.URISyntaxException;
+import java.util.Collection;
+import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
@@ -99,6 +102,11 @@ public class GradlePositionManager extends ScriptPositionManagerHelper {
return PsiManager.getInstance(project).findFile(virtualFile);
}
+ @Override
+ public Collection<? extends FileType> getAcceptedFileTypes() {
+ return Collections.singleton(GradleFileType.INSTANCE);
+ }
+
private static String getLocalFilePath(@NotNull Project project, @NotNull String sourceFilePath) {
// TODO add the support for other run targets mappings
String projectBasePath = project.getBasePath();
diff --git a/plugins/gradle/java/src/service/GradleProjectOutputsUpdater.kt b/plugins/gradle/java/src/service/GradleProjectOutputsUpdater.kt
new file mode 100644
index 000000000000..6353f13fd28f
--- /dev/null
+++ b/plugins/gradle/java/src/service/GradleProjectOutputsUpdater.kt
@@ -0,0 +1,44 @@
+// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+package org.jetbrains.plugins.gradle.service
+
+import com.intellij.compiler.impl.CompilerUtil
+import com.intellij.openapi.compiler.CompilerPaths
+import com.intellij.openapi.diagnostic.logger
+import com.intellij.openapi.externalSystem.model.ProjectKeys
+import com.intellij.openapi.externalSystem.model.project.ModuleData
+import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskId
+import com.intellij.openapi.externalSystem.service.project.IdeModelsProviderImpl
+import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil
+import com.intellij.openapi.module.Module
+import com.intellij.openapi.util.registry.Registry
+import com.intellij.util.containers.ContainerUtil
+import org.jetbrains.plugins.gradle.model.data.GradleSourceSetData
+import org.jetbrains.plugins.gradle.service.task.GradleTaskResultListener
+import org.jetbrains.plugins.gradle.util.GradleConstants
+
+class GradleProjectOutputsUpdater: GradleTaskResultListener {
+ override fun onSuccess(id: ExternalSystemTaskId, projectPath: String) {
+ if (!Registry.`is`("gradle.refresh.project.outputs")) return
+
+ val ideaProject = id.findProject()
+ if (ideaProject == null) {
+ LOG.warn("Project path [$projectPath] does not belong to any open Gradle projects")
+ return
+ }
+
+ val modelsProvider = IdeModelsProviderImpl(ideaProject)
+ val projectNode = ExternalSystemApiUtil.findProjectNode(ideaProject, GradleConstants.SYSTEM_ID, projectPath) ?: return
+ val moduleNodes = ExternalSystemApiUtil.findAll(projectNode, ProjectKeys.MODULE)
+ val affectedModules: List<Module> = moduleNodes.flatMap { ExternalSystemApiUtil.findAll(it, GradleSourceSetData.KEY) + it }
+ .map { it.data }
+ .filterIsInstance(ModuleData::class.java)
+ .mapNotNull { modelsProvider.findIdeModule(it) }
+
+ val affectedRoots = ContainerUtil.newHashSet(*CompilerPaths.getOutputPaths(affectedModules.toTypedArray()))
+ CompilerUtil.refreshOutputRoots(affectedRoots)
+ }
+
+ companion object {
+ private val LOG = logger<GradleProjectOutputsUpdater>()
+ }
+} \ No newline at end of file
diff --git a/plugins/gradle/plugin-resources/META-INF/plugin.xml b/plugins/gradle/plugin-resources/META-INF/plugin.xml
index b201d882de66..5d6437168fe9 100644
--- a/plugins/gradle/plugin-resources/META-INF/plugin.xml
+++ b/plugins/gradle/plugin-resources/META-INF/plugin.xml
@@ -42,6 +42,8 @@
dynamic="true"/>
<extensionPoint qualifiedName="org.jetbrains.plugins.gradle.targetEnvironmentAware" interface="org.jetbrains.plugins.gradle.execution.target.GradleTargetEnvironmentAware"
dynamic="true"/>
+ <extensionPoint qualifiedName= "org.jetbrains.plugins.gradle.taskResultListener" interface="org.jetbrains.plugins.gradle.service.task.GradleTaskResultListener"
+ dynamic="true"/>
</extensionPoints>
<extensions defaultExtensionNs="org.jetbrains.plugins.gradle">
diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/CommonGradleProjectResolverExtension.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/CommonGradleProjectResolverExtension.java
index 2680635554b7..d24588261504 100644
--- a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/CommonGradleProjectResolverExtension.java
+++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/CommonGradleProjectResolverExtension.java
@@ -5,6 +5,7 @@ import com.intellij.build.events.MessageEvent;
import com.intellij.build.issue.BuildIssue;
import com.intellij.openapi.application.ApplicationNamesInfo;
import com.intellij.openapi.application.PathManager;
+import com.intellij.openapi.application.ReadAction;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.externalSystem.debugger.DebuggerBackendExtension;
import com.intellij.openapi.externalSystem.model.ConfigurationDataImpl;
@@ -34,6 +35,7 @@ import com.intellij.util.Consumer;
import com.intellij.util.LazyInitializer;
import com.intellij.util.LazyInitializer.LazyValue;
import com.intellij.util.ReflectionUtil;
+import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.FileCollectionFactory;
import com.intellij.util.containers.MultiMap;
import com.intellij.util.execution.ParametersListUtil;
@@ -586,7 +588,21 @@ public final class CommonGradleProjectResolverExtension extends AbstractProjectR
@Nullable
private static File getGradleOutputDir(@Nullable ExternalSourceDirectorySet sourceDirectorySet) {
if (sourceDirectorySet == null) return null;
- return sourceDirectorySet.getGradleOutputDirs().stream().findFirst().orElse(null);
+ String firstExistingLang = sourceDirectorySet.getSrcDirs().stream()
+ .filter(File::exists)
+ .findFirst()
+ .map(File::getName)
+ .orElse(null);
+
+ if (firstExistingLang == null) {
+ return ContainerUtil.getFirstItem(sourceDirectorySet.getGradleOutputDirs());
+ }
+
+ return sourceDirectorySet.getGradleOutputDirs().stream()
+ .filter(f -> f.getPath().contains(firstExistingLang))
+ .findFirst()
+ .orElse(ContainerUtil.getFirstItem(sourceDirectorySet.getGradleOutputDirs()));
+
}
private static void excludeOutDir(@NotNull DataNode<ModuleData> ideModule, File ideaOutDir) {
diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/task/GradleTaskManager.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/task/GradleTaskManager.java
index d9faf3979d4b..bae1b9a7f784 100644
--- a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/task/GradleTaskManager.java
+++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/task/GradleTaskManager.java
@@ -157,6 +157,7 @@ public class GradleTaskManager implements ExternalSystemTaskManager<GradleExecut
launcher.withCancellationToken(cancellationTokenSource.token());
launcher.run();
}
+ GradleTaskResultListener.EP_NAME.forEachExtensionSafe(ext -> ext.onSuccess(id, projectPath));
}
catch (RuntimeException e) {
LOG.debug("Gradle build launcher error", e);
diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/task/GradleTaskResultListener.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/task/GradleTaskResultListener.java
new file mode 100644
index 000000000000..20b26d197f20
--- /dev/null
+++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/task/GradleTaskResultListener.java
@@ -0,0 +1,26 @@
+// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+package org.jetbrains.plugins.gradle.service.task;
+
+import com.intellij.openapi.extensions.ExtensionPointName;
+import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskId;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Listens for Gradle tasks execution.
+ * <br>
+ * Internal extension point to support internal functionality. E.g., vfs updates for java-related projects
+ */
+@ApiStatus.Internal
+public interface GradleTaskResultListener {
+
+ ExtensionPointName<GradleTaskResultListener> EP_NAME = ExtensionPointName.create("org.jetbrains.plugins.gradle.taskResultListener");
+
+ /**
+ * Called right after successful execution of Gradle task, before returning to External System API
+ *
+ * @param id
+ * @param projectPath
+ */
+ void onSuccess(@NotNull ExternalSystemTaskId id, @NotNull String projectPath);
+}
diff --git a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/importing/GradleDependenciesImportingTest.java b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/importing/GradleDependenciesImportingTest.java
index dd3b4d7363c9..0fc5daac4f7f 100644
--- a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/importing/GradleDependenciesImportingTest.java
+++ b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/importing/GradleDependenciesImportingTest.java
@@ -1118,11 +1118,14 @@ public class GradleDependenciesImportingTest extends GradleImportingTestCase {
"project.project1", "project.project1.main", "project.project1.test",
"project.project2", "project.project2.main", "project.project2.test");
- assertModuleOutput("project.project1.main", getProjectPath() + "/project1/buildIdea/main", "");
- assertModuleOutput("project.project1.test", "", getProjectPath() + "/project1/buildIdea/test");
+ String mainClassesOutputPath = isGradleNewerOrSameAs("4.0") ? "/build/classes/java/main" : "/build/classes/main";
+ String testClassesOutputPath = isGradleNewerOrSameAs("4.0") ? "/build/classes/java/test" : "/build/classes/test";
- assertModuleOutput("project.project2.main", getProjectPath() + "/project2/buildIdea/main", "");
- assertModuleOutput("project.project2.test", "", getProjectPath() + "/project2/buildIdea/test");
+ assertModuleOutput("project.project1.main", getProjectPath() + "/project1" + mainClassesOutputPath, "");
+ assertModuleOutput("project.project1.test", "", getProjectPath() + "/project1" + testClassesOutputPath);
+
+ assertModuleOutput("project.project2.main", getProjectPath() + "/project2" + mainClassesOutputPath, "");
+ assertModuleOutput("project.project2.test", "", getProjectPath() + "/project2" + testClassesOutputPath);
assertModuleModuleDeps("project.project2.main", ArrayUtilRt.EMPTY_STRING_ARRAY);
assertModuleModuleDeps("project.project2.test", "project.project2.main", "project.project1.test");
diff --git a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/importing/GradleFoldersImportingTest.java b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/importing/GradleFoldersImportingTest.java
index e920116bfcca..8701d1300db0 100644
--- a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/importing/GradleFoldersImportingTest.java
+++ b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/importing/GradleFoldersImportingTest.java
@@ -194,10 +194,18 @@ public class GradleFoldersImportingTest extends GradleImportingTestCase {
assertDefaultGradleJavaProjectFolders("project");
- assertModuleOutput("project.main", getProjectPath() + "/build", "");
+ String mainClassesOutputPath = isGradleNewerOrSameAs("4.0") ? "/build/classes/java/main" : "/build/classes/main";
+ assertModuleOutput("project.main", getProjectPath() + mainClassesOutputPath, "");
String testClassesOutputPath = isGradleNewerOrSameAs("4.0") ? "/build/classes/java/test" : "/build/classes/test";
assertModuleOutput("project.test", "", getProjectPath() + testClassesOutputPath);
+ getCurrentExternalProjectSettings().setDelegatedBuild(false);
+ GradleSettings.getInstance(myProject).getPublisher().onBuildDelegationChange(false, getProjectPath());
+ assertModuleOutput("project.main", getProjectPath() + "/build", "");
+ assertModuleOutput("project.test", "", getProjectPath() + "/out/test/classes");
+
+ getCurrentExternalProjectSettings().setDelegatedBuild(true);
+
importProjectUsingSingeModulePerGradleProject();
assertModules("project");
assertContentRoots("project", getProjectPath());
diff --git a/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/builder/ExternalProjectBuilderImpl.groovy b/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/builder/ExternalProjectBuilderImpl.groovy
index 72b2bca5d1a7..8d50211efe27 100644
--- a/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/builder/ExternalProjectBuilderImpl.groovy
+++ b/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/builder/ExternalProjectBuilderImpl.groovy
@@ -298,12 +298,6 @@ class ExternalProjectBuilderImpl extends AbstractModelBuilderService {
ExternalSourceDirectorySet resourcesDirectorySet = new DefaultExternalSourceDirectorySet()
resourcesDirectorySet.name = sourceSet.resources.name
resourcesDirectorySet.srcDirs = sourceSet.resources.srcDirs
- if (ideaPluginOutDir && SourceSet.MAIN_SOURCE_SET_NAME == sourceSet.name) {
- resourcesDirectorySet.addGradleOutputDir(ideaPluginOutDir)
- }
- if (ideaPluginTestOutDir && SourceSet.TEST_SOURCE_SET_NAME == sourceSet.name) {
- resourcesDirectorySet.addGradleOutputDir(ideaPluginTestOutDir)
- }
if (is4OrBetter) {
if (sourceSet.output.resourcesDir) {
resourcesDirectorySet.addGradleOutputDir(sourceSet.output.resourcesDir)
@@ -331,12 +325,6 @@ class ExternalProjectBuilderImpl extends AbstractModelBuilderService {
ExternalSourceDirectorySet javaDirectorySet = new DefaultExternalSourceDirectorySet()
javaDirectorySet.name = sourceSet.allJava.name
javaDirectorySet.srcDirs = sourceSet.allJava.srcDirs
- if (ideaPluginOutDir && SourceSet.MAIN_SOURCE_SET_NAME == sourceSet.name) {
- javaDirectorySet.addGradleOutputDir(ideaPluginOutDir)
- }
- if (ideaPluginTestOutDir && SourceSet.TEST_SOURCE_SET_NAME == sourceSet.name) {
- javaDirectorySet.addGradleOutputDir(ideaPluginTestOutDir)
- }
if (is4OrBetter) {
for (File outDir : sourceSet.output.classesDirs.files) {
javaDirectorySet.addGradleOutputDir(outDir)
diff --git a/plugins/grazie/src/test/kotlin/com/intellij/grazie/text/TextExtractionTest.java b/plugins/grazie/src/test/kotlin/com/intellij/grazie/text/TextExtractionTest.java
index 242e48583228..f0facee7550b 100644
--- a/plugins/grazie/src/test/kotlin/com/intellij/grazie/text/TextExtractionTest.java
+++ b/plugins/grazie/src/test/kotlin/com/intellij/grazie/text/TextExtractionTest.java
@@ -213,7 +213,25 @@ public class TextExtractionTest extends BasePlatformTestCase {
myFixture.type(' ');
PsiDocumentManager.getInstance(getProject()).commitAllDocuments(); // drop file caches
})
- .usesAllCPUCores()
+ .assertTiming();
+ }
+
+ public void testLargeXmlWithUnclosedDoctypePerformance() {
+ String text = "<!DOCTYPE rules [\n<!ENTITY some \"x\">\n<rules> " +
+ IntStreamEx.range(0, 10_000).mapToObj(i -> "<tag> content" + i + "</tag>\n").joining() +
+ " </rules>";
+ PsiFile file = myFixture.configureByText("a.xml", text);
+
+ PlatformTestUtil
+ .startPerformanceTest("text extraction", 1_500, () -> {
+ for (PsiElement element : SyntaxTraverser.psiTraverser(file)) {
+ TextExtractor.findTextsAt(element, TextContent.TextDomain.ALL);
+ }
+ })
+ .setup(() -> {
+ myFixture.type(' ');
+ PsiDocumentManager.getInstance(getProject()).commitAllDocuments(); // drop file caches
+ })
.assertTiming();
}
diff --git a/plugins/grazie/src/test/testData/ide/language/properties/Example.properties b/plugins/grazie/src/test/testData/ide/language/properties/Example.properties
index b0b1151f01c7..18204c77a6ce 100644
--- a/plugins/grazie/src/test/testData/ide/language/properties/Example.properties
+++ b/plugins/grazie/src/test/testData/ide/language/properties/Example.properties
@@ -12,6 +12,7 @@ ru.text.err3=Это случилось <warning descr="INVALID_DATE">31 нояб
ru.text.err4=За весь вечер она <warning descr="ne_proronila_ni">не проронила и слово</warning>.
ru.text.err5=Собрание состоится в <warning descr="RU_COMPOUNDS">конференц зале</warning>.
ru.text.err6=<warning descr="WORD_REPEAT_RULE">Он он</warning> здесь ошибка в тексте.
+ru.with.newline=Не удалось авторизоваться.\nПопробуйте ещё раз.
de.text.err1=Er überprüfte die Rechnungen noch <TYPO descr="Typo: In word 'einal'">einal</TYPO>, um ganz <warning descr="COMPOUND_INFINITIV_RULE">sicher zu gehen</warning>.
de.text.err2=das ist <warning descr="FUEHR_FUER">führ</warning> Dich!
diff --git a/plugins/grazie/src/test/testData/ide/language/xml/Example.xml b/plugins/grazie/src/test/testData/ide/language/xml/Example.xml
index 7b490a394c16..080f030fc091 100644
--- a/plugins/grazie/src/test/testData/ide/language/xml/Example.xml
+++ b/plugins/grazie/src/test/testData/ide/language/xml/Example.xml
@@ -6,4 +6,5 @@
<name>First sentence. <warning descr="PRP_THE">it</warning> <warning descr="EN_A_VS_AN">an</warning> friend. Last sentence.</name>
<address>Some street 23</address>
</shipto>
+ <russian_with_newline>Не удалось авторизоваться.\nПопробуйте ещё раз. И <warning descr="Sklonenije_NUM_NN">пять карандаша</warning>.</russian_with_newline>
</shiporder>
diff --git a/plugins/grazie/xml/main/kotlin/com/intellij/grazie/ide/language/xml/XmlProblemFilter.java b/plugins/grazie/xml/main/kotlin/com/intellij/grazie/ide/language/xml/XmlProblemFilter.java
index e3ca374cf784..a9eb8ebbc734 100644
--- a/plugins/grazie/xml/main/kotlin/com/intellij/grazie/ide/language/xml/XmlProblemFilter.java
+++ b/plugins/grazie/xml/main/kotlin/com/intellij/grazie/ide/language/xml/XmlProblemFilter.java
@@ -1,15 +1,25 @@
package com.intellij.grazie.ide.language.xml;
import com.intellij.grazie.text.ProblemFilter;
+import com.intellij.grazie.text.TextContent;
import com.intellij.grazie.text.TextProblem;
+import com.intellij.openapi.util.text.Strings;
import org.jetbrains.annotations.NotNull;
class XmlProblemFilter extends ProblemFilter {
@Override
public boolean shouldIgnore(@NotNull TextProblem problem) {
+ if (isAfterPossibleEscape(problem)) return true;
+
// This HTML (<b>text</b>) is currently split into 3 parts, and the bracket-pairing rule produces false positives.
// This can be removed when we implement smarter tag content merging.
String id = problem.getRule().getGlobalId();
return id.startsWith("LanguageTool.") && id.endsWith("UNPAIRED_BRACKETS");
}
+
+ private static boolean isAfterPossibleEscape(@NotNull TextProblem problem) {
+ TextContent text = problem.getText();
+ return problem.getHighlightRanges().stream()
+ .anyMatch(r -> Strings.contains(text, Math.max(0, r.getStartOffset() - 1), r.getEndOffset(), '\\'));
+ }
}
diff --git a/plugins/grazie/xml/main/kotlin/com/intellij/grazie/ide/language/xml/XmlTextExtractor.java b/plugins/grazie/xml/main/kotlin/com/intellij/grazie/ide/language/xml/XmlTextExtractor.java
index 20312118d8d0..78e3552fc3de 100644
--- a/plugins/grazie/xml/main/kotlin/com/intellij/grazie/ide/language/xml/XmlTextExtractor.java
+++ b/plugins/grazie/xml/main/kotlin/com/intellij/grazie/ide/language/xml/XmlTextExtractor.java
@@ -24,9 +24,7 @@ import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.CachedValueProvider;
import com.intellij.psi.util.CachedValuesManager;
import com.intellij.psi.util.PsiUtilCore;
-import com.intellij.psi.xml.XmlDocument;
-import com.intellij.psi.xml.XmlTag;
-import com.intellij.psi.xml.XmlTokenType;
+import com.intellij.psi.xml.*;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -51,8 +49,7 @@ public class XmlTextExtractor extends TextExtractor {
@Override
protected @Nullable TextContent buildTextContent(@NotNull PsiElement element,
@NotNull Set<TextContent.TextDomain> allowedDomains) {
- IElementType type = PsiUtilCore.getElementType(element);
- if (isText(type) && hasSuitableDialect(element)) {
+ if (isText(element) && hasSuitableDialect(element)) {
var classifier = tagClassifier(element);
PsiElement container = SyntaxTraverser.psiApi().parents(element)
.find(e -> e instanceof XmlDocument || e instanceof XmlTag && classifier.apply((XmlTag)e) != TagKind.Inline);
@@ -63,6 +60,7 @@ public class XmlTextExtractor extends TextExtractor {
}
}
+ IElementType type = PsiUtilCore.getElementType(element);
if (type == XmlTokenType.XML_COMMENT_CHARACTERS && allowedDomains.contains(COMMENTS) && hasSuitableDialect(element)) {
return builder.build(element, COMMENTS);
}
@@ -105,7 +103,7 @@ public class XmlTextExtractor extends TextExtractor {
unknownBefore = true;
}
- if (isText(PsiUtilCore.getElementType(each))) {
+ if (isText(each)) {
group.add(each);
}
super.visitElement(each);
@@ -138,7 +136,15 @@ public class XmlTextExtractor extends TextExtractor {
return full.excludeRange(new TextRange(range.getEndOffset(), full.length())).excludeRange(new TextRange(0, range.getStartOffset()));
}
- private static boolean isText(IElementType type) {
+ private static boolean isText(PsiElement leaf) {
+ PsiElement parent = leaf.getParent();
+ if (!(parent instanceof XmlText) &&
+ !(PsiUtilCore.getElementType(parent) == XmlElementType.XML_CDATA && parent.getParent() instanceof XmlText) &&
+ !(parent instanceof XmlDocument)) {
+ return false;
+ }
+
+ IElementType type = PsiUtilCore.getElementType(leaf);
return type == XmlTokenType.XML_WHITE_SPACE || type == TokenType.WHITE_SPACE ||
type == XmlTokenType.XML_CHAR_ENTITY_REF || type == XmlTokenType.XML_DATA_CHARACTERS;
}
diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/codeInspection/confusing/GroovyPointlessBooleanInspection.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/codeInspection/confusing/GroovyPointlessBooleanInspection.java
index 040426940cb6..8dbd95f1311b 100644
--- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/codeInspection/confusing/GroovyPointlessBooleanInspection.java
+++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/codeInspection/confusing/GroovyPointlessBooleanInspection.java
@@ -33,7 +33,6 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrBinary
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrUnaryExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.literals.GrLiteral;
-import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil;
import org.jetbrains.plugins.groovy.lang.psi.impl.utils.ComparisonUtils;
import org.jetbrains.plugins.groovy.lang.psi.impl.utils.ParenthesesUtils;
@@ -269,14 +268,13 @@ public class GroovyPointlessBooleanInspection extends BaseInspection {
private static boolean equalityExpressionIsPointless(GrExpression lhs,
GrExpression rhs) {
- return (isTrue(lhs) || isFalse(lhs)) && isBoolean(rhs)
- || (isTrue(rhs) || isFalse(rhs)) && isBoolean(lhs);
+ return ((isTrue(lhs) || isFalse(lhs)) && isBoolean(rhs)) ||
+ ((isTrue(rhs) || isFalse(rhs)) && isBoolean(lhs));
}
private static boolean isBoolean(GrExpression expression) {
final PsiType type = expression.getType();
- final PsiType unboxed = TypesUtil.unboxPrimitiveTypeWrapper(type);
- return unboxed != null && PsiType.BOOLEAN.equals(unboxed);
+ return PsiType.BOOLEAN.equals(type);
}
private static boolean andExpressionIsPointless(GrExpression lhs,
diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/typing/DefaultMethodCallTypeCalculator.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/typing/DefaultMethodCallTypeCalculator.kt
index 97a79993b5da..d0a4ae5cb1ee 100644
--- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/typing/DefaultMethodCallTypeCalculator.kt
+++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/typing/DefaultMethodCallTypeCalculator.kt
@@ -1,14 +1,17 @@
-// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
+// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.plugins.groovy.lang.typing
import com.intellij.openapi.extensions.ExtensionPointName
import com.intellij.openapi.util.registry.Registry
import com.intellij.psi.*
+import com.intellij.util.castSafelyTo
+import org.jetbrains.plugins.groovy.lang.psi.GroovyElementTypes
import org.jetbrains.plugins.groovy.lang.psi.api.GroovyMethodResult
import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrField
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrMethodCall
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrAccessorMethod
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod
import org.jetbrains.plugins.groovy.lang.psi.impl.GrLiteralClassType
@@ -30,7 +33,7 @@ class DefaultMethodCallTypeCalculator : GrTypeCalculator<GrMethodCall> {
for (result in results) {
type = TypesUtil.getLeastUpperBoundNullable(type, getTypeFromResult(result, arguments, expression), expression.manager)
}
- return type
+ return type?.boxIfNecessary(expression)
}
}
@@ -80,6 +83,17 @@ fun PsiType?.devoid(context: PsiElement): PsiType? {
return if (this == PsiType.VOID && !isCompileStatic(context)) PsiType.NULL else this
}
+private fun PsiType.boxIfNecessary(call: GrMethodCall) : PsiType {
+ if (this !is PsiPrimitiveType) {
+ return this
+ }
+ return if (call.invokedExpression.castSafelyTo<GrReferenceExpression>()?.dotTokenType == GroovyElementTypes.T_SAFE_DOT) {
+ this.box(call)
+ } else {
+ this
+ }
+}
+
private fun hasGenerics(type: PsiType): Boolean {
return !Registry.`is`("groovy.return.type.optimization") || type.accept(GenericsSearcher) == true
}
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/debugger/GroovyPositionManager.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/debugger/GroovyPositionManager.java
index a472d02c717b..4544cf9ccb02 100644
--- a/plugins/groovy/src/org/jetbrains/plugins/groovy/debugger/GroovyPositionManager.java
+++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/debugger/GroovyPositionManager.java
@@ -16,6 +16,8 @@ import com.intellij.openapi.application.ReadAction;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.fileTypes.FileTypeRegistry;
+import com.intellij.openapi.fileTypes.LanguageFileType;
+import com.intellij.openapi.fileTypes.UnknownFileType;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.impl.scopes.ModuleWithDependenciesScope;
import com.intellij.openapi.progress.ProcessCanceledException;
@@ -38,6 +40,7 @@ import com.sun.jdi.request.ClassPrepareRequest;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.GroovyFileType;
+import org.jetbrains.plugins.groovy.GroovyLanguage;
import org.jetbrains.plugins.groovy.extensions.debugger.ScriptPositionManagerHelper;
import org.jetbrains.plugins.groovy.lang.psi.GroovyFile;
import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase;
@@ -49,10 +52,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefini
import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
import org.jetbrains.plugins.groovy.lang.stubs.GroovyShortNamesCache;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Set;
+import java.util.*;
public class GroovyPositionManager extends PositionManagerEx {
private static final Logger LOG = Logger.getInstance(PositionManagerImpl.class);
@@ -98,27 +98,31 @@ public class GroovyPositionManager extends PositionManagerEx {
@Override
public @Nullable XStackFrame createStackFrame(@NotNull StackFrameDescriptorImpl descriptor) {
- if (!isInGroovyFile(descriptor)) {
+ if (isInGroovyFile(descriptor.getLocation()) != ThreeState.YES) {
return null;
}
return new GroovyStackFrame(descriptor, true);
}
- private static boolean isInGroovyFile(StackFrameDescriptorImpl descriptor) {
- Location location = descriptor.getLocation();
+ private static ThreeState isInGroovyFile(@Nullable Location location) {
if (location != null) {
var refType = location.declaringType();
try {
String safeName = refType.sourceName();
FileType fileType = FileTypeRegistry.getInstance().getFileTypeByFileName(safeName);
- if (fileType != GroovyFileType.GROOVY_FILE_TYPE) {
- return false;
+ if (fileType == UnknownFileType.INSTANCE) {
+ return ThreeState.UNSURE;
}
- } catch (AbsentInformationException e) {
- return false;
+ if (fileType instanceof LanguageFileType) {
+ LanguageFileType languageFileType = (LanguageFileType)fileType;
+ if (languageFileType.getLanguage() == GroovyLanguage.INSTANCE) {
+ return ThreeState.YES;
+ }
+ }
+ } catch (AbsentInformationException ignore) {
}
}
- return true;
+ return ThreeState.NO;
}
@Nullable
@@ -285,6 +289,10 @@ public class GroovyPositionManager extends PositionManagerEx {
@Override
public SourcePosition getSourcePosition(@Nullable final Location location) throws NoDataException {
if (location == null) throw NoDataException.INSTANCE;
+ if (isInGroovyFile(location) == ThreeState.NO) throw NoDataException.INSTANCE;
+
+ int lineNumber = calcLineIndex(location);
+ if (lineNumber < 0) throw NoDataException.INSTANCE;
if (LOG.isDebugEnabled()) {
LOG.debug("getSourcePosition: " + location);
@@ -292,8 +300,6 @@ public class GroovyPositionManager extends PositionManagerEx {
PsiFile psiFile = getPsiFileByLocation(getDebugProcess().getProject(), location);
if (psiFile == null) throw NoDataException.INSTANCE;
- int lineNumber = calcLineIndex(location);
- if (lineNumber < 0) throw NoDataException.INSTANCE;
return SourcePosition.createFromLine(psiFile, lineNumber);
}
@@ -479,6 +485,9 @@ public class GroovyPositionManager extends PositionManagerEx {
@NotNull
@Override
public Set<? extends FileType> getAcceptedFileTypes() {
- return ourFileTypes;
+ var result = new HashSet<FileType>();
+ ScriptPositionManagerHelper.EP_NAME.forEachExtensionSafe(ext -> result.addAll(ext.getAcceptedFileTypes()));
+ result.addAll(ourFileTypes);
+ return result;
}
} \ No newline at end of file
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/extensions/debugger/ScriptPositionManagerHelper.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/extensions/debugger/ScriptPositionManagerHelper.java
index ea5d224a7191..ff5a46a40c39 100644
--- a/plugins/groovy/src/org/jetbrains/plugins/groovy/extensions/debugger/ScriptPositionManagerHelper.java
+++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/extensions/debugger/ScriptPositionManagerHelper.java
@@ -16,6 +16,7 @@
package org.jetbrains.plugins.groovy.extensions.debugger;
import com.intellij.openapi.extensions.ExtensionPointName;
+import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiFile;
@@ -25,6 +26,9 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.lang.psi.GroovyFile;
+import java.util.Collection;
+import java.util.Collections;
+
/**
* Class to extend debugger functionality to handle various Groovy scripts
*
@@ -83,4 +87,13 @@ public abstract class ScriptPositionManagerHelper {
public String customizeClassName(@NotNull PsiClass psiClass) {
return null;
}
+
+ /**
+ * If a position manager works with scripts of FileType other,
+ * then {@link org.jetbrains.plugins.groovy.GroovyFileType#GROOVY_FILE_TYPE}, it should report them here.
+ * @return file types supported by this position manager helper
+ */
+ public Collection<? extends FileType> getAcceptedFileTypes() {
+ return Collections.emptySet();
+ }
}
diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/codeInspection/confusing/GroovyPointlessBooleanInspectionTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/codeInspection/confusing/GroovyPointlessBooleanInspectionTest.groovy
index 331a8483dfb2..e1f137646974 100644
--- a/plugins/groovy/test/org/jetbrains/plugins/groovy/codeInspection/confusing/GroovyPointlessBooleanInspectionTest.groovy
+++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/codeInspection/confusing/GroovyPointlessBooleanInspectionTest.groovy
@@ -1,4 +1,4 @@
-// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
+// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.plugins.groovy.codeInspection.confusing
import com.intellij.codeInspection.LocalInspectionTool
@@ -34,6 +34,11 @@ class GroovyPointlessBooleanInspectionTest extends GroovyLatestTest implements H
doTest($/!<caret><warning descr="Redundant boolean operations">!!true</warning>/$, '!true')
}
+ @Test
+ void 'non-primitive type'() {
+ highlightingTest('Boolean x = null; x == true')
+ }
+
private void doTest(String before, String after) {
highlightingTest before
doActionTest('Simplify', after)
diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/TypeInferenceTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/TypeInferenceTest.groovy
index 1faa3505aa76..0c779c1e4839 100644
--- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/TypeInferenceTest.groovy
+++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/TypeInferenceTest.groovy
@@ -2003,4 +2003,11 @@ def foo() {
}
""", "java.util.Collection<java.lang.Integer>"
}
+
+ void 'test boxing on nullable receiver'() {
+ doTest """
+def xx = ""?.length()
+x<caret>x
+""", "java.lang.Integer"
+ }
}
diff --git a/plugins/ide-features-trainer/src/training/util/Utils.kt b/plugins/ide-features-trainer/src/training/util/Utils.kt
index 085bbb866bfd..98b45c3e9ba0 100644
--- a/plugins/ide-features-trainer/src/training/util/Utils.kt
+++ b/plugins/ide-features-trainer/src/training/util/Utils.kt
@@ -175,7 +175,7 @@ fun scaledRigid(width: Int, height: Int): Component {
internal fun getLearnToolWindowForProject(project: Project): LearnToolWindow? {
val toolWindow = ToolWindowManager.getInstance(project).getToolWindow(LearnToolWindowFactory.LEARN_TOOL_WINDOW) ?: return null
- val jComponent = toolWindow.contentManager.contents.singleOrNull()?.component
+ val jComponent = toolWindow.contentManagerIfCreated?.contents?.singleOrNull()?.component
return jComponent as? LearnToolWindow
}
diff --git a/python/helpers/pydev/_pydevd_bundle/pydevd_console_output.py b/python/helpers/pydev/_pydevd_bundle/pydevd_console_output.py
index f26f1175ade4..3503e8ca2dad 100644
--- a/python/helpers/pydev/_pydevd_bundle/pydevd_console_output.py
+++ b/python/helpers/pydev/_pydevd_bundle/pydevd_console_output.py
@@ -1,5 +1,6 @@
WRITE_OUT = 1
WRITE_ERR = 2
+MAX_STRING_LENGTH = 1000
class ConsoleOutputHook:
@@ -9,12 +10,10 @@ class ConsoleOutputHook:
self.is_error = is_stderr
def write(self, str):
- if self.is_error:
- cmd = self.dbg.cmd_factory.make_io_message(str, WRITE_ERR)
+ if len(str) > MAX_STRING_LENGTH:
+ self._write_long_string(str)
else:
- cmd = self.dbg.cmd_factory.make_io_message(str, WRITE_OUT)
-
- self.dbg.writer.add_command(cmd)
+ self._write_short_string(str)
def flush(self):
pass
@@ -24,3 +23,16 @@ class ConsoleOutputHook:
if hasattr(self.original_out, item):
return getattr(self.original_out, item)
raise AttributeError("%s has no attribute %s" % (self.original_out, item))
+
+ def _write_long_string(self, str):
+ str_len, chunk_size = len(str), len(str) // MAX_STRING_LENGTH
+ for i in range(0, str_len, chunk_size):
+ self._write_short_string(str[i:i + chunk_size])
+
+ def _write_short_string(self, str):
+ if self.is_error:
+ cmd = self.dbg.cmd_factory.make_io_message(str, WRITE_ERR)
+ else:
+ cmd = self.dbg.cmd_factory.make_io_message(str, WRITE_OUT)
+
+ self.dbg.writer.add_command(cmd)
diff --git a/python/ideCoreSrc/idea/PyCharmCoreApplicationInfo.xml b/python/ideCoreSrc/idea/PyCharmCoreApplicationInfo.xml
index d268cd2f56ff..404b5c2b7cb7 100644
--- a/python/ideCoreSrc/idea/PyCharmCoreApplicationInfo.xml
+++ b/python/ideCoreSrc/idea/PyCharmCoreApplicationInfo.xml
@@ -2,7 +2,7 @@
<component xmlns="http://jetbrains.org/intellij/schema/application-info"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://jetbrains.org/intellij/schema/application-info http://jetbrains.org/intellij/schema/ApplicationInfo.xsd">
- <version major="2022" minor="1.2" eap="false"/>
+ <version major="2022" minor="1.3" suffix="RC" eap="false"/>
<company name="JetBrains s.r.o." url="https://www.jetbrains.com" copyrightStart="2010"/>
<build number="PC-__BUILD__" date="__BUILD_DATE__" majorReleaseDate="20220413"/>
<logo url="/pycharm_core_logo.png" textcolor="ffffff" progressColor="ffffff" progressY="396" progressHeight="4"/>
diff --git a/python/src/com/jetbrains/python/sdk/PythonSdkUpdater.java b/python/src/com/jetbrains/python/sdk/PythonSdkUpdater.java
index d80d7e4c1cef..1bfc5a629864 100644
--- a/python/src/com/jetbrains/python/sdk/PythonSdkUpdater.java
+++ b/python/src/com/jetbrains/python/sdk/PythonSdkUpdater.java
@@ -447,7 +447,10 @@ public class PythonSdkUpdater implements StartupActivity.Background {
final var pathsToTransfer = new HashSet<VirtualFile>();
pathsToTransfer.addAll(sdkRoots.second);
pathsToTransfer.addAll(userAddedRoots.second);
- pathsToTransfer.removeAll(moduleRoots);
+ // Presumably source and content roots that were configured manually by user, not set up automatically as "transferred"
+ HashSet<VirtualFile> nonTransferredModuleRoots = new HashSet<>(moduleRoots);
+ nonTransferredModuleRoots.removeAll(PyTransferredSdkRootsKt.getPathsToTransfer(sdk));
+ pathsToTransfer.removeAll(nonTransferredModuleRoots);
/*
Don't run actions related to transferred roots on editable sdks since they can share data with original ones.
diff --git a/python/testSrc/com/jetbrains/python/sdk/PySdkPathsTest.kt b/python/testSrc/com/jetbrains/python/sdk/PySdkPathsTest.kt
index d1c808cf4173..6ba5053bea30 100644
--- a/python/testSrc/com/jetbrains/python/sdk/PySdkPathsTest.kt
+++ b/python/testSrc/com/jetbrains/python/sdk/PySdkPathsTest.kt
@@ -239,7 +239,10 @@ class PySdkPathsTest {
mockPythonPluginDisposable()
updateSdkPaths(sdk)
+ checkRoots(sdk, module, listOf(moduleRoot, entryPath), emptyList())
+ // Subsequent updates should keep already set up source roots
+ updateSdkPaths(sdk)
checkRoots(sdk, module, listOf(moduleRoot, entryPath), emptyList())
val simpleSdk = PythonMockSdk.create().also {
diff --git a/spellchecker/src/com/intellij/spellchecker/inspections/IdentifierSplitter.java b/spellchecker/src/com/intellij/spellchecker/inspections/IdentifierSplitter.java
index 9a393f0a1c44..90a855240496 100644
--- a/spellchecker/src/com/intellij/spellchecker/inspections/IdentifierSplitter.java
+++ b/spellchecker/src/com/intellij/spellchecker/inspections/IdentifierSplitter.java
@@ -118,6 +118,7 @@ public class IdentifierSplitter extends BaseSplitter {
type == Character.TITLECASE_LETTER ||
type == Character.OTHER_LETTER ||
type == Character.MODIFIER_LETTER ||
+ type == Character.NON_SPACING_MARK ||
type == Character.OTHER_PUNCTUATION
) {
//letter
diff --git a/spellchecker/src/com/intellij/spellchecker/inspections/TextSplitter.java b/spellchecker/src/com/intellij/spellchecker/inspections/TextSplitter.java
index 092fc790e2f6..5c0554566931 100644
--- a/spellchecker/src/com/intellij/spellchecker/inspections/TextSplitter.java
+++ b/spellchecker/src/com/intellij/spellchecker/inspections/TextSplitter.java
@@ -33,8 +33,17 @@ public class TextSplitter extends BaseSplitter {
return INSTANCE;
}
- private static final Pattern EXTENDED_WORD_AND_SPECIAL = Pattern.compile("(&[^;]+;)|(([#]|0x[0-9]*)?\\p{L}+'?\\p{L}[_\\p{L}]*)");
-
+ private static final String letter = "(\\p{L}\\p{Mn}*)";
+ private static final String xmlEntity = "(&.+?;)";
+ // using possessive quantifiers ++ and *+ to avoid SOE on large inputs
+ // see https://blog.sonarsource.com/crafting-regexes-to-avoid-stack-overflows/
+ private static final Pattern EXTENDED_WORD_AND_SPECIAL = Pattern.compile(
+ xmlEntity + "|" +
+ "(#|0x\\d*)?" + // an optional prefix
+ letter + "++" + // some letters
+ "('" + letter + ")?" + // if there's an apostrophe, it should be followed by a letter
+ "(_|" + letter + ")*+" // more letters and underscores
+ );
@Override
public void split(@Nullable String text, @NotNull TextRange range, Consumer<TextRange> consumer) {
if (text == null || StringUtil.isEmpty(text)) {
diff --git a/spellchecker/testData/inspection/commentsWithMistakes/test.txt b/spellchecker/testData/inspection/commentsWithMistakes/test.txt
index 55589a76654d..ddec30627e4a 100644
--- a/spellchecker/testData/inspection/commentsWithMistakes/test.txt
+++ b/spellchecker/testData/inspection/commentsWithMistakes/test.txt
@@ -2,3 +2,4 @@ simple <TYPO descr="Typo: In word 'ttest'">ttest</TYPO> file (just plain text)
русский (например) без словаря не проверять!!!
data && !changed; else
data && !<TYPO descr="Typo: In word 'changsed'">changsed</TYPO>; else
+YWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFh<TYPO descr="Typo: In word 'YWEK'">YWEK</TYPO> \ No newline at end of file
diff --git a/spellchecker/testSrc/com/intellij/spellchecker/inspector/SplitterTest.java b/spellchecker/testSrc/com/intellij/spellchecker/inspector/SplitterTest.java
index 62fb0fb82d38..30a6b97793d9 100644
--- a/spellchecker/testSrc/com/intellij/spellchecker/inspector/SplitterTest.java
+++ b/spellchecker/testSrc/com/intellij/spellchecker/inspector/SplitterTest.java
@@ -139,6 +139,12 @@ public class SplitterTest {
}
@Test
+ public void testUnicodeCombiningChars() {
+ correctListToCheck(PlainTextSplitter.getInstance(), "бо́льшую", "бо́льшую");
+ correctListToCheck(PlainTextSplitter.getInstance(), "dafür", "dafür");
+ }
+
+ @Test
public void testConstantName() {
String text = "TEST_CONSTANT";
correctListToCheck(IdentifierSplitter.getInstance(), text, "TEST", "CONSTANT");
diff --git a/xml/dom-openapi/src/com/intellij/util/xml/ui/UndoHelper.java b/xml/dom-openapi/src/com/intellij/util/xml/ui/UndoHelper.java
index ed10f84682fe..dda6b55894ae 100644
--- a/xml/dom-openapi/src/com/intellij/util/xml/ui/UndoHelper.java
+++ b/xml/dom-openapi/src/com/intellij/util/xml/ui/UndoHelper.java
@@ -61,13 +61,13 @@ public class UndoHelper {
});
}
- final void startListeningDocuments() {
+ public final void startListeningDocuments() {
for (final Document document : myCurrentDocuments) {
document.addDocumentListener(myDocumentAdapter);
}
}
- final void stopListeningDocuments() {
+ public final void stopListeningDocuments() {
for (final Document document : myCurrentDocuments) {
document.removeDocumentListener(myDocumentAdapter);
}
@@ -87,7 +87,7 @@ public class UndoHelper {
startListeningDocuments();
}
- final void removeWatchedDocument(@NotNull Document document) {
+ public final void removeWatchedDocument(@NotNull Document document) {
stopListeningDocuments();
myCurrentDocuments.remove(document);
startListeningDocuments();